Options Payoff logo

Options Payoff

OrganizationPopular
HKUDS
options-payoff

Option P&L analysis methodology: payoff diagrams, breakeven calculation, multi-leg strategy visualization, and Greeks-based scenario analysis.

Overview

PublisherHKUDS
RepositoryVibe-Trading
Skill nameoptions-payoff
Stars
33.6K
Forks
5.5K
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by HKUDS on GitHub. Read the source before you install it.

Installation

Install the Options Payoff AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/HKUDS/Vibe-Trading.git /tmp/Vibe-Trading
mkdir -p .claude/skills
cp -r /tmp/Vibe-Trading/agent/src/skills/options-payoff .claude/skills/options-payoff
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Options Payoff in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Options Payoff on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Options Payoff is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Options Payoff — Option P&L Analysis Methodology

Overview

This skill is designed for option strategy analysis scenarios within the Vibe-Trading quantitative framework, covering:

  • P&L curve generation for single-leg and multi-leg option portfolios
  • Black-Scholes pricing and Greeks calculation
  • Implied volatility inversion
  • Strategy selection decision support

Constraint: For research and backtesting only. Do not output live trading instructions, in line with the project's guardrails.

Built-in execution tool

Load this skill for methodology, then call options_payoff for production calculations. Pass signed legs (qty > 0 long, qty < 0 short), entry_spot, and expiry_days; optionally pass actual per-share premiums, multiplier, commission, chart bounds, and IV scenarios. The tool returns an expiry curve, a spot × IV scenario matrix, and analytic breakeven/max-risk results that do not depend on the display grid containing every strike.


1. Supported Strategy Types

1.1 Single-Leg Strategies

StrategyBiasPremiumMax ProfitMax Loss
Long CallBullishPaidUnlimitedPremium
Long PutBearishPaidStrike - premiumPremium
Short CallNeutral / mildly bearishReceivedPremiumUnlimited
Short PutNeutral / mildly bullishReceivedPremiumStrike - premium

1.2 Vertical Spreads

StrategyStructureMarket ViewNet Premium
Bull Call SpreadLong Call (lower K) + Short Call (higher K)Moderately bullishNet debit
Bear Put SpreadLong Put (higher K) + Short Put (lower K)Moderately bearishNet debit
Bull Put SpreadShort Put (higher K) + Long Put (lower K)Moderately bullishNet credit
Bear Call SpreadShort Call (lower K) + Long Call (higher K)Moderately bearishNet credit

1.3 Straddles / Strangles (Volatility Strategies)

StrategyStructureMarket View
Long StraddleLong Call (ATM) + Long Put (ATM)Large move up or down, low volatility
Short StraddleShort Call (ATM) + Short Put (ATM)Range-bound market, high volatility
Long StrangleLong Call (OTM) + Long Put (OTM)Large move, lower cost than a straddle
Short StrangleShort Call (OTM) + Short Put (OTM)Tight range, collect two-sided premium

1.4 Butterflies / Iron Butterflies

StrategyStructureFeature
Long Butterfly (Call)Long Call (K1) + 2× Short Call (K2) + Long Call (K3)Low-cost bet that the underlying expires near K2
Long Butterfly (Put)Long Put (K3) + 2× Short Put (K2) + Long Put (K1)Same logic, built with puts
Iron ButterflyShort Call (K2) + Short Put (K2) + Long Call (K3) + Long Put (K1)Net credit, max profit at K2

1.5 Condors / Iron Condors

StrategyStructureFeature
Long Condor (Call)Long Call (K1) + Short Call (K2) + Short Call (K3) + Long Call (K4)Bet that the underlying stays between K2 and K3
Iron CondorShort Put (K2) + Long Put (K1) + Short Call (K3) + Long Call (K4)Most common neutral strategy with capped risk on both sides

Here K1 < K2 < K3 < K4, and K2 / K3 are usually OTM.

1.6 Calendar Spreads (Time Spreads)

StrategyStructureMarket View
Calendar SpreadShort near-month Call/Put (K) + Long far-month Call/Put (K)Short-term range-bound market + rising forward volatility
Diagonal SpreadShort near-month Call/Put (K1) + Long far-month Call/Put (K2)Calendar spread with mild directional bias

