Solution: Vega-Neutral Portfolio Construction
Exercise: Vega-Neutral Portfolio Construction
Part 1 — Individual Greeks
import numpy as np
from scipy.stats import norm
def bs_greeks(S, K, T, r, sigma, q=0):
d1 = (np.log(S/K) + (r - q + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
C = S*np.exp(-q*T)*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
delta = np.exp(-q*T)*norm.cdf(d1)
gamma = np.exp(-q*T)*norm.pdf(d1) / (S*sigma*np.sqrt(T))
vega = S*np.exp(-q*T)*norm.pdf(d1)*np.sqrt(T)
return C, delta, gamma, vega
S, r, sigma = 100, 0.05, 0.2
C1, D1, G1, V1 = bs_greeks(S, 100, 0.25, r, sigma)
C2, D2, G2, V2 = bs_greeks(S, 100, 1.0, r, sigma)
print(f"C1 (3M ATM): C={C1:.3f}, delta={D1:.4f}, gamma={G1:.4f}, vega={V1:.3f}")
print(f"C2 (12M ATM): C={C2:.3f}, delta={D2:.4f}, gamma={G2:.4f}, vega={V2:.3f}")
# C1 (3M ATM): C=4.615, delta=0.5596, gamma=0.0389, vega=19.426
# C2 (12M ATM): C=10.451, delta=0.6368, gamma=0.0188, vega=37.524Part 2 — Build portfolio
Fix . Vega neutrality:
Delta neutrality:
alpha = 1
beta = -V1 / V2
gamma_stock = -(alpha*D1 + beta*D2)
print(f"alpha={alpha}, beta={beta:.4f}, stock shares={gamma_stock:.4f}")
# alpha=1.0000, beta=-0.5177, stock shares=-0.2299Interpretation: Long 1 unit of 3-month ATM call, short 0.518 units of 12-month ATM call, short 0.230 shares of stock.
This is a calendar spread (long short-dated, short long-dated) with a delta hedge.
Part 3 — Portfolio gamma
Positive gamma — the portfolio is long gamma (long convexity). The calendar spread gains when the stock moves in either direction; it's a bet on "realized vol exceeds implied" on the short-dated tenor.
gamma_P = alpha*G1 + beta*G2
print(f"Portfolio gamma: {gamma_P:.4f}")
# Portfolio gamma: 0.0292Part 4 — Parallel vol shift scenario
If both vols rise to 0.21:
C1_up, _, _, _ = bs_greeks(S, 100, 0.25, r, 0.21)
C2_up, _, _, _ = bs_greeks(S, 100, 1.0, r, 0.21)
pnl = alpha*(C1_up - C1) + beta*(C2_up - C2)
print(f"Parallel 1% IV shift P&L: {pnl:.4f}")
# Parallel 1% IV shift P&L: 0.0008 (≈ 0, vega-neutral as designed)Verifying vega-neutrality empirically: P&L (second-order vomma residual).
Part 5 — Term-structure twist
Only 3-month vol rises to 0.21:
C1_up, _, _, _ = bs_greeks(S, 100, 0.25, r, 0.21)
# C2 unchanged
pnl_twist = alpha*(C1_up - C1) + beta*(C2_up_unchanged - C2) # C2 unchanged
pnl_twist = alpha*(C1_up - C1) # since C2 didn't move
print(f"Short-end-only 1% IV shift P&L: {pnl_twist:.4f}")
# Short-end-only 1% IV shift P&L: +0.1944 (≈ +$0.19)The portfolio gains $0.19 because it's long 3-month vega ($19.43) and short 12-month vega (-0.518 × $37.52 = -$19.43). A unilateral rise in short-dated IV (which is what the position is net long of after netting) creates a positive P&L. Equivalently: the portfolio is long the short-end of the vol term structure.
Takeaways
- Delta and vega neutrality can be imposed simultaneously with two option instruments of different maturities (or strikes), plus the stock to zero the delta. This gives a pure gamma / pure term-structure bet.
- The resulting calendar spread is a classic structured-vol position: long gamma, flat vega to parallel shifts, exposed to vol term structure.
- Vega-neutrality is a local concept. It holds at one point on the vol surface. A twist of the surface (skew steepening, term-structure flattening) produces P&L even with zero net parallel-vega.
- Real-world vol trading books decompose vega into buckets: each strike × maturity gets its own P&L attribution. A "vega-neutral" position in this richer sense requires many more instruments to hedge.