Solution: Computing Delta for a Vanilla Call and Put
Computations
import numpy as np
from scipy.stats import norm
def bs_call(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)
return S*np.exp(-q*T)*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
def delta_call(S, K, T, r, sigma, q=0):
d1 = (np.log(S/K) + (r - q + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
return np.exp(-q*T) * norm.cdf(d1)
def delta_put(S, K, T, r, sigma, q=0):
return delta_call(S, K, T, r, sigma, q) - np.exp(-q*T)
S, K, T, r, q = 100, 100, 0.5, 0.05, 0
# Part 1
for sigma in [0.1, 0.2, 0.4]:
dc = delta_call(S, K, T, r, sigma)
dp = delta_put(S, K, T, r, sigma)
print(f"sigma={sigma}: delta_call={dc:.4f}, delta_put={dp:.4f}")
# sigma=0.1: delta_call=0.6617, delta_put=-0.3383
# sigma=0.2: delta_call=0.5977, delta_put=-0.4023
# sigma=0.4: delta_call=0.5495, delta_put=-0.4505
# Part 2
sigma = 0.2
for S in [80, 100, 120]:
dc = delta_call(S, K, T, r, sigma)
print(f"S={S}: delta_call={dc:.4f}")
# S=80: delta_call=0.1126 (deep OTM)
# S=100: delta_call=0.5977 (ATM)
# S=120: delta_call=0.9390 (deep ITM)
# Part 3: parity check
for sigma in [0.1, 0.2, 0.4]:
diff = delta_call(100, K, T, r, sigma) - delta_put(100, K, T, r, sigma)
print(f"sigma={sigma}: call_delta - put_delta = {diff:.6f}")
# all = 1.000000
# Part 4: FD check
sigma = 0.2
S = 100
h = 0.01
fd = (bs_call(S+h, K, T, r, sigma) - bs_call(S-h, K, T, r, sigma)) / (2*h)
print(f"closed-form delta: {delta_call(S, K, T, r, sigma):.6f}")
print(f"FD delta: {fd:.6f}")
# closed-form delta: 0.597682
# FD delta: 0.597682
Interpretation
- Delta increases as option moves ITM. At S=80 (OTM), Δ=0.11 — far from stock-like. At S=120 (ITM), Δ=0.94 — almost like holding stock.
- Delta is less sensitive to σ for ATM options. At S=K with varying vol, delta stays near 0.5-0.66, decreasing slightly as vol rises (ATM delta →0.5 asymptotically as σ→∞).
- Put-call parity forces Δc−Δp=1 (for q=0). This is exact, independent of σ or S.
- Finite-difference agrees to 6 decimal places — closed-form and numerical differentiation both converge to the same answer.
Takeaways
- Delta is a moneyness gauge. It's a monotone map from spot to [0,1] (for calls). Traders internalise "25-delta put" as "roughly 25% probability of exercise" — a useful shorthand even if not exact.
- Volatility flattens delta. Higher σ pushes deep-OTM deltas up and deep-ITM deltas down (options become less certain to exercise). ATM delta drifts toward 0.5.
- Parity is robust. It holds exactly regardless of volatility or model — as long as no-arbitrage holds.
- Closed-form vs. numerical. Finite differences are numerically equivalent to analytical deltas, and are the workhorse when working with models that lack closed-form Greeks (e.g. Heston, SABR).