Calendar spreads profit because near-month Theta decay is faster than far-month Theta decay.

1.7 Ratio Spreads

StrategyStructureFeature
Ratio Call SpreadLong 1× Call (K1) + Short N× Call (K2), N>1Limited upside profit, losses if the upside move becomes extreme
Ratio Put SpreadLong 1× Put (K2) + Short N× Put (K1)Limited downside profit, losses if the downside move becomes extreme
Call Back SpreadShort 1× Call (K1) + Long N× Call (K2), N>1Profits from extreme upside, loses on a modest rally
Put Back SpreadShort 1× Put (K2) + Long N× Put (K1), N>1Profits from extreme downside, loses on a mild decline

1.8 Protective / Hedging Strategies

StrategyStructureUse Case
Covered CallLong underlying + Short Call (K)Generate income on an existing position, give up gains above K
Protective PutLong underlying + Long Put (K)Downside protection on an existing position, pay an insurance premium
CollarLong underlying + Long Put (K1) + Short Call (K2)Lock the position into a zero-cost / low-cost range

2. Black-Scholes Pricing Model

2.1 Core Assumptions

  • The underlying price follows geometric Brownian motion (lognormal distribution)
  • Risk-free rate r is constant
  • Volatility σ is constant (historical or implied)
  • No dividends, or adjust with a continuous dividend yield q
  • European options only (exercise at expiration)

2.2 Full Formula

S  = current underlying price
K  = strike price
T  = time to expiration (years)
r  = risk-free rate (annualized continuous compounding)
q  = continuous dividend yield (commonly used for China A-share / index options)
σ  = annualized volatility
N  = standard normal CDF

d1 = [ln(S/K) + (r - q + σ²/2) × T] / (σ × √T)
d2 = d1 - σ × √T

Call = S × e^(-qT) × N(d1) - K × e^(-rT) × N(d2)
Put  = K × e^(-rT) × N(-d2) - S × e^(-qT) × N(-d1)

2.3 Put-Call Parity

Call - Put = S × e^(-qT) - K × e^(-rT)

Use this to verify pricing consistency and detect arbitrage. When dividends exist, replace S with S × e^(-qT).

2.4 Greeks Calculation

Delta (Price Sensitivity)
Delta(Call) = e^(-qT) × N(d1)
Delta(Put)  = e^(-qT) × (N(d1) - 1)
  • Range: Call [0, 1], Put [-1, 0]
  • ATM ≈ ±0.5, deep ITM → ±1, deep OTM → 0
Gamma (Rate of Change of Delta)
Gamma = e^(-qT) × N'(d1) / (S × σ × √T)

N'(x) = (1/√(2π)) × e^(-x²/2)  [standard normal PDF]
  • Calls and puts have the same Gamma
  • Gamma is highest near ATM and explodes as expiration approaches
Theta (Time Decay, per day)
Theta(Call) = [-S × e^(-qT) × N'(d1) × σ / (2√T)
               - r × K × e^(-rT) × N(d2)
               + q × S × e^(-qT) × N(d1)] / 365

Theta(Put)  = [-S × e^(-qT) × N'(d1) × σ / (2√T)
               + r × K × e^(-rT) × N(-d2)
               - q × S × e^(-qT) × N(-d1)] / 365
  • Usually negative for option holders
  • ATM options near expiration have the largest Theta magnitude, which benefits option sellers the most
Vega (Volatility Sensitivity, per 1% vol change)
Vega = S × e^(-qT) × N'(d1) × √T / 100
  • Calls and puts have the same Vega
  • ATM Vega is the largest, and Vega approaches 0 at expiration
Rho (Interest Rate Sensitivity, per 1% rate change)
Rho(Call) = K × T × e^(-rT) × N(d2) / 100
Rho(Put)  = -K × T × e^(-rT) × N(-d2) / 100
  • The rate effect is usually small and often negligible for short-dated options

2.5 Implied Volatility Inversion (Newton-Raphson)

Given a market price P_market, solve for σ such that BS(σ) = P_market:

Iteration:
σ_{n+1} = σ_n - [BS(σ_n) - P_market] / Vega(σ_n)

Stopping condition: |BS(σ_n) - P_market| < 1e-6

