CONTENTS

Solution: 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.524

Part 2 — Build portfolio

Fix α=1\alpha = 1. Vega neutrality:

19.426+β37.524=0    β=0.5177.19.426 + \beta\cdot 37.524 = 0 \implies \beta = -0.5177.

Delta neutrality:

0.5596+β0.6368+γ=0    γ=0.5596(0.5177)(0.6368)=0.5596+0.3297=0.2299.0.5596 + \beta\cdot 0.6368 + \gamma = 0 \implies \gamma = -0.5596 - (-0.5177)(0.6368) = -0.5596 + 0.3297 = -0.2299.
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.2299
Interpretation: 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

ΓP=10.0389+(0.5177)0.0188=0.03890.00975=0.0292.\Gamma_P = 1\cdot 0.0389 + (-0.5177)\cdot 0.0188 = 0.0389 - 0.00975 = 0.0292.
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.0292

Part 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 0\approx 0 (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.
Solution — Vega-Neutral Portfolio Construction | q4quant.studio