σμ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.11·~45 minIntermediate

Vega

Skill positionModule 4 of 11 · Topic 11 of 16
4.11 Vega
—Lab score— / 100Total XP—Streak—

The input nobody can observe

In the Black–Scholes formula the spot, the strike, the rate and the time are known. The volatility is not: it is the market's expectation of future movement, and it changes every day. An option's price therefore depends heavily on a number that has to be guessed, and the sensitivity to it, vega, dC/dsigma, is often the largest risk of an options book. In Black–Scholes it is S * pdf(d1) * sqrt(T), the same for calls and puts, and positive: more volatility always makes an option more valuable.

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 vega(spot, strike, rate, sigma, t):
    return spot * norm_pdf(d1(spot, strike, rate, sigma, t)) * math.sqrt(t)

print(round(vega(100, 100, 0.05, 0.2, 1), 4))             # 37.524   per change of 1.00 in sigma (100 volatility points)
print(round(vega(100, 100, 0.05, 0.2, 1) / 100, 4))       # 0.3752   per volatility point: sigma from 20% to 21%

Where vega is largest

Vega is highest for at-the-money options, where the outcome is most uncertain and extra volatility changes the most, and it fades for options deep in or out of the money (strike 80: 23.8, strike 100: 37.5, strike 120: 21.6). Unlike gamma, vega grows with time to expiry: 19.6 for three months, 37.5 for a year, 62.5 for four years, because a longer life gives volatility more time to matter. Long-dated options are therefore the most exposed to changes in volatility, while short-dated options are the most exposed to gamma.

for strike in (80, 100, 120):
    print("strike", strike, round(vega(100, strike, 0.05, 0.2, 1), 3))
# strike 80 23.806
# strike 100 37.524
# strike 120 21.601
for t in (0.25, 1, 4):
    print("t", t, round(vega(100, 100, 0.05, 0.2, t), 3))
# t 0.25 19.644
# t 1 37.524
# t 4 62.451       vega grows with time to expiry

Measuring it, and using it

Volatility is quoted in percentage points, so risk desks quote vega per point: vega / 100, the price change when volatility moves from 20% to 21%. A 10-point jump in volatility, as in a market scare, moves the at-the-money option by about 0.375 * 10 = 3.75, almost 36% of its price. As with delta and gamma, you can measure vega for any model by bumping: price with sigma + h and sigma - h and take the central difference. The linear estimate is slightly off for big moves, because the price is also curved in volatility.

def bs_call(spot, strike, rate, sigma, t):
    d_1 = d1(spot, strike, rate, sigma, t)
    return spot * 0.5 * (1 + math.erf(d_1 / math.sqrt(2))) - strike * math.exp(-rate * t) * 0.5 * (1 + math.erf((d_1 - sigma * math.sqrt(t)) / math.sqrt(2)))

def numerical_vega(price_function, sigma, bump):
    return (price_function(sigma + bump) - price_function(sigma - bump)) / (2 * bump)

price = lambda s: bs_call(100, 100, 0.05, s, 1)
print(round(numerical_vega(price, 0.2, 1e-4), 4))                # 37.524   the same as the formula

per_point = vega(100, 100, 0.05, 0.2, 1) / 100
print(round(per_point * 10, 3), round(price(0.30) - price(0.20), 3))    # 3.752 3.781   linear estimate vs exact, for +10 points
# Vega of a put equals vega of a call: build the put price from parity and bump the volatility
put_price = lambda s: bs_call(100, 100, 0.05, s, 1) - 100 + 100 * math.exp(-0.05)
print(round(numerical_vega(put_price, 0.2, 1e-4), 4))       # 37.524   the same number as for the call
Vega is why we quote implied volatilityBecause volatility is the one unobserved input and the price is so sensitive to it, traders run the formula backwards: from the market price of an option they solve for the volatility that reproduces it. That number, the implied volatility, is how options are quoted and compared across strikes and dates, and vega tells how far a price error translates into a volatility error: the next topics build exactly this.
  • Vega = S * pdf(d1) * sqrt(T): positive, the same for calls and puts, largest at the money and growing with time to expiry.
  • Quote it per volatility point (vega / 100); numerically, (f(sigma + h) - f(sigma - h)) / (2h) works for any model.
  • Price change ~ vega_per_point * points: a volatility jump matters as much as a stock move; implied volatility is the market's quote.

Next up: theta and rho, the sensitivities to time and to interest rates.

Lab · what's graded

  • Measure the sensitivity to volatility with vega25 pts
  • Quote vega per volatility point with vega_per_point25 pts
  • Bump the volatility with numerical_vega25 pts
  • Forecast the effect of a volatility move with price_change_from_vol25 pts
Explorer · lab-76-1
▾ lab-76-1
…
bash · in-browser
learner@quantcraft:~/lab-76-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-76-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