Initial guess:
σ_0 = √(2π/T) × P_market/S  (Brenner-Subrahmanyam approximation)

Notes:
- If Vega is close to 0 (deep OTM / ITM), switch to bisection
- If the iteration does not converge (>100 rounds), return NaN and raise a warning
- IV > 500% is usually an outlier and should be filtered

This is already implemented, guards included, as src.quantlib.options.implied_volatility — see section 4.1. The formulas above document what it computes; they are not an instruction to rewrite it.


3. Payoff Diagram Analysis

3.1 Expiry Payoff Curve

Calculation logic:

For each leg i (Call/Put, Long/Short, strike K_i, quantity n_i):
  Payoff_i(S_T) = n_i × direction_i × max(0, S_T - K_i)  # Call
  Payoff_i(S_T) = n_i × direction_i × max(0, K_i - S_T)  # Put

Where direction = +1 (Long) / -1 (Short)

Portfolio payoff = Σ Payoff_i - net premium cost
  (paid premium is positive, received premium is negative)

X-axis range: [min(K) × 0.7, max(K) × 1.3], step size 0.5 or 1

3.2 Theoretical Value Curve (Current Black-Scholes Pricing)

For each underlying price S, hold T, r, and σ constant and compute current theoretical PnL using the Black-Scholes formula:

TheoValue(S) = Σ n_i × direction_i × BS_price(S, K_i, T, r, σ, type_i) - net premium cost

The gap between the theoretical value curve and the expiry curve equals the remaining time value.

3.3 Break-Even Points

Expiry payoff is piecewise linear. Solve Payoff(S_T) = 0 on intervals formed by S=0, every unique strike, and the right tail. Do not search only the chart grid: a narrow grid can miss a valid root beyond its bounds.

  • Single-leg strategies:
    • Long Call BEP = K + premium
    • Long Put BEP = K - premium
    • Short Call BEP = K + premium received
    • Short Put BEP = K - premium received
  • Multi-leg strategies can have more than two breakevens; inspect every strike interval and the unbounded right interval.

3.4 Max Profit / Max Loss

Evaluate payoff at S=0 and every unique strike. Those are all finite points where slope can change, so finite extrema occur in that set. Then inspect the right-tail slope: positive means unlimited profit, negative means unlimited loss, and zero means the payoff remains flat. Never derive max profit/loss only from sampled chart points.

3.5 P&L Under Different Volatility Scenarios

Generate a σ scenario matrix using current IV × [0.5, 0.75, 1.0, 1.25, 1.5]. Plot one theoretical value curve for each σ and distinguish them by color to observe Vega sensitivity.


4. Python Code Templates

4.1 Black-Scholes Pricing Functions — Import, Do Not Retype

bs_price, bs_greeks and implied_volatility are implemented once in src/quantlib/options.py and pinned by tests/quantlib/test_options.py (published Hull reference values, put-call parity, Greeks against finite-difference bumps, implied-vol round-trips). Import them.

Do not retype the formulas from section 2 into your own helper. A retyped copy is a different, untested function on every run, and the copies that used to live here had two live defects: they crashed on a non-positive spot or strike, and they reported a zero Delta for an expiring in-the-money option.

python
from src.quantlib.options import bs_greeks, bs_price, implied_volatility

price = bs_price(S=100, K=100, T=0.25, r=0.03, sigma=0.20, option_type="call", q=0.0)
greeks = bs_greeks(100, 100, 0.25, 0.03, 0.20, "call")   # delta gamma theta vega rho
iv = implied_volatility(market_price=5.0, S=100, K=100, T=0.25, r=0.03, option_type="call")

Argument order is (S, K, T, r, sigma, option_type="call", q=0.0) for both pricing functions; implied_volatility takes market_price first, then (S, K, T, r, option_type="call", q=0.0, tol=1e-6, max_iter=200).

Contract worth knowing before you use the numbers:

