One value, several inputs
Take the call of case studies 2.4.6, 2.7.4 and 2.8.4: strike , expiry years from today, interest rate . Today the stock price is and the volatility , and the call is worth $6.3710.
The strike and the expiry date are fixed by the contract. The stock price, the volatility and the date move.
Measure the date in years from today, so is the time left. Then the value is a function of three variables, :
This is case study 2.4.6's formula with in place of . is the standard normal distribution function and , below, its density (lesson 2.6.3). The rate can move too, so it is a fourth input.
A Greek is the sensitivity of the value to one input with the others held fixed. That is exactly a partial derivative, so each Greek is the slope of one slice of (lesson 4.1.1).
Rule: The Greeks as partial derivatives
Delta and gamma hold , and fixed and move ; vega moves only , theta only the date, rho only the rate. Each is a one-variable derivative of a slice.
Delta and gamma came from case study 2.7.4, and vega from case study 2.4.6. Theta and rho are new:
| Greek | closed form | value | as desks quote it |
|---|---|---|---|
| 0.570158 | per $1 of stock | ||
| 0.027772 | change in delta per $1 | ||
| vega | 27.7721 | 0.2777 per vol point | |
| see below | per day | ||
| rho | 25.3224 | 0.2532 per point of rate |
The signs say how a long call responds. It gains when the stock rises (), when volatility rises (vega ) and when rates rise (rho ). It loses value as time passes ().
Try it
greeks returns the value and the five partial derivatives at a point , from the closed forms. The second line converts three of them to desk units: per vol point, per day and per point of rate.
Slices and level curves of the value
Hold and fixed, and is a function of two variables, and . It has a surface and a contour map, like the functions of lesson 4.1.1.
Slices. Fix and let move: that is case study 2.7.4's curve, and delta is its slope. At the slices for 10%, 20% and 30% volatility give 3.6065, 6.3710 and 9.1494. The steps of 10 vol points add 2.7645 and 2.7784, close to vega's .
Level curves. The value rises with and with . So along a level curve, a lower stock price must come with a higher volatility. The curve through today's point passes and .
The call's value as slices, one for each volatility, and as a contour map. Along the bold level curve the value stays at $6.37: a lower stock price needs a higher volatility, and above $104.88 no volatility is low enough.
Each point on that curve is an implied volatility, as in case study 2.4.6. If the stock were at $95 and the call still traded at $6.37, the market would be pricing 29.38% volatility.
To the right the curve ends. It meets at .
Case study 2.4.6 showed that the value never falls below , its value with no uncertainty. With the stock at $105 that floor is 6.4888, so no volatility gives $6.37.
Try it
The first line prints the three slices at and the steps between them. brentq (lesson 1.3.2) then finds the volatility that keeps the value at $6.3710 with the stock at $95 and at $90.
The last line gives where the level curve meets , then the call's value on a $105 stock at 0.01% volatility.
Theta: the passage of time
Hold and fixed and let the date move on. The time left shrinks, and the value changes at the rate . For a call it has two parts:
The first part comes from volatility: less time left means less chance of the large move the option pays for. The second is about the strike, paid at expiry. As expiry comes closer, its present value grows, and that lowers the call's value.
With both parts are negative, so a call's theta is negative. The first part is also , since . An option with a lot of gamma pays for it with a lot of theta.
Per day
is per year, an awkward unit for something that happens daily. Desks divide by 365 for a calendar day, , or by 252 for a trading day, . So with nothing else moving, the call loses about 2 cents a day.
Repricing agrees. Moving the date one day forward changes the value by , against . The small gap is the forward difference's error (lesson 2.8.1): theta itself changes over the day.
Close to expiry
At the money, theta grows as expiry nears, like gamma in case study 2.7.4. Here it is per day, with and fixed:
| time left | 6 months | 1 month | 1 week | 1 day |
|---|---|---|---|---|
| value | 6.3710 | 2.4271 | 1.1352 | 0.4217 |
| theta per day |
With a day left the call loses half its value overnight, if nothing moves. At the formula divides by zero: at expiry the value is the payoff, with its corner at the strike.
Try it
theta_parts returns the two parts of theta and . The second line is theta per calendar day and per trading day.
Then the one-day repricing and a central difference in , and the slope in , the time to expiry. The loop repeats the table.
The slope in the time to expiry is : the same number with the opposite sign. More time to expiry is worth more, and time passing takes it away. Check which of the two a system reports before adding it to anything.
Rho, and all five by bumping
Rho is the slope in , with , and fixed: . Desks quote it per percentage point of rate, 0.2532: each point of rate is worth about 25 cents.
It is positive because a higher rate makes the strike, paid later, cheaper today. For a six-month option it is small; it grows with the time left.
Case study 2.8.4 checked delta, gamma and vega by bump-and-reprice: move one input a little, reprice and divide. The same works for theta and rho. Each bump moves one input and holds the others fixed, so it is a finite difference of a slice (lesson 4.1.2).
| Greek | closed form | bumped | bump |
|---|---|---|---|
| delta | 0.570158 | 0.570054 | stock $1 |
| gamma | 0.027772 | 0.027762 | stock $1 |
| vega per vol point | 0.277721 | 0.277717 | |
| theta per day | one day forward | ||
| rho per point | 0.253224 | 0.253212 |
The first three rows are case study 2.8.4's. All five agree to about 0.1% or better; theta's one-sided bump is the least accurate, as lesson 2.8.1 predicts.
Try it
closed holds the five closed forms in desk units. bumped reprices the call with one input moved each time. The stock moves by $1, the volatility by one point, the date by one day and the rate by one point.
The last column is each bump's error as a share of the closed form.
Overnight: adding vega and theta
Case study 2.7.4's estimate moved only . When and move too, add one term for each, using its own partial derivative:
Rule: Delta–gamma–vega–theta estimate
is in dollars, a decimal (0.01 for one vol point) and in years ( for a day). With vega per vol point and theta per day, use points and days instead.
Each error below is the repriced change minus the estimate, as in case study 2.7.4.
| stock ($), vol (points), days | repriced | delta–gamma | with vega and theta | error |
|---|---|---|---|---|
| 0, 0, 1 day | 0 | 0.0000 | ||
| 0, 0, 3 days | 0 | |||
| , , 1 day | ||||
| , , 1 day | 2.6530 | 3.1979 | 2.6231 | 0.0298 |
| , , 1 day | ||||
| , , 1 day |
The hook's night is the third row. Delta–gamma alone misses by 26 cents; with vega and theta the estimate is within a tenth of a cent.
A sell-off usually comes with rising volatility, as in the last two rows. There, ignoring vega would miss by 83 cents and $1.39.
What is left grows when both moves are large. It comes from vega changing with : with the stock at $95, vega is 26.34, not 27.77, so three vol points are worth about 4 cents less than the estimate assumes. Case study 4.3.4 finds that at the money most of this change is of degree 3 in the moves.
Lesson 4.2.2 explains why the separate terms can simply be added: the total differential. Case study 4.2.4 uses it to split a day's profit and loss among the inputs, and case study 4.3.4 adds the mixed second-order terms.
Try it
The loop reprices the call after each scenario, with the date moved by the number of days. It prints the repriced change, the delta–gamma estimate, the full estimate and its error.
The last line compares vega at $95 and at $100, and the cost of that difference over three vol points.
The Greeks of a call, in desk units
Write two functions for a Black–Scholes call, with norm.cdf and norm.pdf from scipy.stats. Here T is the time left in years.
call_greeks(S, K, T, r, sigma)returns a dictionary with keys"value","delta","gamma","vega","theta"and"rho". Quote vega per vol point, theta per calendar day (divide by 365) and rho per percentage point. RaiseValueErrorifS,K,Torsigmais not positive.overnight_change(S, K, T, r, sigma, dS, dsigma, days=1)returns the estimate . Heredsigmais a decimal (0.01 for one vol point) and isdays/ 365. RaiseValueErrorifdaysis negative, or not shorter than the time left.
The tests use the six-month call above and compare every Greek with bump-and-reprice for another option. They try the hook's night, a weekend with nothing moving, and inputs that divide by zero.
See the tests
import math
from scipy.stats import norm
def _value(S, K, T, r, sigma):
d1 = (math.log(S / K) + (r + sigma**2 / 2) * T) / (sigma * math.sqrt(T))
return S * norm.cdf(d1) - K * math.exp(-r * T) * norm.cdf(d1 - sigma * math.sqrt(T))
def test_delta_gamma():
"""The six-month call has delta 0.570158 and gamma 0.027772"""
g = call_greeks(100, 100, 0.5, 0.03, 0.2)
expect_close(g["value"], 6.3710279, what="value", rel=1e-6)
expect_close(g["delta"], 0.5701581, what="delta", rel=1e-6)
expect_close(g["gamma"], 0.0277721, what="gamma", rel=1e-5)
def test_vega_per_vol_point():
"""Vega is quoted per vol point: 0.2777 for the six-month call"""
expect_close(call_greeks(100, 100, 0.5, 0.03, 0.2)["vega"], 0.2777213, what="vega per vol point", rel=1e-5)
def test_theta_per_day():
"""Theta is per calendar day and negative: -0.0194 for the six-month call"""
expect_close(call_greeks(100, 100, 0.5, 0.03, 0.2)["theta"], -7.0737698 / 365, what="theta per day", rel=1e-5)
def test_rho_per_point():
"""Rho is per percentage point of rate: 0.2532 for the six-month call"""
expect_close(call_greeks(100, 100, 0.5, 0.03, 0.2)["rho"], 0.2532239, what="rho per point", rel=1e-5)
def test_matches_bumps():
"""Every Greek matches bump-and-reprice for a one-year call at strike 110"""
S, K, T, r, s = 95, 110, 1.0, 0.04, 0.3
g = call_greeks(S, K, T, r, s)
h, k = 0.01, 1e-4
expect_close(g["delta"], (_value(S + h, K, T, r, s) - _value(S - h, K, T, r, s)) / (2 * h), what="delta", rel=1e-6)
expect_close(g["gamma"], (_value(S + h, K, T, r, s) - 2 * _value(S, K, T, r, s) + _value(S - h, K, T, r, s)) / h**2,
what="gamma", rel=1e-4)
expect_close(g["vega"], (_value(S, K, T, r, s + k) - _value(S, K, T, r, s - k)) / (2 * k) / 100, what="vega per vol point", rel=1e-6)
expect_close(g["theta"], -(_value(S, K, T + k, r, s) - _value(S, K, T - k, r, s)) / (2 * k) / 365, what="theta per day", rel=1e-6)
expect_close(g["rho"], (_value(S, K, T, r + k, s) - _value(S, K, T, r - k, s)) / (2 * k) / 100, what="rho per point", rel=1e-6)
def test_hook_night():
"""The stock falls $2, volatility rises one point, a day passes: the estimate is -0.8264"""
expect_close(overnight_change(100, 100, 0.5, 0.03, 0.2, -2, 0.01, days=1), -0.8264308, what="overnight_change", rel=1e-5)
def test_weekend():
"""With nothing moving, a weekend costs three days of theta"""
expect_close(overnight_change(100, 100, 0.5, 0.03, 0.2, 0, 0, days=3), -0.0581406, what="overnight_change over 3 days", rel=1e-5)
def test_bad_inputs():
"""T = 0 and sigma = 0 raise ValueError: the formulas divide by zero"""
for args in [(100, 100, 0.0, 0.03, 0.2), (100, 100, 0.5, 0.03, 0.0)]:
try:
call_greeks(*args)
except ValueError:
continue
raise AssertionError(f"expected ValueError for call_greeks{args}")
def test_days_past_expiry():
"""A move of 200 days on a six-month call raises ValueError"""
try:
overnight_change(100, 100, 0.5, 0.03, 0.2, 0, 0, days=200)
except ValueError:
return
raise AssertionError("expected ValueError: 200 days is past expiry")
Summary card
- An option's value is a function of several inputs, and the rate . Each Greek is a partial derivative in one of them, the others held fixed.
- , , vega , , rho . For a long call all are positive except theta.
- Theta , quoted per day: for the six-month call. It grows near expiry at the money, like gamma.
- Bump-and-reprice confirms all five; theta's one-day bump is a forward difference.
- Along a level curve of in and the value stays fixed. A lower stock price needs a higher volatility, and the floor ends the curve.
- Overnight, . What remains comes mostly from terms that mix the moves.