Volatility trading
Once you can price an option you can trade the one input that is not observable: volatility. A vol trader is not betting on direction — they are betting that the volatility implied by option prices is wrong relative to what the underlying will actually realize. This chapter defines both, explains the persistent gap between them (the variance risk premium), shows why the vol smile proves Black-Scholes is a convenient lie, and then walks through the mechanics — straddles, and the gamma-versus-theta P&L of a delta-hedged position — together with the tail risk that makes short vol so dangerous.
Realized vs implied volatility#
Realized volatility is backward-looking: the annualised standard deviation of the returns the underlying actually printed. From log returns over a window of bars with bars per year:
Implied volatility is forward-looking: the single you back out of a traded option price with ek.options.implied_vol(previous chapter). It is the market's consensus forecast of volatility over the option's life. In edgekit the realized side comes from ek.timeseries:
import numpy as np
import edgekit as ek
logret = np.diff(np.log(close))
# rolling per-bar std, annualised by sqrt(periods_per_year)
rv = ek.timeseries.rolling_volatility(logret, window=20, periods_per_year=252)
# EWMA (RiskMetrics): weights recent shocks more, reacts to regime change
ew = ek.timeseries.ewma_volatility(logret, lam=0.94) * np.sqrt(252)
# realized_vol is the HF estimator: sqrt of the rolling *sum* of squared returns
rvol = ek.timeseries.realized_vol(logret, window=20)rolling_volatility is the textbook rolling std (a per-bar average). realized_vol is the high-frequency total-variation estimator — the sum of squared returns, larger by roughly , measuring how far the series actually travelled. ewma_volatility replaces the hard lookback window with exponential decay so a new shock is felt immediately. Pick by purpose; do not mix their scales in one comparison.The variance risk premium#
Compare the two series and a robust empirical fact appears: implied volatility is, on average, higher than the volatility that subsequently realizes. The average gap is the variance risk premium (VRP):
Why does it persist? Options are insurance. Most participants are natural buyers of protection (long puts, long vol), and the sellers who warehouse that risk demand compensation for taking on rare, violent losses. So implied vol embeds a risk premium above the statistical forecast — the same reason insurance premiums exceed expected claims. Selling vol harvests this premium most of the time, which is exactly what makes it dangerous: the payoff is a long stream of small gains punctuated by rare catastrophic losses.
The vol smile and skew#
Black-Scholes assumes one constant for all strikes. If that were true, inverting every option on the same underlying and expiry would yield the same implied vol. It does not. Plot implied vol against strike and you get a smile (or, in equity and index markets, a downward skew): out-of-the-money options — especially downside puts — trade at higher implied vol than at-the-money.

The smile is the market correcting Black-Scholes' two false assumptions: returns are not Gaussian (they have fat tails, so far-OTM options are worth more than a normal distribution implies), and volatility is notconstant (it clusters and spikes precisely when prices fall). The downside skew in equities encodes crash-o-phobia: demand for put protection bids up implied vol on the left wing. Practically, the smile means there is no single “the” volatility — you must speak of the implied vol at a given strike, and any model with one will misprice the wings.
import numpy as np
import edgekit as ek
S, t, r = 100.0, 0.25, 0.04
strikes = np.array([80, 90, 100, 110, 120], float)
# Suppose these are observed market prices for calls at each strike.
# Inverting each with implied_vol recovers a *different* sigma per strike:
market_px = np.array([...]) # traded prices
ivs = [ek.options.implied_vol(px, S, K, t, r, kind="call")
for px, K in zip(market_px, strikes)]
# a flat 'ivs' would confirm BS; a U-shape is the smile.Trading volatility with structures#
To bet on the magnitude of a move while staying (initially) direction-neutral, combine options so the deltas cancel and the vega adds.
Straddle and strangle#
A long straddle is a long call plus a long put at the same at-the-money strike. Its deltas roughly offset ( at the money), leaving a position that is long gamma and long vega: it profits from a large move in either direction, or from implied vol rising, and it pays for that convexity through theta. A strangle uses OTM strikes instead — cheaper premium, but the underlying must travel further before it pays.
import edgekit as ek
S = K = 100.0; t, r, sig = 0.25, 0.04, 0.25
call = ek.options.bs_price(S, K, t, r, sig, kind="call")
put = ek.options.bs_price(S, K, t, r, sig, kind="put")
premium = call + put # cost of the straddle
gc = ek.options.bs_greeks(S, K, t, r, sig, kind="call")
gp = ek.options.bs_greeks(S, K, t, r, sig, kind="put")
net_delta = gc["delta"] + gp["delta"] # ~ 0 at the money
net_vega = gc["vega"] + gp["vega"] # additive, long vol
print(round(premium, 3), round(net_delta, 4), round(net_vega / 100, 3))Delta-hedging: gamma vs theta#
Buying a straddle leaves you exposed to direction if the underlying drifts. To isolate a pure vol bet, continuously delta-hedge: hold units of the underlying and rebalance as spot moves. A delta-hedged long option has no first-order spot exposure, so its P&L over a small step in time is the second-order Taylor expansion:
This is the central identity of vol trading. The first term is positive (long gamma: and ) — you make money from movement regardless of sign, because each rebalance buys low and sells high around the hedge. The second term is negative (theta decay: ) — you bleed time value every day. The net is a race:
Rewritten this way it is transparent: a delta-hedged long option makes money exactly when realized volatility exceeds the implied vol you paid, and loses when it does not. You bought vol at ; the market delivers ; the difference, scaled by your gamma exposure, is the P&L. The short-vol seller sits on the other side of this equation — collecting theta, praying gamma losses stay small.
• A 4% day (): gamma earns , theta costs $0.08, net +$0.40. Movement won.
• A quiet 0.8% day (): gamma earns only , theta still costs $0.08, net −$0.06. Time won. Sum a month of days: you profit if and only if Zenith realizes more than the 25% you paid. The hedge turned a directional lottery ticket into a clean bet on realized-vs-implied.
The short-vol tail#
The reason short vol is treated with such caution is the shape of its return distribution: many small positive days (theta collected) and a fat, sudden left tail (gamma losses in a crash, compounded by implied vol spiking against your short vega at the worst moment). It is negatively skewed and leptokurtic — the mirror image of the right-skewed trend-following payoff. Standard risk metrics flatter it: a short-vol book can post a gorgeous Sharpe for years and then surrender it all in a week, because Sharpe cannot see a tail it has not sampled yet.
This is not a reason to avoid vol — it is a reason to size it against the tail, not the average. The lessons from position sizing and Monte Carlo apply with full force: bootstrap the worst case, never let a single event exceed your ruin threshold, and report MAR and the loss distribution alongside any headline return.
Next: Market microstructure — the limit order book, the anatomy of the bid-ask spread, and where trading costs are actually born.