PointBehaviour
UnitsTheta per calendar day; Vega and Rho per 1 percentage point; Delta and Gamma per 1.0 of spot. Nothing is rounded
option_typeCase-insensitive; anything other than call/put raises ValueError
Degenerate inputT <= 0, sigma <= 0, S <= 0 or K <= 0 returns intrinsic value, and Greeks with the correct ±1/0 point-mass Delta — it does not raise
IV lower guardRaises ValueError below the discounted forward intrinsic. Using undiscounted K - S instead would wrongly reject deep ITM European puts, which really do trade below it
IV upper guardRaises ValueError at or above the no-arbitrage ceiling (S·e^(-qT) for a call, K·e^(-rT) for a put) — no volatility reaches it
IV failureNewton seeded by Brenner-Subrahmanyam, falling back to bisection when Vega collapses; returns nan only if neither converges

4.2 Multi-Leg Portfolio Payoff Calculation

python
from dataclasses import dataclass
from typing import Literal

import numpy as np
from scipy.optimize import brentq

from src.quantlib.options import bs_price

@dataclass
class OptionLeg:
    """Single option leg definition.

    Attributes:
        option_type: "call" or "put"
        K: Strike price
        direction: +1 for Long / -1 for Short
        quantity: Number of contracts, defaults to 1
        premium: Actual traded premium, positive when paid and negative when received
        T: Time to expiration in years, used for theoretical Black-Scholes pricing
        sigma: Volatility used in pricing
    """
    option_type: Literal["call", "put"]
    K: float
    direction: int  # +1 or -1
    quantity: float = 1.0
    premium: float = 0.0
    T: float = 0.25
    sigma: float = 0.20


def compute_expiry_payoff(
    legs: list[OptionLeg],
    S_range: np.ndarray,
) -> np.ndarray:
    """Calculate the expiry payoff curve.

    Args:
        legs: Option legs
        S_range: Array of underlying prices

    Returns:
        Payoff array aligned with S_range, including premium cost
    """
    total_payoff = np.zeros(len(S_range))
    net_premium = sum(leg.direction * leg.quantity * leg.premium for leg in legs)

    for leg in legs:
        if leg.option_type == "call":
            intrinsic = np.maximum(S_range - leg.K, 0)
        else:
            intrinsic = np.maximum(leg.K - S_range, 0)
        total_payoff += leg.direction * leg.quantity * intrinsic

    return total_payoff - net_premium


def compute_theo_value(
    legs: list[OptionLeg],
    S_range: np.ndarray,
    r: float = 0.03,
    q: float = 0.0,
) -> np.ndarray:
    """Calculate the theoretical value curve under current Black-Scholes pricing.

    Args:
        legs: Option legs, each carrying T and sigma
        S_range: Array of underlying prices
        r: Risk-free rate
        q: Continuous dividend yield

    Returns:
        Theoretical PnL array
    """
    total_value = np.zeros(len(S_range))
    net_premium = sum(leg.direction * leg.quantity * leg.premium for leg in legs)

    for leg in legs:
        prices = np.array([
            bs_price(S, leg.K, leg.T, r, leg.sigma, leg.option_type, q)
            for S in S_range
        ])
        total_value += leg.direction * leg.quantity * prices

    return total_value - net_premium


def find_breakeven_points(
    S_range: np.ndarray,
    payoff: np.ndarray,
) -> list[float]:
    """Solve for break-even points numerically.

    Returns:
        A list of break-even points, from 0 to many depending on the structure
    """
    beps = []
    for i in range(len(S_range) - 1):
        if payoff[i] * payoff[i + 1] < 0:
            bep = brentq(
                lambda s: np.interp(s, S_range, payoff),
                S_range[i], S_range[i + 1],
                xtol=0.01
            )
            beps.append(round(bep, 2))
    return beps

4.3 Matplotlib Payoff Diagram

python
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker

