σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1.2k Learners
LoginJoin ↗
Skills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python skill›Module 4 · Fixed income & options pricing›Topic 4.10·~45 minIntermediate

Gamma

Skill positionModule 4 of 11 · Topic 10 of 16
4.10 Gamma
—Lab score— / 100Total XP—Streak—

Delta is not constant

A delta hedge is exact only for an instant. As soon as the stock moves, the option's delta changes and the hedge is wrong. Gamma is the rate of change of delta with the stock: gamma = d(delta)/dS, the second derivative of the price. A long call or put has positive gamma. In Black–Scholes it is pdf(d1) / (S * sigma * sqrt(T)), the same for calls and puts, where pdf is the bell-curve density. A large gamma means the hedge goes stale quickly and must be adjusted often.

import math

def norm_pdf(x):
    return math.exp(-0.5 * x * x) / math.sqrt(2 * math.pi)

def d1(spot, strike, rate, sigma, t):
    return (math.log(spot / strike) + (rate + 0.5 * sigma ** 2) * t) / (sigma * math.sqrt(t))

def gamma(spot, strike, rate, sigma, t):
    return norm_pdf(d1(spot, strike, rate, sigma, t)) / (spot * sigma * math.sqrt(t))

for spot in (80, 90, 100, 110, 120):
    print(spot, round(gamma(spot, 100, 0.05, 0.2, 1), 5))
# 80 0.0186
# 90 0.02182
# 100 0.01876
# 110 0.01289
# 120 0.0075      gamma peaks near the strike and fades far from it

Gamma grows as expiry nears

For an at-the-money option gamma rises sharply as expiry approaches: 0.019 with a year to go, 0.039 with three months, 0.141 with a week. Near expiry the option is nearly a coin toss between worthless and worth the full move, so delta swings from 0 to 1 over a tiny price range. This is why traders who are short options near expiry (short gamma) sleep badly: the hedge needs constant adjusting and a jump hurts. You can also estimate gamma for any model by the second difference (f(S + h) - 2 f(S) + f(S - h)) / h², exact for a parabola.

for t in (1, 0.25, 0.02):
    print(t, round(gamma(100, 100, 0.05, 0.2, t), 5))
# 1 0.01876
# 0.25 0.03929
# 0.02 0.14087      a week before expiry the at-the-money gamma is 7 times larger

def numerical_gamma(price_function, spot, bump):
    return (price_function(spot + bump) - 2 * price_function(spot) + price_function(spot - bump)) / bump ** 2

price = lambda s: bs_call(s, 100, 0.05, 0.2, 1)               # bs_call as in the previous topic
print(round(numerical_gamma(price, 100, 0.5), 5))             # 0.01876   the same as the formula

What gamma earns

Because delta changes with the stock, a long option gains more than delta alone predicts, whichever way the stock moves. A $5 rise lifts delta from 0.637 to 0.637 + 0.01876 * 5 = 0.731. The profit of a move is delta * move + 0.5 * gamma * move²: the second term is the gamma profit for a long option (a loss for a short one). It grows with the square of the move, so large moves, either way, favour the long-gamma side. That profit is not free: the holder pays for it through the option's premium and its time decay.

g = gamma(100, 100, 0.05, 0.2, 1)
delta = call_delta(100, 100, 0.05, 0.2, 1)                     # as in the delta topic
print(round(delta, 4), round(delta + g * 5, 4))                 # 0.6368 0.7306   the delta after a $5 rise
print(round(call_delta(105, 100, 0.05, 0.2, 1), 4))             # 0.7237          the exact delta at 105 (gamma is a first-order guide)

move = 5
true_gain = bs_call(105, 100, 0.05, 0.2, 1) - bs_call(100, 100, 0.05, 0.2, 1)
print(round(true_gain - delta * move, 4), round(0.5 * g * move ** 2, 4))   # 0.2232 0.2345   what delta missed, and what gamma explains
# Dollar gamma: how many dollars of stock the delta hedge changes for a 1% move of the stock at 100
print(round(g * 100 ** 2 / 100, 3))      # 1.876
Long gamma is not freeGamma profit has a price: the option's time decay (theta). An option held while the stock goes nowhere loses value every day. Whether being long gamma pays depends on whether the stock actually moves as much as the volatility used to price the option; the balance between gamma and theta is the trade-off at the heart of option trading.
  • Gamma = pdf(d1) / (S * sigma * sqrt(T)), the second derivative of the price; the same for calls and puts, largest near the strike and near expiry.
  • Numerical gamma (f(S + h) - 2 f(S) + f(S - h)) / h²; delta after a move delta + gamma * move.
  • A move pays delta * move + 0.5 * gamma * move²: a long option gains from big moves either way, and pays for it in time decay.

Next up: vega, the sensitivity to volatility, the input nobody can observe directly.

Lab · what's graded

  • Measure how fast delta changes with gamma25 pts
  • Measure the curvature of any price with numerical_gamma25 pts
  • Update the delta after a move with delta_after_move25 pts
  • Price the benefit of curvature with gamma_pnl25 pts
Explorer · lab-75-1
▾ lab-75-1
…
bash · in-browser
learner@quantcraft:~/lab-75-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-75-1 goes back to the starter files and the terminal is cleared. Your current solution will be lost — this can't be undone.

Will be reset
  • main.py → starter code
  • Terminal history and test output
  • Unsubmitted changes
Will be kept
  • Best lab score
  • Your XP and streak
  • Lecture progress and notes

Log in to run your code.

Every lecture is free to read. Create an account or log in to run code, run tests and submit this lab.

  • In-browser IDE with a bash terminal — nothing to install
  • Instant grading, XP and your place on the skill
Create an accountLog in
OR
Continue with GitHub