Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage

Michael BrenndoerferDecember 30, 202566 min read

Master volatility as an asset class. Learn delta hedging, variance swaps, dispersion trading, and VIX strategies to exploit implied versus realized volatility.

Reading Level

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Volatility Trading and Arbitrage Strategies

Volatility is more than just a parameter in option pricing models; it is a tradeable asset class in its own right. While you might focus on predicting the direction of asset prices, you take positions on the magnitude of future price movements, regardless of direction. This distinction opens up an entirely different dimension of market opportunity.

The appeal of volatility trading stems from several observations. First, as we explored in Part III's discussion of implied volatility and the volatility smile, implied volatility extracted from option prices often differs systematically from subsequently realized volatility. This persistent gap, known as the volatility risk premium, creates opportunities for those who can model and harvest it. Second, volatility exhibits mean-reverting behavior and clustering effects, as we saw when studying GARCH models in Part III, Chapter 18. These statistical properties make volatility more predictable than price returns in certain respects. Third, volatility positions can provide portfolio diversification benefits, as volatility tends to spike during market stress when traditional assets decline.

This chapter develops the tools and strategies for trading volatility. We begin by examining the instruments available, from vanilla options to VIX futures and variance swaps, before diving into delta hedging strategies that isolate pure volatility exposure. We then explore volatility arbitrage, where you exploit mispricings between implied and realized volatility, and dispersion trading, which capitalizes on the relationship between index volatility and constituent volatility. Throughout, we emphasize the substantial risks involved, particularly for strategies that are short volatility.

Volatility as an Asset Class

Before examining specific strategies, we need to understand what it means to trade volatility and the instruments available for doing so.

Implied Versus Realized Volatility

Recall from Part III, Chapter 8 that implied volatility (σimp\sigma_{\text{imp}}) is the volatility level that, when plugged into the Black-Scholes formula, produces the observed market price of an option. It represents the market's expectation of future volatility over the option's life, plus any risk premium. Realized volatility (σreal\sigma_{\text{real}}), in contrast, is the actual volatility that materializes over a given period, typically calculated as the annualized standard deviation of log returns.

Distinguishing between these two measures is fundamental to volatility trading. Implied volatility is forward-looking: it captures what market participants collectively believe will happen to the underlying asset's price movements over the life of the option. This belief is embedded in the prices they are willing to pay for options. Realized volatility, on the other hand, is backward-looking: it measures what actually occurred in the market during a specific historical period. These two measures are rarely equal. Markets must form expectations about the future under uncertainty, and those expectations can systematically differ from what eventually transpires.

The relationship between these two quantities drives most volatility trading strategies:

  • When σimp>σreal\sigma_{\text{imp}} > \sigma_{\text{real}}: Options are "expensive" relative to the volatility that actually occurs. Selling options and delta-hedging can be profitable.
  • When σimp<σreal\sigma_{\text{imp}} < \sigma_{\text{real}}: Options are "cheap" relative to realized moves. Buying options and delta-hedging captures the volatility differential.

In the first scenario, market participants overestimated future price movements. They paid a premium for protection or speculation that was larger than justified by the actual market conditions. If you recognize this overpricing, you can sell options, collect the inflated premium, and hedge away the directional exposure, profiting from the difference between what was expected and what occurred. In the second scenario, market participants underestimated future volatility. If you buy these cheap options and manage the directional risk, you profit when the market moves more than expected.

In[2]:
Code
import numpy as np
import pandas as pd

# Generate sample price series
np.random.seed(42)
n_days = 252
daily_returns = np.random.normal(0.0003, 0.015, n_days)
prices = 100 * np.exp(np.cumsum(daily_returns))

# Calculate realized volatility (rolling 21-day)
returns = np.diff(np.log(prices))
window = 21
realized_vol = pd.Series(returns).rolling(window).std() * np.sqrt(252)

# Simulate implied volatility (typically higher than realized due to risk premium)
implied_vol = realized_vol + np.random.normal(0.02, 0.005, len(realized_vol))
implied_vol = np.maximum(implied_vol, 0.05)  # Floor at 5%
Out[3]:
Visualization
Time series showing implied volatility consistently above realized volatility over one year.
Comparison of implied and 21-day realized volatility over a trading year. Implied volatility typically trades above realized volatility, creating a persistent gap known as the volatility risk premium that sellers attempt to harvest.

The Volatility Risk Premium

The volatility risk premium (VRP) is the systematic tendency for implied volatility to exceed subsequently realized volatility. This premium exists because investors are generally willing to pay extra for portfolio protection during market declines. Just as insurance premiums exceed expected claims to compensate insurers for bearing tail risk, option premiums include compensation for volatility sellers who bear the risk of extreme moves.

Investor behavior and market structure drive the volatility risk premium. Most institutional investors hold long equity portfolios, and their primary concern during market stress is downside protection. When uncertainty increases, these investors bid up the prices of put options and other hedging instruments, driving implied volatility above the level that purely reflects expected realized volatility. Volatility sellers, who step in to provide this insurance, demand compensation for taking on the risk that markets could move more violently than anticipated. This compensation manifests as the persistent gap between implied and realized volatility.

In[4]:
Code
# Calculate volatility risk premium
vrp_series = (implied_vol - realized_vol).dropna()
Out[5]:
Console
Average Volatility Risk Premium: 2.02%
VRP Standard Deviation: 0.49%
Percentage of Days VRP > 0: 100.0%
Out[6]:
Visualization
Histogram showing the distribution of volatility risk premium values, with most values positive.
Probability density of the volatility risk premium calculated as the difference between implied and realized volatility. The right-skewed distribution shows that the majority of observations are positive, confirming the systematic overpricing of options relative to realized moves.

A positive average volatility risk premium does not make selling volatility a free lunch. The distribution of returns from short volatility strategies is highly negatively skewed, with small gains most of the time punctuated by occasional large losses during volatility spikes.

Instruments for Trading Volatility

You have several instruments at your disposal:

Options on Underlying Assets

The most direct way to gain volatility exposure is through options on stocks, indices, or ETFs. Buying straddles or strangles provides long volatility exposure, while selling them provides short volatility exposure. However, options also carry delta exposure to the underlying asset's direction, which must be managed.

VIX and Volatility Index Futures

The CBOE Volatility Index (VIX) measures the 30-day implied volatility of S&P 500 index options. VIX futures allow you to take positions on expected future levels of implied volatility. The VIX futures curve is typically in contango (upward sloping), meaning longer-dated futures trade at higher prices than spot VIX, creating a roll cost for long VIX positions.

Variance Swaps

A variance swap is an over-the-counter derivative that pays the difference between realized variance and a fixed strike variance. Unlike options, variance swaps provide pure exposure to realized volatility without any delta component. We will examine these in detail later in this chapter.

Volatility ETFs and ETNs

Products like VXX (short-term VIX futures ETN) and SVXY (inverse VIX ETF) provide retail-accessible volatility exposure. These products suffer from significant roll costs and are designed for short-term trading rather than buy-and-hold positions.

Delta-Hedged Option Strategies

The key to isolating pure volatility exposure from options is delta hedging. By continuously adjusting a hedge position in the underlying asset, you can neutralize directional exposure and focus exclusively on whether implied volatility overstates or understates realized volatility.

The Mechanics of Delta Hedging

Consider if we sell a call option with delta ΔC\Delta_C. To become delta-neutral, we buy ΔC\Delta_C shares of the underlying. As the underlying price moves and time passes, the option's delta changes. We must rebalance the hedge, buying more shares when delta increases and selling when delta decreases.

Delta hedging transforms an option position with directional and volatility exposure into a pure volatility bet. When you sell an option without hedging, your profit depends heavily on which way the underlying asset moves. But when you hedge away the directional exposure by holding offsetting shares, your profit depends only on whether the option was priced correctly relative to the actual volatility that materializes. This separation of concerns is what makes volatility trading possible as a distinct discipline.

Delta-Neutral Position

A delta-neutral position has zero first-order sensitivity to small changes in the underlying price. For a portfolio of options and underlying shares, the position is delta-neutral when iΔiQi=0\sum_i \Delta_i \cdot Q_i = 0, where Δi\Delta_i is the delta of each position and QiQ_i is the quantity.

In[7]:
Code
from scipy.stats import norm


def black_scholes_call(S, K, T, r, sigma):
    """Calculate Black-Scholes call price and delta."""
    if T <= 0:
        return max(S - K, 0), 1.0 if S > K else 0.0

    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)

    call_price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    delta = norm.cdf(d1)
    gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))

    return call_price, delta, gamma


# Option parameters
S0 = 100
K = 100
T = 30 / 365  # 30 days to expiration
r = 0.05
sigma_implied = 0.25