def plot_payoff_diagram(
    legs: list[OptionLeg],
    S_current: float,
    r: float = 0.03,
    q: float = 0.0,
    title: str = "Option Payoff Diagram",
    figsize: tuple = (10, 6),
) -> plt.Figure:
    """Plot the payoff diagram for an option portfolio.

    Args:
        legs: Option legs
        S_current: Current underlying price
        r: Risk-free rate
        q: Continuous dividend yield
        title: Chart title
        figsize: Figure size

    Returns:
        A matplotlib Figure object
    """
    K_values = [leg.K for leg in legs]
    S_lo = min(K_values) * 0.70
    S_hi = max(K_values) * 1.30
    S_range = np.linspace(S_lo, S_hi, 500)

    expiry_pnl = compute_expiry_payoff(legs, S_range)
    theo_pnl = compute_theo_value(legs, S_range, r, q)
    beps = find_breakeven_points(S_range, expiry_pnl)

    fig, ax = plt.subplots(figsize=figsize)

    # Shade profit and loss regions.
    ax.fill_between(S_range, expiry_pnl, 0,
                    where=(expiry_pnl >= 0), alpha=0.15, color="green", label="_nolegend_")
    ax.fill_between(S_range, expiry_pnl, 0,
                    where=(expiry_pnl < 0), alpha=0.15, color="red", label="_nolegend_")

    # Expiry payoff curve.
    ax.plot(S_range, expiry_pnl, color="steelblue", linewidth=2.0, label="Expiry P&L")

    # Theoretical value curve.
    ax.plot(S_range, theo_pnl, color="darkorange", linewidth=1.5,
            linestyle="--", label="Current theoretical value")

    # Zero axis.
    ax.axhline(0, color="black", linewidth=0.8, linestyle="-")

    # Current price line.
    ax.axvline(S_current, color="gray", linewidth=1.0, linestyle=":",
               label=f"Spot {S_current:.2f}")

    # Strike annotations.
    for K in K_values:
        ax.axvline(K, color="purple", linewidth=0.6, linestyle="--", alpha=0.5)
        ax.text(K, ax.get_ylim()[0], f"K={K}", fontsize=8,
                rotation=90, va="bottom", color="purple")

    # Break-even points.
    for bep in beps:
        ax.scatter([bep], [0], color="red", zorder=5, s=50)
        ax.annotate(f"BEP\n{bep:.2f}", xy=(bep, 0),
                    xytext=(bep, max(expiry_pnl) * 0.15),
                    fontsize=8, ha="center", color="red",
                    arrowprops=dict(arrowstyle="->", color="red", lw=0.8))

    # Max profit / max loss summary.
    max_p = max(expiry_pnl)
    max_l = min(expiry_pnl)
    stats_text = (
        f"Max profit: {'Unlimited' if max_p > 1e6 else f'{max_p:.2f}'}\n"
        f"Max loss: {'Unlimited' if max_l < -1e6 else f'{max_l:.2f}'}\n"
        f"Break-even: {', '.join([str(b) for b in beps]) if beps else 'None'}"
    )
    ax.text(0.02, 0.97, stats_text, transform=ax.transAxes,
            fontsize=9, va="top", bbox=dict(boxstyle="round", fc="white", alpha=0.8))

    ax.set_xlabel("Underlying price")
    ax.set_ylabel("P&L")
    ax.set_title(title)
    ax.legend(loc="upper right")
    ax.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x, _: f"{x:,.0f}"))
    ax.grid(True, alpha=0.3)
    plt.tight_layout()

    return fig

4.4 Plotly Interactive Payoff Diagram (Recommended for Frontend Display)

python
import plotly.graph_objects as go

