Solution: Delta Hedging P&L Simulation
Exercise: Delta Hedging P&L Simulation
Simulation
import numpy as np
from scipy.stats import norm
def bs_call(S, K, T, r, sigma):
if T <= 0:
return np.maximum(S - K, 0)
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
def delta_call(S, K, T, r, sigma):
if T <= 0:
return 1.0 * (S > K)
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
return norm.cdf(d1)
def simulate_hedge_pnl(M, N, S0, K, T, r, sigma, seed=0):
rng = np.random.default_rng(seed)
dt = T / N
times = np.linspace(0, T, N + 1)
# Simulate GBM paths
Z = rng.standard_normal((M, N))
log_ret = (r - 0.5*sigma**2)*dt + sigma*np.sqrt(dt)*Z
log_paths = np.hstack([np.zeros((M, 1)), np.cumsum(log_ret, axis=1)])
S_paths = S0 * np.exp(log_paths) # shape (M, N+1)
# Initial option price and delta
C0 = bs_call(S0, K, T, r, sigma)
Delta0 = delta_call(S0, K, T, r, sigma)
# At t=0: sell 1 call, buy Delta0 stock, cash = C0 - Delta0*S0
cash = C0 - Delta0*S0 * np.ones(M)
shares = Delta0 * np.ones(M)
for i in range(1, N + 1):
tau = T - times[i]
S_t = S_paths[:, i]
# Accrue interest on cash from t_{i-1} to t_i
cash *= np.exp(r*dt)
# Update delta at new time
new_delta = delta_call(S_t, K, tau, r, sigma)
# Rebalance: buy/sell (new_delta - shares) at S_t
cash -= (new_delta - shares) * S_t
shares = new_delta
# Close the option payoff
S_T = S_paths[:, -1]
payoff = np.maximum(S_T - K, 0)
pnl = cash + shares*S_T - payoff
return pnl
# Part 2
S0, K, T, r, sigma = 100, 100, 0.5, 0.05, 0.2
for N in [10, 50, 250]:
pnl = simulate_hedge_pnl(10_000, N, S0, K, T, r, sigma)
print(f"N={N}: mean={pnl.mean():.4f}, std={pnl.std():.4f}")
# N=10: mean=-0.0133, std=1.2893
# N=50: mean=-0.0027, std=0.5752
# N=250: mean=-0.0006, std=0.2566Part 3 — Convergence
Theoretical scaling: .
Checking ratios: , should be . ✓ , should be . ✓
Part 4 — Residual P&L source: gamma
At each rebalancing, the first-order hedge catches but misses . Over steps, the accumulated gamma-P&L has:
- Expected value under (this is what makes Black-Scholes work).
- Standard deviation (the fluctuations scale as , and there are of them).
In continuous hedging (), and hedging is perfect. Real-world discreteness (hedging hourly or daily, not continuously) leaves the hedger exposed to gamma risk — the second-order curvature.
Takeaways
- Delta-hedged options have approximately zero expected P&L under Black-Scholes. The mean P&L for all — the option's premium is "paid" by expected hedging costs.
- Residual P&L has standard deviation . The gamma risk shrinks as you rebalance more frequently; finer discretisation closer to perfect replication.
- Transaction costs break this. Real-world hedging has bid-ask spread and commissions; rebalancing more frequently quickly becomes expensive. The optimum balances gamma risk vs. transaction cost — a well-known "hedging bandwidth" problem.
- Discrete-time delta hedging is the bridge between theory and practice. Black-Scholes is a continuous-time idealisation; this exercise demonstrates that the idealised zero-variance replication is a limit attained only in the continuum.