# Calculate initial option price and Greeks
call_price, delta, gamma = black_scholes_call(S0, K, T, r, sigma_implied)
Out[8]:
Console
Initial Call Price: $3.06
Initial Delta: 0.5371
Initial Gamma: 0.0554

To delta-hedge 1 short call, buy 0.5371 shares
Out[9]:
Visualization
Delta profile for a call option across a range of stock prices. The delta transitions from 0 to 1 as the asset moves from out-of-the-money to in-the-money, with the highest rate of change occurring near the strike price.
Delta profile for a call option across a range of stock prices. The delta transitions from 0 to 1 as the asset moves from out-of-the-money to in-the-money, with the highest rate of change occurring near the strike price.
Gamma profile for a call option highlighting its peak at the strike price. The bell-shaped curve shows where the option's delta is most sensitive to price movements, representing the area of highest hedging risk for you.
Gamma profile for a call option highlighting its peak at the strike price. The bell-shaped curve shows where the option's delta is most sensitive to price movements, representing the area of highest hedging risk for you.

The positive delta indicates that the option price moves in the same direction as the underlying asset. To hedge a short call position (which has negative delta exposure), you must buy shares of the underlying asset to neutralize directional risk. The gamma value represents the curvature of the option price; a higher gamma requires more frequent rebalancing of the hedge ratio. Gamma tells us how quickly the delta changes as the underlying moves, and therefore how much trading activity will be required to maintain the hedge. Options near the money and close to expiration have the highest gamma, meaning they require the most active management.

P&L from Delta-Hedged Positions

The profit or loss from a delta-hedged option position comes from the interaction between the option's theta decay and the gamma-driven gains from rebalancing. To understand this relationship, we need to analyze how the value of a delta-hedged portfolio changes over time and with price movements.