def plot_payoff_plotly(
    legs: list[OptionLeg],
    S_current: float,
    r: float = 0.03,
    q: float = 0.0,
    title: str = "Option Payoff Diagram",
    sigma_scenarios: list[float] | None = None,
) -> go.Figure:
    """Generate a Plotly interactive payoff diagram with optional multi-sigma scenarios.

    Args:
        sigma_scenarios: For example [0.10, 0.15, 0.20, 0.25, 0.30].
            If None, use each leg's own sigma.
    """
    K_values = [leg.K for leg in legs]
    S_range = np.linspace(min(K_values) * 0.70, max(K_values) * 1.30, 500)
    expiry_pnl = compute_expiry_payoff(legs, S_range)

    fig = go.Figure()

    # Expiry payoff.
    fig.add_trace(go.Scatter(
        x=S_range, y=expiry_pnl,
        name="Expiry P&L", line=dict(color="steelblue", width=2),
        fill="tozeroy",
        fillcolor="rgba(70,130,180,0.1)",
    ))

    # Theoretical value under multiple volatility scenarios.
    if sigma_scenarios:
        colors = ["#FF6B6B", "#FFA500", "#4CAF50", "#2196F3", "#9C27B0"]
        for i, sigma in enumerate(sigma_scenarios):
            scenario_legs = [
                OptionLeg(
                    option_type=leg.option_type, K=leg.K,
                    direction=leg.direction, quantity=leg.quantity,
                    premium=leg.premium, T=leg.T, sigma=sigma
                )
                for leg in legs
            ]
            theo = compute_theo_value(scenario_legs, S_range, r, q)
            fig.add_trace(go.Scatter(
                x=S_range, y=theo,
                name=f"IV={sigma*100:.0f}%",
                line=dict(color=colors[i % len(colors)], width=1.5, dash="dash"),
            ))
    else:
        theo_pnl = compute_theo_value(legs, S_range, r, q)
        fig.add_trace(go.Scatter(
            x=S_range, y=theo_pnl,
            name="Current theoretical value",
            line=dict(color="darkorange", width=1.5, dash="dash"),
        ))

    # Zero line and current price line.
    fig.add_hline(y=0, line_dash="solid", line_color="black", line_width=0.8)
    fig.add_vline(x=S_current, line_dash="dot", line_color="gray",
                  annotation_text=f"Spot {S_current:.2f}", annotation_position="top right")

    # Strikes.
    for K in set(K_values):
        fig.add_vline(x=K, line_dash="dash", line_color="purple",
                      line_width=0.8, opacity=0.5)

    fig.update_layout(
        title=title,
        xaxis_title="Underlying price",
        yaxis_title="P&L",
        hovermode="x unified",
        template="plotly_white",
        legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
    )

    return fig

4.5 Greeks Profile vs Underlying Price

python
from src.quantlib.options import bs_greeks

def plot_greeks_profile(
    legs: list[OptionLeg],
    S_current: float,
    r: float = 0.03,
    q: float = 0.0,
    greeks_to_plot: list[str] | None = None,
) -> go.Figure:
    """Plot portfolio Greeks as functions of the underlying price.

    Args:
        greeks_to_plot: Defaults to ["delta", "gamma", "vega", "theta"]
    """
    if greeks_to_plot is None:
        greeks_to_plot = ["delta", "gamma", "vega", "theta"]

    K_values = [leg.K for leg in legs]
    S_range = np.linspace(min(K_values) * 0.70, max(K_values) * 1.30, 300)

    # Compute portfolio Greeks.
    greek_values = {g: np.zeros(len(S_range)) for g in greeks_to_plot}
    for leg in legs:
        for j, S in enumerate(S_range):
            g = bs_greeks(S, leg.K, leg.T, r, leg.sigma, leg.option_type, q)
            for name in greeks_to_plot:
                greek_values[name][j] += leg.direction * leg.quantity * g[name]

    # Plot subplots.
    from plotly.subplots import make_subplots
    n = len(greeks_to_plot)
    fig = make_subplots(rows=n, cols=1, shared_xaxes=True,
                        subplot_titles=[g.capitalize() for g in greeks_to_plot])

    greek_colors = {"delta": "steelblue", "gamma": "green",
                    "theta": "red", "vega": "darkorange", "rho": "purple"}

    for i, name in enumerate(greeks_to_plot, start=1):
        fig.add_trace(
            go.Scatter(x=S_range, y=greek_values[name],
                       name=name.capitalize(),
                       line=dict(color=greek_colors.get(name, "gray"), width=2)),
            row=i, col=1
        )
        fig.add_hline(y=0, line_dash="dot", line_color="black",
                      line_width=0.5, row=i, col=1)
        fig.add_vline(x=S_current, line_dash="dash", line_color="gray",
                      line_width=0.8, row=i, col=1)

    fig.update_layout(
        title="Greeks Profile",
        height=200 * n,
        showlegend=False,
        template="plotly_white",
    )

    return fig

5. Practical Usage

5.1 Strategy Selection Decision Tree by Market View

