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 expiryMeasuring 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 =
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