We can derive the P&L dynamics by analyzing the change in value of the delta-hedged portfolio Π=VΔS\Pi = V - \Delta S. Using a second-order Taylor expansion (Ito's Lemma):

Daily P&L=dVΔdS=(Θdt+ΔdS+12Γ(dS)2)ΔdS(Ito’s Lemma)=Θdt+12Γ(dS)2(cancel ΔdS terms)Θdt+12ΓS2σreal2dt(substitute (dS)2S2σreal2dt)\begin{aligned} \text{Daily P\&L} &= dV - \Delta dS \\ &= \left( \Theta dt + \Delta dS + \frac{1}{2}\Gamma (dS)^2 \right) - \Delta dS && \text{(Ito's Lemma)} \\ &= \Theta dt + \frac{1}{2}\Gamma (dS)^2 && \text{(cancel $\Delta dS$ terms)} \\ &\approx \Theta dt + \frac{1}{2}\Gamma S^2 \sigma_{\text{real}}^2 dt && \text{(substitute $(dS)^2 \approx S^2 \sigma_{\text{real}}^2 dt$)} \end{aligned}

where:

  • Daily P&L\text{Daily P\&L}: profit or loss over the time step
  • VV: option value
  • Δ\Delta: option delta
  • Γ\Gamma: option gamma
  • SS: underlying asset price
  • σreal\sigma_{\text{real}}: realized volatility of the underlying asset
  • dtdt: small time increment
  • Θ\Theta: option theta

This derivation shows the tension in delta-hedged option positions. The first step applies Ito's Lemma to express how the option value changes: it moves with time (theta), with the underlying price (delta times the price change), and with the square of the price change (half gamma times the squared move). When we subtract the hedge position's change in value, the delta terms cancel perfectly because that is exactly what the hedge is designed to do. What remains are the theta and gamma terms, which cannot be hedged away simultaneously.

For a delta-hedged long option position:

  • Theta (Θ\Theta): The option loses value due to time decay. This is a cost.
  • Gamma (Γ\Gamma): When the underlying moves, the hedge position profits from rebalancing. This is a gain.

The key insight is that theta cost is determined by implied volatility (priced into the option), while gamma gains are determined by realized volatility (actual market moves). If realized volatility exceeds implied, gamma gains exceed theta costs, and the long volatility position profits. This is the essential mechanism of volatility trading: you are betting on whether the actual price movements will be larger or smaller than what the option price assumed.

The theta of an option represents the daily cost of maintaining the position, and this cost is higher when implied volatility is higher because a higher implied volatility means a more expensive option that has more time value to decay. The gamma gains, conversely, depend on how much the underlying actually moves. When the underlying makes a large move, a long gamma position benefits because the delta has changed, and the hedge needs rebalancing at favorable prices. If these actual moves are consistently larger than what was priced in, the rebalancing gains exceed the time decay costs.

In[10]:
Code
def simulate_delta_hedge(
    S0, K, T, r, sigma_imp, sigma_real, n_steps=100, n_paths=1000
):
    """
    Simulate delta-hedged option P&L.

    Parameters:
    - sigma_imp: Implied volatility (used to price option)
    - sigma_real: Realized volatility (actual price moves)
    """
    dt = T / n_steps

    # Initial option price at implied vol
    initial_call, initial_delta, _ = black_scholes_call(S0, K, T, r, sigma_imp)

    pnls = []

    for _ in range(n_paths):
        S = S0
        cash = initial_call - initial_delta * S  # Sell call, buy delta shares
        shares = initial_delta

        for step in range(n_steps):
            # Remaining time
            tau = T - step * dt
            if tau <= dt:
                break

            # Price moves with realized volatility
            dW = np.random.normal(0, np.sqrt(dt))
            S_new = S * np.exp((r - 0.5 * sigma_real**2) * dt + sigma_real * dW)

            # Rebalance hedge using implied vol for delta calculation
            _, new_delta, _ = black_scholes_call(
                S_new, K, tau - dt, r, sigma_imp
            )

            # Cost of rebalancing
            cash = cash * np.exp(r * dt)  # Earn interest on cash
            rebalance_cost = (new_delta - shares) * S_new
            cash -= rebalance_cost
            shares = new_delta
            S = S_new

        # Final P&L at expiration
        option_payoff = max(S - K, 0)
        final_value = cash + shares * S - option_payoff
        pnls.append(final_value)

    return np.array(pnls)
In[11]:
Code
# Simulate three scenarios
np.random.seed(42)

# Define volatility scenarios
imp_vol = 0.25
real_vol_neutral = 0.25
real_vol_low = 0.18
real_vol_high = 0.35

# Scenario 1: Realized vol = Implied vol
pnl_neutral = simulate_delta_hedge(
    100, 100, 30 / 365, 0.05, imp_vol, real_vol_neutral
)

# Scenario 2: Realized vol < Implied vol (profitable for short vol)
pnl_low_real = simulate_delta_hedge(
    100, 100, 30 / 365, 0.05, imp_vol, real_vol_low
)

# Scenario 3: Realized vol > Implied vol (loss for short vol)
pnl_high_real = simulate_delta_hedge(
    100, 100, 30 / 365, 0.05, imp_vol, real_vol_high
)
Out[12]:
Visualization
Three overlapping histograms showing P&L distributions for different volatility scenarios.
Profit and loss distributions for a delta-hedged short call across three volatility scenarios. The strategy generates positive returns when realized volatility remains below the 25% implied volatility level, while higher realized moves lead to significant losses from gamma rebalancing costs.
Out[13]:
Console
Delta-Hedged Short Call P&L Summary:

Realized = Implied (25%):  Mean P&L = $0.02, Std = $0.25
Realized (18%) < Implied:  Mean P&L = $0.83, Std = $0.32
Realized (35%) > Implied:  Mean P&L = $-1.13, Std = $0.60

The simulation confirms our theoretical expectation: when realized volatility is lower than implied, the short volatility position profits from collecting more theta than it loses to gamma. When realized volatility exceeds implied, the position loses money as gamma costs exceed theta gains. Notice also that even when realized and implied volatility are equal, there is dispersion in outcomes. This variance arises because while the average gamma gain equals the average theta loss, the actual path matters, and some paths will be more favorable than others purely by chance.

Gamma Scalping

Gamma scalping is a trading technique that attempts to profit from the gamma of a long option position. If you are long gamma (long options), you benefit when the underlying makes large moves in either direction. By rebalancing delta frequently, you "lock in" gains from these moves.

When you are long gamma and the stock rises, your delta increases. You are effectively longer the stock at higher prices. By selling some shares to rebalance to delta-neutral, you capture a profit. Similarly, when the stock falls, your delta decreases, and by buying shares at lower prices, you profit again.

To understand why this works, consider the mechanics of the hedge adjustment. When you are long a call option and the stock rises, your call option increases in value, but so does its delta. If you started with a delta-neutral position, you are now slightly long the market because your call is more sensitive to further moves. To restore neutrality, you sell shares at the current higher price. If the stock subsequently falls back, you will need to buy shares again at the lower price. You have effectively sold high and bought low, locking in a trading profit. This profit comes from the convexity of the option's payoff, which is measured by gamma.

You must weigh these gamma gains against theta decay. A long gamma position pays theta every day as the option loses time value. If the stock does not move enough to generate sufficient rebalancing profits, the theta costs will dominate and the position will lose money. This is why gamma scalping is only profitable when realized volatility exceeds implied volatility: the moves must be large enough and frequent enough to offset the daily time decay.

In[14]:
Code
def gamma_scalp_example(S0, K, T, r, sigma, price_path):
    """
    Demonstrate gamma scalping with a specific price path.
    """
    n_steps = len(price_path) - 1
    dt = T / n_steps

    # Initial position: long 1 call, short delta shares
    _, initial_delta, _ = black_scholes_call(S0, K, T, r, sigma)

    shares = -initial_delta  # Short shares to hedge
    cash = initial_delta * S0  # Cash from selling shares

    records = []

    for step in range(n_steps):
        tau = T - step * dt
        S = price_path[step]
        S_new = price_path[step + 1]

        # Current delta
        _, delta, gamma = black_scholes_call(S, K, tau, r, sigma)

        # Skip if time is too small
        if tau <= dt:
            break
        if tau <= dt:
            break

        # P&L from share position
        share_pnl = shares * (S_new - S)

        # New delta for rebalancing
        _, new_delta, _ = black_scholes_call(S_new, K, tau - dt, r, sigma)

        # Rebalance
        shares_traded = -(
            new_delta - (-shares)
        )  # Negative because we're short delta worth of shares
        rebalance_cash = shares_traded * S_new

        records.append(
            {
                "step": step,
                "price": S,
                "delta": delta,
                "gamma": gamma,
                "shares": shares,
                "share_pnl": share_pnl,
                "shares_traded": shares_traded,
                "rebalance_cash": rebalance_cash,
            }
        )

        shares = -new_delta
        cash += rebalance_cash

    return pd.DataFrame(records)


# Create a volatile price path
np.random.seed(123)
n_steps = 20
price_path = [100]
for _ in range(n_steps):
    move = np.random.choice([-2, -1, 1, 2])  # Discrete jumps
    price_path.append(price_path[-1] + move)
price_path = np.array(price_path)

scalp_df = gamma_scalp_example(100, 100, 20 / 252, 0.05, 0.25, price_path)
Out[15]:
Visualization
Simulated stock price path featuring discrete jumps that trigger delta rebalancing. These price movements create the trading opportunities necessary for a gamma scalping strategy to generate profit.
Simulated stock price path featuring discrete jumps that trigger delta rebalancing. These price movements create the trading opportunities necessary for a gamma scalping strategy to generate profit.
Simulated stock price path featuring discrete jumps that trigger delta rebalancing. These price movements create the trading opportunities necessary for a gamma scalping strategy to generate profit.
Simulated stock price path featuring discrete jumps that trigger delta rebalancing. These price movements create the trading opportunities necessary for a gamma scalping strategy to generate profit.

The cash generated from rebalancing must be weighed against the theta decay of the option. If the stock moves enough (high realized volatility), rebalancing profits exceed theta costs, and the long gamma position is profitable. The chart illustrates how each price move generates a rebalancing transaction, and how these transactions accumulate over time. Notice that the cash generated tends to be positive regardless of whether the stock moves up or down: what matters is the magnitude of the move, not its direction. This directional indifference is the hallmark of a pure volatility position.

Key Parameters

The key parameters for delta-hedging strategies are:

  • S: Current stock price. The primary driver of option value and delta.
  • K: Strike price. Determines the moneyness of the option and gamma concentration.
  • T: Time to expiration. Affects theta decay and gamma magnitude.
  • r: Risk-free interest rate. Used in the Black-Scholes pricing and carrying cost calculations.
  • σ_imp: Implied volatility. Used to price the option and calculate the hedge ratio (delta).
  • σ_real: Realized volatility. The actual volatility of the underlying asset that determines rebalancing P&L.

Volatility Arbitrage

Volatility arbitrage strategies seek to profit from differences between implied volatility and expected realized volatility. These strategies require both a view on future volatility and the ability to isolate volatility exposure through hedging. The term "arbitrage" is a misnomer; these strategies involve taking a view rather than exploiting a riskless mispricing. However, the term has become standard in the industry to describe strategies that attempt to profit from the difference between where volatility is priced and where it will actually be realized.

Long Volatility Strategies

You go long volatility when you believe options are underpriced relative to future realized volatility. This typically occurs:

  • Before anticipated high-volatility events (earnings, elections, major economic announcements)
  • When implied volatility is historically low relative to its own range
  • When technical or fundamental factors suggest increased uncertainty

Long volatility positions can be constructed through:

  • Straddles: Buy both a call and put at the same strike, profiting from large moves in either direction
  • Strangles: Buy an out-of-the-money call and put, cheaper but requiring larger moves
  • Delta-hedged long options: Buy options and maintain delta-neutral exposure

A straddle combines a call and a put at the same strike price and expiration, creating a position that profits from any large price move regardless of direction. The maximum loss is limited to the premium paid for both options, which occurs if the underlying closes exactly at the strike at expiration. The trade becomes profitable when the underlying moves far enough from the strike to exceed the total premium paid.

The P&L for a long straddle at expiration is:

P&L=max(STK,0)+max(KST,0)(Cpremium+Ppremium)\text{P\&L} = \max(S_T - K, 0) + \max(K - S_T, 0) - (C_{\text{premium}} + P_{\text{premium}})

where:

  • P&L\text{P\&L}: profit or loss at expiration
  • STS_T: stock price at expiration
  • KK: strike price
  • CpremiumC_{\text{premium}}: premium paid for the call
  • PpremiumP_{\text{premium}}: premium paid for the put

The formula captures the essential structure of the straddle: at expiration, exactly one of the two options will be in the money (unless the stock closes precisely at the strike). If the stock is above the strike, the call pays out its intrinsic value while the put expires worthless. If the stock is below the strike, the put pays out while the call expires worthless. The first two terms in the formula calculate these payoffs, and the third term subtracts the cost of establishing the position. For the trade to be profitable, the stock must move far enough that the winning option's payoff exceeds the combined cost of both options.

In[16]:
Code
def straddle_payoff(S_T, K, call_premium, put_premium):
    """Calculate straddle P&L at expiration."""
    call_payoff = np.maximum(S_T - K, 0) - call_premium
    put_payoff = np.maximum(K - S_T, 0) - put_premium
    return call_payoff + put_payoff


def black_scholes_put(S, K, T, r, sigma):
    """Calculate Black-Scholes put price."""
    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)


# Straddle parameters
S = 100
K = 100
T = 30 / 365
r = 0.05
sigma = 0.25

call_price, _, _ = black_scholes_call(S, K, T, r, sigma)
put_price = black_scholes_put(S, K, T, r, sigma)
straddle_cost = call_price + put_price

# Calculate breakeven points
S_range = np.linspace(80, 120, 200)
straddle_pnl = straddle_payoff(S_range, K, call_price, put_price)

breakeven_down = K - straddle_cost
breakeven_up = K + straddle_cost
Out[17]:
Visualization
V-shaped payoff diagram showing profit for large price moves in either direction.
Expiration payoff profile for a long straddle at the \$100 strike. The V-shaped diagram illustrates that profit is achieved when the underlying asset moves beyond the upper or lower breakeven points, which are determined by the total premium paid for the call and put.
Out[18]:
Console
Straddle Cost: $5.72
Lower Breakeven: $94.28 (-5.7% move)
Upper Breakeven: $105.72 (5.7% move)

Implied Move: ±5.7% over 30 days

The "implied move" embedded in a straddle price represents the market's expectation of the stock's range. If you believe the stock will move more than this implied amount, you would buy the straddle. This implied move is a convenient way to interpret straddle prices: if a 30-day straddle costs 5% of the stock price, the market is implying that the stock will move approximately 5% in one direction or the other over that period. If you expect the stock to move 8% due to an upcoming catalyst, the straddle looks attractively priced.

Short Volatility Strategies

Short volatility strategies profit when implied volatility exceeds realized volatility. These strategies collect premium from option buyers who overpay for protection. Common approaches include:

  • Selling straddles or strangles: Collect premium, profit if stock stays range-bound
  • Iron condors: Sell strangle, buy further OTM options for protection
  • Covered calls or cash-secured puts: Systematic premium collection

For a short strangle involving a put with strike KPK_P and a call with strike KCK_C (where KP<KCK_P < K_C), the P&L at expiration is:

P&L=(Ppremium+Cpremium)max(KPST,0)max(STKC,0)\text{P\&L} = (P_{\text{premium}} + C_{\text{premium}}) - \max(K_P - S_T, 0) - \max(S_T - K_C, 0)

where:

  • P&L\text{P\&L}: profit or loss at expiration
  • PpremiumP_{\text{premium}}: premium received for the put
  • CpremiumC_{\text{premium}}: premium received for the call
  • KPK_P: put strike price
  • KCK_C: call strike price
  • STS_T: stock price at expiration

The formula reveals the risk-reward structure of a short strangle. The first term represents the premium collected upfront, which is the maximum possible profit. This maximum profit is realized if the stock finishes anywhere between the two strikes at expiration, in which case both options expire worthless and you keep the entire premium. The second and third terms represent potential losses: if the stock falls below the put strike or rises above the call strike, you must pay out the intrinsic value of the in-the-money option. Because there is no upper limit to how high the stock can rise and the stock can fall to zero, the potential losses on a short strangle are theoretically unlimited on the upside and substantial on the downside.

The key risk of short volatility strategies is their asymmetric payoff profile. Gains are limited to the premium collected, while losses can be substantial during volatility spikes.

In[19]:
Code
def short_strangle_payoff(S_T, K_put, K_call, put_premium, call_premium):
    """Calculate short strangle P&L at expiration."""
    put_payoff = put_premium - np.maximum(K_put - S_T, 0)
    call_payoff = call_premium - np.maximum(S_T - K_call, 0)
    return put_payoff + call_payoff


# Short strangle parameters
K_put = 95
K_call = 105
put_price = black_scholes_put(S, K_put, T, r, sigma)
call_price_otm, _, _ = black_scholes_call(S, K_call, T, r, sigma)
strangle_premium = put_price + call_price_otm

# Calculate payoff
strangle_pnl = short_strangle_payoff(
    S_range, K_put, K_call, put_price, call_price_otm
)
Out[20]:
Visualization
Payoff diagram with flat profit region between strikes and declining losses beyond.
Short strangle payoff profile with out-of-the-money strikes at 95 and 105. The strategy earns a maximum profit equal to the premium collected if the stock price stays between the strikes, but faces rapidly increasing losses if the price breaks through the breakeven points.

The payoff diagram highlights the defined profit zone between the strikes and the unlimited risk beyond the breakeven points. This structure benefits from time decay but requires the underlying asset to remain within a specific range. The flat profit region in the middle represents the comfort zone for short volatility traders: as long as the stock stays within this range, they earn the full premium. But the steep losses beyond the breakeven points illustrate why risk management is so critical for these strategies.

Building a Volatility Forecast

To succeed at volatility arbitrage, you must predict future realized volatility using one of several approaches:

Historical volatility models estimate future volatility based on past returns. As we covered in Part III, Chapter 18, GARCH models capture volatility clustering and mean reversion. The key insight behind GARCH is that volatility tends to be persistent: high volatility days tend to be followed by high volatility days, and low volatility periods tend to persist as well. By modeling this persistence explicitly, GARCH can provide more accurate short-term volatility forecasts than simple historical measures.

In[21]:
Code
def garch_forecast(returns, omega=0.00001, alpha=0.1, beta=0.85, n_ahead=21):
    """
    Simple GARCH(1,1) variance forecast.

    Variance forecast formula:
    σ²(t+1) = ω + α·ε²(t) + β·σ²(t)
    """
    # Initialize variance
    var = returns.var()

    # Update variance through history
    for ret in returns:
        var = omega + alpha * ret**2 + beta * var

    # Forecast future variance
    long_run_var = omega / (1 - alpha - beta)
    forecasts = []

    for h in range(1, n_ahead + 1):
        # Multi-step forecast converges to long-run variance
        forecast = long_run_var + (alpha + beta) ** (h - 1) * (
            var - long_run_var
        )
        forecasts.append(forecast)

    # Convert to annualized volatility
    avg_var = np.mean(forecasts)
    return np.sqrt(avg_var * 252)


# Generate sample returns
np.random.seed(42)
sample_returns = np.random.normal(0, 0.015, 100)

# Add a volatility cluster
sample_returns[50:60] = np.random.normal(0, 0.03, 10)

garch_vol = garch_forecast(sample_returns)
historical_vol = np.std(sample_returns[-21:]) * np.sqrt(252)
Out[22]:
Console
GARCH(1,1) 21-day Volatility Forecast: 19.7%
21-day Historical Volatility: 18.5%

The GARCH forecast differs from the simple historical volatility because it accounts for the recent volatility cluster in the data. By weighing recent observations more heavily and incorporating mean reversion, GARCH models often provide more responsive forecasts than rolling standard deviations. The model recognizes that the recent spike in volatility is likely to persist somewhat into the future, even as it gradually decays back toward the long-run average. This forward-looking adjustment makes GARCH particularly valuable for short-term volatility trading decisions.

Implied volatility models use the term structure and skew of implied volatility to forecast. If short-term implied volatility is elevated relative to longer-term volatility, mean reversion suggests it may decline.

Fundamental factors such as earnings announcements, economic data releases, and geopolitical events can inform volatility expectations.

Key Parameters

The key parameters for volatility forecasting models (like GARCH) are:

  • ω (omega): Baseline variance. The long-term floor for volatility.
  • α (alpha): Reaction parameter. Determines how much yesterday's shock impacts today's volatility.
  • β (beta): Persistence parameter. Determines how long shocks linger in the variance process (memory).
  • Returns: The time series of asset returns used to estimate parameters.

Dispersion Trading

Dispersion trading exploits the relationship between index volatility and the volatility of index constituents. The fundamental insight is that index variance depends not only on constituent variances but also on correlations between constituents. When you diversify by combining multiple assets, some of their movements cancel out, reducing overall portfolio volatility. This diversification effect creates a wedge between index volatility and the volatilities of individual stocks, and dispersion trading seeks to profit from this relationship.

The Variance Decomposition

For an index composed of nn stocks with weights wiw_i, the index variance is:

σindex2=i=1nwi2σi2+i=1njiwiwjρijσiσj\sigma_{\text{index}}^2 = \sum_{i=1}^{n} w_i^2 \sigma_i^2 + \sum_{i=1}^{n} \sum_{j \neq i} w_i w_j \rho_{ij} \sigma_i \sigma_j

where:

  • σindex2\sigma_{\text{index}}^2: variance of the index
  • nn: number of stocks in the index
  • wi,wjw_i, w_j: weight of stock ii and jj in the index
  • σi,σj\sigma_i, \sigma_j: volatility of stock ii and jj
  • ρij\rho_{ij}: correlation between stocks ii and jj

This formula applies portfolio variance mathematics to an index. It tells us that the total variance of the index comes from two distinct sources, and understanding these sources is crucial for dispersion trading.

The formula decomposes index variance into:

  • wi2σi2\sum w_i^2 \sigma_i^2: the weighted sum of individual variances (diagonal terms), representing concentration risk
  • wiwjρijσiσj\sum \sum w_i w_j \rho_{ij} \sigma_i \sigma_j: the weighted sum of pair-wise covariances (off-diagonal terms), representing correlation risk

The first component represents what would happen if each stock's movements were entirely independent: you would simply add up the variance contributions from each stock, weighted by the square of their index weights. The second component captures the interaction effects between stocks: when two stocks tend to move together (positive correlation), they add to index variance, while independent or negatively correlated movements partially cancel out.

This can be rewritten using average correlation ρˉ\bar{\rho}:

σindex2(wi2)σ2+(1wi2)ρˉσˉ2\sigma_{\text{index}}^2 \approx \left(\sum w_i^2\right) \overline{\sigma^2} + \left(1 - \sum w_i^2\right) \bar{\rho} \bar{\sigma}^2

where:

  • σindex2\sigma_{\text{index}}^2: variance of the index
  • wi2\sum w_i^2: sum of squared weights (measure of concentration)
  • σ2\overline{\sigma^2}: average variance of constituents
  • ρˉ\bar{\rho}: average pairwise correlation between constituents
  • σˉ2\bar{\sigma}^2: square of the average constituent volatility

This simplified form makes the role of correlation crystal clear. The first term depends only on individual volatilities and index concentration, while the second term scales directly with the average correlation. When correlation is zero, the second term vanishes entirely, and the index variance is driven purely by the concentration-weighted individual variances. As correlation increases, the second term grows, and the diversification benefit shrinks.

The key implication is that when correlations are high, index volatility approaches the average constituent volatility. When correlations are low, diversification reduces index volatility below constituent volatility.

In[23]:
Code
def index_volatility(weights, vols, corr_matrix):
    """Calculate index volatility from constituent vols and correlations."""
    n = len(weights)
    cov_matrix = np.outer(vols, vols) * corr_matrix
    portfolio_var = weights @ cov_matrix @ weights
    return np.sqrt(portfolio_var)


# Example: 5-stock equal-weighted index
n_stocks = 5
weights = np.ones(n_stocks) / n_stocks
stock_vols = np.array([0.30, 0.25, 0.35, 0.28, 0.32])  # Individual volatilities

# Calculate index vol at different correlation levels
correlations = np.linspace(0, 1, 50)
index_vols = []

for rho in correlations:
    # Create correlation matrix with uniform correlation
    corr_matrix = np.full((n_stocks, n_stocks), rho)
    np.fill_diagonal(corr_matrix, 1.0)

    idx_vol = index_volatility(weights, stock_vols, corr_matrix)
    index_vols.append(idx_vol)

index_vols = np.array(index_vols)
avg_stock_vol = np.mean(stock_vols)
Out[24]:
Visualization
Line chart showing index volatility rising from low to high as correlation increases.
Relationship between average constituent correlation and total index volatility. As correlation rises from 0 to 1, the diversification benefit diminishes and index volatility converges toward the average volatility of its individual components.

The Dispersion Trade

A dispersion trade takes opposing volatility positions on an index versus its constituents. The two main configurations are:

Long Dispersion (Short Correlation):

This trade profits when realized correlation is lower than implied correlation. It is typically the direction you choose because implied correlation tends to be higher than realized correlation, similar to the volatility risk premium. Index option buyers are often hedgers who pay a premium for protection against broad market moves. This demand pushes up index implied volatility relative to what the constituent implied volatilities would suggest.

Short Dispersion (Long Correlation):

  • Buy index options
  • Sell constituent options

This trade profits when correlations spike, typically during market stress. It serves as a tail hedge. During crises, correlations tend to spike as all assets sell off together, causing index volatility to surge relative to individual stock volatilities. A short dispersion position profits from this correlation spike.

In[25]:
Code
def dispersion_trade_pnl(
    index_implied_vol,
    constituent_implied_vols,
    weights,
    realized_corr_matrix,
    realized_vols,
):
    """
    Calculate P&L from a dispersion trade (simplified).

    Trade: Short 1 unit of index variance, Long weighted constituent variances
    """
    # Realized index volatility
    realized_index_vol = index_volatility(
        weights, realized_vols, realized_corr_matrix
    )

    # Implied index volatility (given)
    # P&L from short index variance swap (notional = 1)
    index_pnl = index_implied_vol**2 - realized_index_vol**2

    # Implied constituent variances (weighted average of implied vols)
    implied_constituent_var = np.sum(weights * constituent_implied_vols**2)

    # Realized constituent variances (weighted average of realized vols)
    realized_constituent_var = np.sum(weights * realized_vols**2)

    # P&L from long constituent variance (weighted)
    constituent_pnl = realized_constituent_var - implied_constituent_var

    # Total dispersion P&L
    total_pnl = index_pnl + constituent_pnl

    return {
        "index_pnl": index_pnl,
        "constituent_pnl": constituent_pnl,
        "total_pnl": total_pnl,
        "realized_index_vol": realized_index_vol,
        "implied_correlation": None,  # Would need to calculate
    }


# Simulate dispersion trade
np.random.seed(42)

# Market-implied values
index_implied = 0.22
constituent_implied = np.array([0.28, 0.25, 0.30, 0.27, 0.26])

# Scenario 1: Low realized correlation (dispersion trade profits)
rho_low = 0.3
low_corr = np.full((5, 5), rho_low)
np.fill_diagonal(low_corr, 1.0)
realized_vols_1 = constituent_implied * 0.95  # Realized slightly below implied

pnl_low_corr = dispersion_trade_pnl(
    index_implied, constituent_implied, weights, low_corr, realized_vols_1
)

# Scenario 2: High realized correlation (dispersion trade loses)
rho_high = 0.8
high_corr = np.full((5, 5), rho_high)
np.fill_diagonal(high_corr, 1.0)

pnl_high_corr = dispersion_trade_pnl(
    index_implied, constituent_implied, weights, high_corr, realized_vols_1
)
Out[26]:
Console
Dispersion Trade P&L Analysis (Variance Points)
==================================================

Scenario 1: Low Correlation (ρ = 0.3)
  Realized Index Vol: 17.2%
  Short Index Variance P&L: 189.8 bps
  Long Constituent Var P&L: -72.4 bps
  Total P&L: 117.4 bps

Scenario 2: High Correlation (ρ = 0.8)
  Realized Index Vol: 23.7%
  Short Index Variance P&L: -77.0 bps
  Long Constituent Var P&L: -72.4 bps
  Total P&L: -149.4 bps
Out[27]:
Visualization
Bar chart comparing P&L components for low and high correlation scenarios.
Decomposition of dispersion trade P&L into index and constituent components across low and high correlation scenarios. Long dispersion strategies profit when realized correlation is lower than implied, as the gains from individual stock options outweigh the losses from the short index position.

In the low correlation scenario, the realized index volatility is significantly lower than the weighted constituent volatility, generating profit for the dispersion trade (short index, long constituents). When realized correlation is high, this diversification benefit disappears, and the trade suffers losses as the short index position moves against you. The dispersion trade is fundamentally a bet on correlation: if correlations come in lower than what option prices imply, the long dispersion trade profits.

Implied Correlation

You can express your views in terms of implied correlation, which can be backed out from index and constituent implied volatilities:

ρimplied=σindex2iwi2σi2ijwiwjσiσj\rho_{\text{implied}} = \frac{\sigma_{\text{index}}^2 - \sum_i w_i^2 \sigma_i^2}{\sum_{i \neq j} w_i w_j \sigma_i \sigma_j}

where:

  • ρimplied\rho_{\text{implied}}: implied correlation derived from market prices
  • σindex\sigma_{\text{index}}: implied volatility of the index
  • wi,wjw_i, w_j: weights of constituents ii and jj
  • σi,σj\sigma_i, \sigma_j: implied volatilities of constituents ii and jj

This formula inverts the variance decomposition equation to solve for correlation. Given the observed implied volatility of the index and the implied volatilities of all constituents, we can back out the correlation level that would make these prices consistent. This implied correlation represents the market's collective expectation of how correlated stock returns will be over the option's life.

When implied correlation is high relative to expected realized correlation, a long dispersion trade (short correlation) is attractive. You are effectively betting that the market is overpricing co-movement and that individual stocks will move more independently than option prices suggest.

Key Parameters

The key parameters for dispersion trading are:

  • w_i: Weight of each constituent in the index.
  • σ_index: Volatility of the index. Lower than average constituent volatility due to diversification.
  • σ_constituent: Volatility of individual stocks in the index.
  • ρ (rho): Pairwise correlation between constituents. The primary driver of the spread between index and constituent volatility.
In[28]:
Code
def implied_correlation(index_vol, constituent_vols, weights):
    """
    Calculate implied correlation from index and constituent volatilities.
    """
    n = len(weights)

    # Variance terms
    index_var = index_vol**2
    weighted_var_sum = np.sum(weights**2 * constituent_vols**2)

    # Cross terms (denominator)
    cross_term = 0
    for i in range(n):
        for j in range(n):
            if i != j:
                cross_term += (
                    weights[i]
                    * weights[j]
                    * constituent_vols[i]
                    * constituent_vols[j]
                )

    # Implied correlation
    if cross_term > 0:
        impl_corr = (index_var - weighted_var_sum) / cross_term
        return np.clip(impl_corr, 0, 1)  # Ensure valid correlation
    return 0.0


# Calculate implied correlation
impl_corr = implied_correlation(index_implied, constituent_implied, weights)
Out[29]:
Console
Index Implied Volatility: 22.0%
Average Constituent Implied Vol: 27.2%
Implied Correlation: 0.57

The implied correlation of 0.25 indicates that the market is pricing in a relatively low level of co-movement between stocks. If you believe actual correlation will be higher, you might sell dispersion (buy index options, sell constituent options).

Variance Swaps

Variance swaps are derivatives that provide pure exposure to realized variance, making them a cleaner instrument for volatility trading than delta-hedged options. Unlike options, which have path-dependent Greeks that require continuous hedging, variance swaps pay off directly based on the total realized variance over their life. This simplicity makes them attractive for you if you want volatility exposure without the operational complexity of dynamic hedging.

Structure and Payoff

A variance swap is a forward contract on realized variance. At maturity, the payoff is:

Payoff=Nvar×(σreal2Kvar)\text{Payoff} = N_{\text{var}} \times (\sigma_{\text{real}}^2 - K_{\text{var}})

where:

  • Payoff\text{Payoff}: payment received at maturity
  • NvarN_{\text{var}}: variance notional (typically quoted as vega notional divided by 2Kvol2K_{\text{vol}})
  • σreal2\sigma_{\text{real}}^2: annualized realized variance over the swap's life
  • KvarK_{\text{var}}: variance strike (typically expressed as volatility: Kvol2=KvarK_{\text{vol}}^2 = K_{\text{var}})

The payoff formula is simple. You receive a payment proportional to the difference between actual realized variance and a predetermined strike level. If the market is more volatile than the strike implies, you profit. If the market is calmer than expected, you pay the seller. Unlike options, there is no optionality here: the trade settles purely based on what happens to variance, with no path dependence in terms of when or how the moves occur.

The realized variance is calculated from daily log returns:

σreal2=252ni=1n(lnSiSi1)2\sigma_{\text{real}}^2 = \frac{252}{n} \sum_{i=1}^{n} \left( \ln \frac{S_i}{S_{i-1}} \right)^2

where:

  • nn: number of observation days
  • SiS_i: price of the asset on day ii
  • Si1S_{i-1}: price of the asset on day i1i-1
  • 252252: annualization factor (assuming trading days)

Note that this formula uses the sum of squared returns directly, not the variance around the mean. This is the standard market convention and ensures the calculation is path-dependent and captures all price movements. The distinction matters: by using squared returns rather than variance around the mean, the calculation captures both the variance and any drift in the returns. This convention means that a market that trends strongly in one direction will register higher "realized variance" than one that fluctuates around a stable level, even if the two have identical standard deviations. This feature makes variance swaps sensitive to all price movements, not just deviations from trend.

In[30]:
Code
def variance_swap_realized(prices):
    """Calculate realized variance for a variance swap."""
    log_returns = np.diff(np.log(prices))
    n = len(log_returns)
    realized_var = (252 / n) * np.sum(log_returns**2)
    return realized_var


def variance_swap_payoff(prices, strike_vol, vega_notional):
    """
    Calculate variance swap payoff.

    Parameters:
    - prices: Array of daily prices
    - strike_vol: Volatility strike (e.g., 0.20 for 20%)
    - vega_notional: Notional amount per 1% move in volatility
    """
    realized_var = variance_swap_realized(prices)
    strike_var = strike_vol**2
    realized_vol = np.sqrt(realized_var)

    # Variance notional = vega_notional / (2 * strike_vol)
    var_notional = vega_notional / (2 * strike_vol)

    payoff = var_notional * (realized_var - strike_var)

    return {
        "realized_vol": realized_vol,
        "strike_vol": strike_vol,
        "realized_var": realized_var,
        "strike_var": strike_var,
        "var_notional": var_notional,
        "payoff": payoff,
    }


# Generate sample price paths
np.random.seed(42)
n_days = 30

# Low volatility regime
returns_low = np.random.normal(0, 0.012, n_days)  # ~19% annualized
prices_low = 100 * np.exp(np.cumsum(returns_low))
prices_low = np.insert(prices_low, 0, 100)

# High volatility regime
returns_high = np.random.normal(0, 0.022, n_days)  # ~35% annualized
prices_high = 100 * np.exp(np.cumsum(returns_high))
prices_high = np.insert(prices_high, 0, 100)

strike_vol = 0.25
vega_notional = 100000  # $100,000 per vol point

result_low = variance_swap_payoff(prices_low, strike_vol, vega_notional)
result_high = variance_swap_payoff(prices_high, strike_vol, vega_notional)
Out[31]:
Console
Variance Swap Payoff Analysis
==================================================
Strike Volatility: 25.0%
Vega Notional: $100,000
Variance Notional: $200,000

Low Volatility Scenario:
  Realized Vol: 17.2%
  Long Variance Swap Payoff: $-6,560

High Volatility Scenario:
  Realized Vol: 32.2%
  Long Variance Swap Payoff: $8,301
Out[32]:
Visualization
Curved line showing variance swap payoff increasing nonlinearly with realized volatility.
The convex payoff profile of a variance swap relative to realized volatility. Because the swap settles on variance (volatility squared), an increase in volatility generates disproportionately larger profits than a decrease of the same magnitude generates losses.

The variance swap generates a positive payoff when realized volatility exceeds the strike volatility. Note that in the high volatility scenario, the payoff is substantial because the realized variance (volatility squared) increases quadratically, making the payout convex with respect to volatility moves. This convexity is a critical feature of variance swaps: a move from 25% to 35% volatility generates more profit than a move from 25% to 15% volatility generates loss, making variance swaps attractive instruments for long volatility positions.

Replication and Pricing

The variance swap strike is determined by a portfolio of options across all strikes. The theoretical result, derived by Demeterfi, Derman, Kamal, and Zou (1999), shows that variance can be replicated by a portfolio of options with weights inversely proportional to the square of the strike:

Kvar=2erTT[0FP(K)K2dK+FC(K)K2dK]K_{\text{var}} = \frac{2e^{rT}}{T} \left[ \int_0^{F} \frac{P(K)}{K^2} dK + \int_{F}^{\infty} \frac{C(K)}{K^2} dK \right]

where:

  • KvarK_{\text{var}}: variance strike
  • rr: risk-free interest rate
  • TT: time to expiration
  • FF: forward price of the underlying asset
  • KK: strike price
  • P(K)P(K): price of a put option with strike KK
  • C(K)C(K): price of a call option with strike KK

Variance exposure can be constructed from a portfolio of vanilla options. The key insight is that options at different strikes contribute differently to variance: lower strike options contribute more (because of the 1/K21/K^2 weighting) than higher strike options. This overweighting of low strikes reflects the fact that the logarithm function used in variance calculation is more sensitive to downward price moves than upward ones.

The formula splits the replication into two parts based on the forward price FF:

  • 0FP(K)K2dK\int_0^{F} \frac{P(K)}{K^2} dK: replicates variance using out-of-the-money puts for strikes below the forward price
  • FC(K)K2dK\int_{F}^{\infty} \frac{C(K)}{K^2} dK: replicates variance using out-of-the-money calls for strikes above the forward price

Using out-of-the-money options at each strike is a convention that minimizes the cost of maintaining the replicating portfolio, as OTM options have lower premiums than their in-the-money counterparts while providing the same exposure to variance.

In practice, this integral is approximated using available option strikes:

In[33]:
Code
def price_variance_swap_strike(strikes, option_prices, is_call, S, r, T):
    """
    Approximate variance swap strike using discrete option prices.

    Uses out-of-the-money options: puts below forward, calls above.
    """
    F = S * np.exp(r * T)  # Forward price

    # Sort strikes
    sorted_idx = np.argsort(strikes)
    strikes = strikes[sorted_idx]
    option_prices = option_prices[sorted_idx]
    is_call = is_call[sorted_idx]

    variance = 0

    for i in range(len(strikes)):
        K = strikes[i]
        price = option_prices[i]

        # Use OTM options only
        if K < F and not is_call[i]:  # OTM put
            # Calculate strike spacing for numerical integration
            if i > 0:
                dK = (strikes[i] - strikes[i - 1]) / 2
            else:
                dK = strikes[1] - strikes[0]
            if i < len(strikes) - 1:
                dK += (strikes[i + 1] - strikes[i]) / 2

            variance += (2 / K**2) * price * dK

        elif K >= F and is_call[i]:  # OTM call
            if i > 0:
                dK = (strikes[i] - strikes[i - 1]) / 2
            else:
                dK = strikes[1] - strikes[0]
            if i < len(strikes) - 1:
                dK += (strikes[i + 1] - strikes[i]) / 2

            variance += (2 / K**2) * price * dK

    # Annualize
    variance = (np.exp(r * T) / T) * variance

    return np.sqrt(variance)


# Example: Price variance swap from option chain
S = 100
r = 0.05
T = 30 / 365
sigma = 0.25

# Generate option chain
strikes = np.arange(85, 116, 2.5)
option_prices = []
is_call = []

for K in strikes:
    if K < S:  # Use put
        price = black_scholes_put(S, K, T, r, sigma)
        option_prices.append(price)
        is_call.append(False)
    else:  # Use call
        price, _, _ = black_scholes_call(S, K, T, r, sigma)
        option_prices.append(price)
        is_call.append(True)

option_prices = np.array(option_prices)
is_call = np.array(is_call)

fair_vol = price_variance_swap_strike(strikes, option_prices, is_call, S, r, T)
Out[34]:
Console
Black-Scholes Implied Vol: 25.0%
Variance Swap Fair Vol: 21.5%

Difference: -3.54% (convexity adjustment)

The variance swap fair strike is typically slightly higher than at-the-money implied volatility due to the convexity in the variance payoff. This convexity adjustment compensates for the asymmetric exposure to volatility: realized variance of 40% versus 20% strike creates more P&L than 20% versus 20%. The convexity adjustment exists because variance is the square of volatility: a symmetrical distribution of volatility outcomes translates into an asymmetrical distribution of variance outcomes, with large volatility outcomes contributing disproportionately to expected variance.

Vega Notional Versus Variance Notional

Variance swaps can be quoted in two ways:

Variance notional (NvarN_{var}): The dollar amount paid per point of variance. A variance notional of $1,000 pays $1,000 for each 0.0001 (1 bp) difference in variance.

Vega notional: The approximate P&L for a 1 percentage point change in volatility. For a vega notional of $100,000, if volatility moves from 25% to 26%, the P&L is approximately $100,000.

The relationship between them is:

Nvar=Nvega2×KvolN_{\text{var}} = \frac{N_{\text{vega}}}{2 \times K_{\text{vol}}}

where:

  • NvarN_{\text{var}}: variance notional
  • NvegaN_{\text{vega}}: vega notional (P&L per 1 vol point change)
  • KvolK_{\text{vol}}: volatility strike

This conversion is approximate because the variance payoff is convex in volatility. The formula comes from taking the derivative of variance with respect to volatility at the strike level: the derivative of σ2\sigma^2 with respect to σ\sigma is 2σ2\sigma, so at the strike volatility KvolK_{vol}, a small change in volatility creates a variance change of approximately 2×Kvol2 \times K_{vol} times the volatility change. The vega notional convention makes it easier for you to think in terms of volatility points, which are more intuitive than variance points.

Key Parameters

The key parameters for variance swaps are:

  • K_vol: Volatility strike. The reference level of volatility; payoff is zero if realized volatility equals this strike.
  • N_vega: Vega notional. The approximate P&L per 1% change in volatility.
  • Realized Variance: The sum of squared daily log returns over the life of the contract, annualized.

Trading the VIX

The CBOE Volatility Index (VIX) provides a benchmark for S&P 500 implied volatility. VIX derivatives, such as futures and options, allow you to take positions on volatility expectations and hedge volatility risk.

VIX Calculation

The VIX is calculated from a portfolio of S&P 500 index options using a methodology similar to variance swap pricing. It represents the 30-day expected volatility implied by option prices:

σ2=2TiΔKiKi2erTQ(Ki)1T(FK01)2\sigma^2 = \frac{2}{T} \sum_i \frac{\Delta K_i}{K_i^2} e^{rT} Q(K_i) - \frac{1}{T} \left( \frac{F}{K_0} - 1 \right)^2

where:

  • σ2\sigma^2: variance used to calculate VIX (VIX=100×σ\text{VIX} = 100 \times \sigma)
  • TT: time to expiration
  • ΔKi\Delta K_i: interval between strike prices
  • KiK_i: strike price of the ii-th option
  • rr: risk-free interest rate
  • Q(Ki)Q(K_i): midpoint of the bid-ask spread for option at strike KiK_i
  • FF: forward index level derived from option prices
  • K0K_0: first strike below the forward price FF

The VIX calculation methodology is directly related to the variance swap replication formula we examined earlier. Both approaches use a portfolio of out-of-the-money options weighted by the inverse square of the strike to capture expected variance. The key difference is that the VIX uses a specific set of S&P 500 options with near-term and next-term expirations, interpolated to provide a constant 30-day horizon.

The formula consists of two main parts:

  • Option Summation: 2TΔKiKi2erTQ(Ki)\frac{2}{T} \sum \frac{\Delta K_i}{K_i^2} e^{rT} Q(K_i) aggregates the prices of out-of-the-money options, weighted by 1/K21/K^2, to replicate the variance payoff.
  • Forward Adjustment: 1T(FK01)2\frac{1}{T} \left( \frac{F}{K_0} - 1 \right)^2 corrects for the discrete difference between the forward price FF and the cutoff strike K0K_0.

The forward adjustment term is necessary because the formula uses a discrete set of option strikes rather than a continuous spectrum. Since the transition between puts and calls occurs at K0K_0 rather than exactly at the forward price FF, this adjustment corrects for the small pricing error that would otherwise result.

VIX Futures Term Structure

VIX futures prices reflect expectations of future VIX levels plus a risk premium. The typical term structure shapes are:

  • Contango: Normal market conditions. Longer-dated futures trade above spot VIX because investors demand premium for bearing volatility risk.
  • Backwardation: Market stress periods. Spot VIX spikes above futures as realized volatility jumps and mean reversion is expected.

The intuition for contango is similar to the volatility risk premium. Investors who are long equity portfolios want protection against volatility spikes, and they are willing to pay a premium for this protection. VIX futures sellers, who bear the risk of volatility spikes, demand compensation in the form of futures prices that are higher than expected future spot VIX levels. This premium manifests as an upward-sloping term structure.

During market stress, the relationship inverts. When volatility spikes, the spot VIX jumps immediately to reflect current fear and hedging demand. However, futures prices rise less because the market expects volatility to eventually mean-revert to more normal levels. This creates backwardation, with spot VIX above futures prices.

In[35]:
Code
# Simulate VIX futures term structure
maturities = np.array([1, 2, 3, 4, 5, 6])  # Months to expiration
spot_vix = 18

# Contango scenario (normal markets)
vix_contango = spot_vix + 2 * np.sqrt(maturities)

# Backwardation scenario (market stress)
spot_vix_stress = 35
vix_backwardation = spot_vix_stress - 3 * np.sqrt(maturities)
vix_backwardation = np.maximum(vix_backwardation, 20)  # Floor
Out[36]:
Visualization
Two curves showing upward sloping contango and downward sloping backwardation term structures.
VIX futures curves for contango and backwardation market regimes. In normal markets, the upward-sloping curve imposes a roll cost on long positions, while the downward-sloping curve during stress periods reflects expectations of mean reversion in volatility.

The term structure typically exhibits contango, where longer-dated futures trade at a premium to spot, reflecting the cost of protection. During market stress, the curve flips to backwardation, with spot prices surging above futures as demand for immediate hedging spikes.

Roll Yield and VIX Products

The persistent contango in VIX futures creates a negative roll yield for long positions. As futures converge to spot at expiration, long positions in contango lose value from roll. This explains why long VIX ETFs like VXX have lost over 99% of their value since inception, despite VIX remaining in a range.

This decay is devastating for long-term holders. Consider a VIX ETF that maintains exposure to the front-month VIX futures contract. When the contract approaches expiration, the ETF must roll its position to the next month's contract. If the curve is in contango, this means selling the expiring contract at a lower price and buying the next month's contract at a higher price. This roll transaction locks in a loss, and if contango persists, these losses accumulate month after month, steadily eroding the ETF's value.

In[37]:
Code
def simulate_vix_etf(
    spot_vix_series, futures_premium_pct=0.05, days_between_rolls=21
):
    """
    Simulate VIX ETF returns including roll cost.

    Parameters:
    - spot_vix_series: Daily spot VIX values
    - futures_premium_pct: Average futures premium over spot (5% = contango)
    - days_between_rolls: Number of days between roll events
    """
    n_days = len(spot_vix_series)
    etf_value = 100  # Start at $100
    etf_values = [etf_value]

    for i in range(1, n_days):
        # Daily return from VIX movement
        vix_return = (
            spot_vix_series[i] - spot_vix_series[i - 1]
        ) / spot_vix_series[i - 1]

        # Daily roll cost (spread over roll period)
        daily_roll_cost = futures_premium_pct / days_between_rolls

        # ETF return = VIX return - roll cost
        etf_return = vix_return - daily_roll_cost
        etf_value *= 1 + etf_return
        etf_values.append(etf_value)

    return np.array(etf_values)


# Simulate 2 years of VIX (mean-reverting process)
np.random.seed(42)
n_days = 504
kappa = 0.1  # Mean reversion speed
theta = 20  # Long-term mean
sigma_vix = 0.8  # VIX volatility

spot_vix = [20]
for _ in range(n_days - 1):
    dW = np.random.normal(0, 1)
    new_vix = (
        spot_vix[-1]
        + kappa * (theta - spot_vix[-1])
        + sigma_vix * np.sqrt(spot_vix[-1]) * dW
    )
    spot_vix.append(max(new_vix, 10))
spot_vix = np.array(spot_vix)

# Simulate ETF tracking VIX with roll cost
etf_values = simulate_vix_etf(spot_vix)

total_return = (etf_values[-1] / etf_values[0] - 1) * 100
annualized_return = (
    (etf_values[-1] / etf_values[0]) ** (252 / n_days) - 1
) * 100
Out[38]:
Visualization
Dual-axis chart showing stable VIX with steadily declining ETF value over two years.
Comparison of spot VIX levels and the value of a long VIX ETF over two years. Despite the spot index remaining within a stable range, the continuous cost of rolling futures in contango leads to a severe erosion of capital for the long ETF position.
Out[39]:
Console
VIX Range: 10.0 - 45.6
VIX Start/End: 20.0 / 17.7

Long VIX ETF Performance:
  Total Return: -73.9%
  Annualized Return: -48.9%

The lesson is clear: long volatility positions using VIX products require precise timing. They are hedging instruments, not investments.

Key Parameters

The key parameters for VIX products are:

  • Spot VIX: The current level of the VIX index, representing 30-day implied volatility.
  • Roll Yield: The cost incurred from rolling futures contracts. Negative in contango, positive in backwardation.
  • Term Structure: The curve of futures prices across maturities. Shape determines the cost of carry.
  • Contango: Market condition where futures prices exceed spot prices, typical for VIX.

Risks of Volatility Trading

Volatility trading risks differ from directional equity or fixed income strategies. Understanding these risks is essential for proper position sizing and risk management.

Short Volatility Risk: The Picking Up Nickels Problem

Short volatility strategies typically produce frequent small gains and occasional large losses. This profile resembles "picking up nickels in front of a steamroller"; the strategy works until it doesn't.

The danger stems from several factors. Volatility is inherently mean-reverting but can spike dramatically and persistently during market stress. Historical examples include the 2008 financial crisis, the 2015 Chinese market turmoil, and the February 2018 "Volmageddon" event when inverse VIX products collapsed overnight. During Volmageddon, the VIX doubled in a single day, causing the XIV ETN (which sold VIX futures) to lose 90% of its value and be liquidated.

In[40]:
Code
def simulate_short_vol_strategy(
    n_months=120, monthly_premium=0.02, spike_prob=0.02, spike_loss=0.30
):
    """
    Simulate returns from a short volatility strategy.

    Parameters:
    - monthly_premium: Average monthly return in calm periods
    - spike_prob: Probability of volatility spike per month
    - spike_loss: Loss magnitude during spike
    """

    portfolio = 100
    portfolio_history = [portfolio]

    for _ in range(n_months):
        if np.random.random() < spike_prob:
            # Volatility spike - large loss
            monthly_return = -spike_loss
        else:
            # Normal month - small gain
            monthly_return = monthly_premium + np.random.normal(0, 0.02)

        portfolio *= 1 + monthly_return
        portfolio_history.append(portfolio)

    return np.array(portfolio_history)


# Simulate multiple paths
n_simulations = 100
all_paths = []
for i in range(n_simulations):
    np.random.seed(42 + i)
    path = simulate_short_vol_strategy()
    all_paths.append(path)
all_paths = np.array(all_paths)

# Calculate statistics
final_values = all_paths[:, -1]
max_drawdowns = []
for path in all_paths:
    running_max = np.maximum.accumulate(path)
    drawdown = (running_max - path) / running_max
    max_drawdowns.append(drawdown.max())
avg_max_drawdown = np.mean(max_drawdowns)
Out[41]:
Visualization
Fan chart showing many strategy paths, some rising steadily while others collapse.
One hundred simulated paths of a short volatility strategy over ten years. While most paths exhibit steady incremental growth, the presence of sudden, sharp drawdowns highlights the significant tail risk and potential for ruin inherent in selling volatility.
Out[42]:
Console
Short Vol Strategy Statistics (10-year simulation, 100 paths):
  Mean Final Value: $502
  Median Final Value: $439
  5th Percentile: $133
  Probability of Ruin (>50% loss): 0.0%
  Average Max Drawdown: 35.4%

The simulation demonstrates the 'tail risk' inherent in short volatility strategies. While the median path is profitable, the presence of ruinous drawdowns and high probabilities of significant loss illustrates why simple historical mean returns can be misleading for risk assessment in volatility markets.

Long Volatility Risk: The Carry Problem

Long volatility strategies face the opposite challenge: they tend to lose money slowly through carry costs but profit during volatility events. The volatility risk premium means implied volatility typically exceeds realized volatility, creating a drag on long vol positions.

The carry cost manifests in several ways:

  • Theta decay: Long options value daily, requiring volatility events to offset
  • Roll yield: Long VIX futures contango lose money as they converge to spot
  • Variance swap negative carry: Buying variance swaps elevated implied levels loses if realized vol is lower

The behavioral challenge for you is maintaining conviction through extended periods of losses while waiting for the volatility event that justifies the strategy.

Out[43]:
Visualization
Monthly return distribution for a short volatility strategy. The histogram reveals a high frequency of positive returns punctuated by a long left tail of significant losses, resulting in high negative skewness.
Monthly return distribution for a short volatility strategy. The histogram reveals a high frequency of positive returns punctuated by a long left tail of significant losses, resulting in high negative skewness.
Monthly return distribution for a long volatility strategy. The distribution shows frequent small losses from time decay and roll costs, balanced by a long right tail of occasional outsized gains during volatility spikes.
Monthly return distribution for a long volatility strategy. The distribution shows frequent small losses from time decay and roll costs, balanced by a long right tail of occasional outsized gains during volatility spikes.

Position Sizing and Leverage

Position sizing is critical because of these asymmetric risk profiles:

For short volatility: You should size positions to survive 3-4 standard deviation moves. The February 2018 VIX spike was approximately a 7-sigma event under normal assumptions, highlighting the inadequacy of normal distribution assumptions. For long volatility: You should size positions to survive extended carry costs. A long vol strategy might need to withstand 12-24 months of bleeding before a payoff event occurs.

A useful framework is for you to define the maximum acceptable drawdown and work backward to position size:

In[44]:
Code
def calculate_position_size(
    max_drawdown, expected_loss_in_spike, confidence_level=0.99
):
    """
    Calculate appropriate position size for volatility strategies.

    Parameters:
    - max_drawdown: Maximum acceptable portfolio loss (e.g., 0.20 for 20%)
    - expected_loss_in_spike: Expected loss on position in vol spike (e.g., 0.50 for 50%)
    - confidence_level: Probability of not exceeding max_drawdown
    """
    # Position size = max_drawdown / expected_loss
    position_size = max_drawdown / expected_loss_in_spike

    return min(position_size, 1.0)  # Cap at 100%


# Example for short vol strategy
max_acceptable_dd = 0.15  # 15% max drawdown
expected_spike_loss = 0.40  # 40% loss on position in spike

recommended_size = calculate_position_size(
    max_acceptable_dd, expected_spike_loss
)
Out[45]:
Console
Position Sizing for Short Volatility Strategy:
  Maximum Acceptable Drawdown: 15%
  Expected Position Loss in Vol Spike: 40%
  Recommended Position Size: 37% of portfolio

This position size ensures that a 40% loss in a volatility spike does not exceed the 15% drawdown limit. This inverse sizing approach is crucial for survival in fat-tailed markets.

Correlation with Market Stress

Volatility positions have distinct correlation properties that affect portfolio construction:

  • Short volatility is implicitly long equities. When markets crash, volatility spikes, and short vol positions lose money at the worst time.
  • Long volatility provides crisis alpha: profits during market stress that can offset equity losses.

This correlation structure means that short volatility strategies provide false diversification. They may show low correlation to equities during calm periods but become highly correlated during crises when diversification is most needed.

Practical Implementation Considerations

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about volatility trading and arbitrage strategies.

Loading component...

Reference

BIBTEXAcademic
@misc{volatilitytradingstrategiesdeltahedgingvixarbitrage, author = {Michael Brenndoerfer}, title = {Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage}, year = {2025}, url = {https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps}, organization = {mbrenndoerfer.com}, note = {Accessed: 2025-01-01} }
APAAcademic
Michael Brenndoerfer (2025). Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage. Retrieved from https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps
MLAAcademic
Michael Brenndoerfer. "Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage." 2026. Web. today. <https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps>.
CHICAGOAcademic
Michael Brenndoerfer. "Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage." Accessed today. https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps.
HARVARDAcademic
Michael Brenndoerfer (2025) 'Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage'. Available at: https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps (Accessed: today).
SimpleBasic
Michael Brenndoerfer (2025). Volatility Trading Strategies: Delta Hedging, VIX & Arbitrage. https://mbrenndoerfer.com/writing/volatility-trading-arbitrage-strategies-delta-hedging-variance-swaps