Market view
├── Strongly bullish
│   ├── Willing to pay premium → Long Call
│   └── Want lower cost → Bull Call Spread
├── Moderately bullish
│   ├── Already hold the underlying → Covered Call (income enhancement)
│   └── No existing position → Bull Put Spread (net credit)
├── Moderately bearish
│   ├── Already hold the underlying → Protective Put or Collar
│   └── No existing position → Bear Call Spread (net credit)
├── Strongly bearish
│   ├── Willing to pay premium → Long Put
│   └── Want lower cost → Bear Put Spread
├── Range-bound market (low-IV environment)
│   ├── Wide range → Short Strangle
│   ├── Narrow range → Short Straddle
│   └── Want limited risk → Iron Condor / Iron Butterfly
└── Large move expected (low-IV environment)
    ├── Direction unclear → Long Straddle / Long Strangle
    └── Slight directional bias → Call / Put Back Spread

5.2 Volatility Environment → Strategy Mapping

IV RegimeRule of ThumbSuitable StrategiesStrategies to Avoid
Low IV (< 20th percentile)IV Rank < 20Long Straddle, Long Strangle, Back SpreadShort strategies, because premium is too thin
Normal IV (20th to 80th percentile)IV Rank 20 to 80Vertical spreads, Calendar Spread, DiagonalSingle-leg positions with asymmetric risk
High IV (> 80th percentile)IV Rank > 80Short Straddle, Iron Condor, Covered CallLong single-leg options due to rich premium

IV Rank formula:

python
iv_rank = (current_iv - iv_52w_low) / (iv_52w_high - iv_52w_low) * 100

IV Percentile: The historical percentile rank of current IV over the last 252 trading days.

5.3 When to Roll or Adjust

Rolling
  • Trigger: Option Delta moves outside the target range, or time to expiration < 21 days
  • Rolling Up / Down: Close the current leg and reopen at a higher / lower strike while keeping the same directional bias
  • Rolling Out: Close the near-month leg and reopen further out on the curve to harvest additional time value
  • Cost assessment: Compare the net debit / credit of the roll with the payoff from simply holding to expiration
Adjusting
  • Delta-neutral rebalancing: Hedge with underlying or options when portfolio Delta deviates from target by more than ±0.10
  • Gamma scalping: Under a Long Gamma portfolio, hedge Delta after large underlying moves to lock in gains
  • Stop-loss rule: Force liquidation when losses reach 2× the initial premium received, a common rule for Iron Condors
Common Adjustment Examples

Iron Condor gets breached:

Underlying rallies above the short call:
1. Close the call spread and realize the loss
2. Reassess directional view:
   - Still bullish → reopen a higher put spread to preserve neutrality
   - Not bullish → close the entire portfolio

Covered Call faces assignment risk:

Underlying approaches the call strike:
1. Assess whether you are willing to sell the underlying at that price
   - Yes → allow assignment and keep premium + capital gain
   - No → Roll Up & Out to a higher strike and/or later expiration

Quick Usage Example

python
from src.quantlib.options import implied_volatility

# Example: Iron Condor payoff diagram
legs = [
    OptionLeg("put",  K=90,  direction=-1, premium=1.5, T=0.083, sigma=0.20),
    OptionLeg("put",  K=85,  direction=+1, premium=0.5, T=0.083, sigma=0.20),
    OptionLeg("call", K=110, direction=-1, premium=1.5, T=0.083, sigma=0.20),
    OptionLeg("call", K=115, direction=+1, premium=0.5, T=0.083, sigma=0.20),
]

fig = plot_payoff_plotly(
    legs, S_current=100.0,
    title="Iron Condor (85/90/110/115, 1 month)",
    sigma_scenarios=[0.15, 0.20, 0.25, 0.30],
)
fig.show()

# Implied volatility example
iv = implied_volatility(
    market_price=5.0, S=100, K=100,
    T=0.25, r=0.03, option_type="call"
)
print(f"Implied volatility: {iv:.2%}")  # 23.25%

Frequently asked questions

What does the Options Payoff AI skill do?

Option P&L analysis methodology: payoff diagrams, breakeven calculation, multi-leg strategy visualization, and Greeks-based scenario analysis.

Why use Options Payoff on TypingMind?

Because you install it once and use it with any model. Options Payoff is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Options Payoff in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/HKUDS/Vibe-Trading/tree/main/agent/src/skills/options-payoff. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Options Payoff?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Options Payoff?

As many as you like. As long as a model supports skills, you can use Options Payoff with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Options Payoff AI skill free?

Yes. It is published on GitHub by HKUDS under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