Chapter 31
28 min read
Section 264 of 353

The Black-Scholes Formula

The Black-Scholes Equation

Learning Objectives

By the end of this section you will be able to:

  1. State the Black-Scholes formula for a European call and explain what each of S0N(d1)S_0 N(d_1) and KerTN(d2)Ke^{-rT}N(d_2) represents.
  2. Compute d1d_1 and d2d_2 by hand and interpret them as signed log-distances measured in standard deviations.
  3. Read N(d2)N(d_2) as the risk-neutral probability that the option is exercised, and N(d1)N(d_1) as the same probability weighted by the share you receive when it is.
  4. Use put-call parity to derive the put formula from the call.
  5. Implement the formula in Python with scipy.stats.norm\text{scipy.stats.norm} and reproduce the canonical sanity check C10.45C \approx 10.45 for the ATM example.
The goal of this section: turn the famously intimidating expression C=S0N(d1)KerTN(d2)C = S_0 N(d_1) - K e^{-rT} N(d_2) into a sentence you can say out loud in plain English — and then play with it until it feels obvious.

From PDE to Closed-Form Formula

In the previous section we derived the Black-Scholes partial differential equation:

Vt+12σ2S22VS2+rSVSrV=0.\displaystyle \frac{\partial V}{\partial t} + \tfrac{1}{2}\sigma^2 S^2 \frac{\partial^2 V}{\partial S^2} + rS\frac{\partial V}{\partial S} - rV = 0.

On its own, that PDE is a recipe, not a number. To get an actual price we need a boundary condition — what the option is worth at expiry — and a clever change of variables. For a European call the boundary condition is the payoff:

V(S,T)=max(SK,  0).V(S, T) = \max(S - K,\; 0).

Substituting x=lnSx = \ln S and τ=Tt\tau = T - t turns the Black-Scholes PDE into the heat equation on a log axis, which has been solvable since Fourier. After undoing the change of variables you are left with the closed-form solution discovered by Fischer Black, Myron Scholes, and (in a more rigorous derivation) Robert Merton in 1973.

Why a closed form was such a big deal

Before 1973, banks priced options by simulation, intuition, or haggling. A closed-form formula meant a trader could price thousands of options in microseconds, hedge them in real time, and arbitrage anyone still pricing by gut. That single equation built a multi-trillion-dollar industry.


The Black-Scholes Formula

For a European call option on a non-dividend-paying stock with spot S0S_0, strike KK, volatility σ\sigma, risk-free rate rr, and time to expiry TT:

C=S0N(d1)    KerTN(d2),\displaystyle C = S_0\, N(d_1) \;-\; K e^{-rT}\, N(d_2),

where

d1=ln ⁣(S0/K)+(r+12σ2)TσT,d2=d1σT,\displaystyle d_1 = \frac{\ln\!\left(S_0/K\right) + \left(r + \tfrac{1}{2}\sigma^2\right) T}{\sigma\sqrt{T}}, \qquad d_2 = d_1 - \sigma\sqrt{T},

and N()N(\cdot) is the cumulative distribution function of a standard normal random variable.

The whole formula in one English sentence

The fair price of a call option is the expected stock you receive at expiry minus the expected cash you pay — both weighted by the probability that the option is actually exercised, and both pulled back to today's dollars.

Read out loud: "Stock leg minus discounted cash leg." That is the whole intuition. The rest of this section is just unpacking why the probabilities N(d1)N(d_1) and N(d2)N(d_2) show up.


What Are d₁ and d₂?

Stripped of decoration, d1d_1 and d2d_2 are signed distances: how far is the current stock from the strike, measured on a log scale, in units of the stock's diffusion σT\sigma\sqrt{T}?

The numerator: how far from the strike, in log-space?

The numerator of d1d_1 is ln(S0/K)+(r+12σ2)T\ln(S_0/K) + (r + \tfrac{1}{2}\sigma^2)T. The first piece ln(S0/K)\ln(S_0/K) is positive when S0>KS_0 > K (in-the-money), zero at the strike, and negative when out-of-the-money. The second piece (r+12σ2)T(r + \tfrac{1}{2}\sigma^2)T is the drift of the log-stock under the risk-neutral measure — where the stock is "expected" to be, on average, by expiry.

The denominator: how big are the wiggles?

σT\sigma\sqrt{T} is the standard deviation of the log-stock at time TT. So dividing by it converts "distance to strike" into "distance in standard deviations." This is exactly the kind of z-score you would compute in any statistics class.

The one-sentence interpretation

d2d_2 is the z-score of the log-strike under the risk-neutral distribution of the stock at expiry. d1=d2+σTd_1 = d_2 + \sigma\sqrt{T} is the same z-score shifted by one diffusion unit, which is exactly the shift induced by changing measure from cash-weighted to share-weighted.

Step-by-step for the canonical example

Take the textbook ATM call: S0=100S_0=100, K=100K=100, σ=0.20\sigma=0.20, r=0.05r=0.05, T=1T=1 year.

QuantitySubstitutionValue
ln(S₀/K)ln(1)0
(r + ½σ²)T(0.05 + 0.02)·10.07
σ√T0.20·10.20
d₁0.07 / 0.200.35
d₂0.35 − 0.200.15
N(d₁)Φ(0.35)0.6368
N(d₂)Φ(0.15)0.5596

Notice how small d1d_1 and d2d_2 are — both well under 1 standard deviation. That tells you the at-the-money case is genuinely "undecided": the option is roughly a coin flip plus a small drift bonus.


The Two Pieces of the Price

The Black-Scholes formula has the form C=(stock leg)(cash leg)C = (\text{stock leg}) - (\text{cash leg}). Each leg corresponds to one of the two things that happen if the option is exercised at expiry: you receive a share and you pay the strike. Both are weighted by a probability and pulled back to today.

Stock leg: S0N(d1)S_0\, N(d_1)

Present value of receiving the share when the call is exercised. The probability weight N(d1)N(d_1) is the risk-neutral probability of exercise weighted by the share you collect — a stock-measure expectation.

Cash leg: KerTN(d2)K e^{-rT}\, N(d_2)

Present value of paying the strike when the call is exercised. KerTK e^{-rT} discounts the strike back to today; N(d2)N(d_2) is the plain risk-neutral probability that exercise actually happens.

Why N(d₁) ≥ N(d₂)

The two probabilities are not the same. N(d1)N(d_1) over-weights paths where the stock ends up high (because the share you receive is worth more there). N(d2)N(d_2) is the unweighted probability of exercise. The gap N(d1)N(d2)N(d_1) - N(d_2) is exactly where the option's convexity premium hides.


The Risk-Neutral Probability Story

Under the Black-Scholes model, the stock at expiry follows a log-normal distribution:

lnST    N ⁣(lnS0+(r12σ2)T,  σ2T).\displaystyle \ln S_T \;\sim\; \mathcal{N}\!\left(\ln S_0 + (r - \tfrac{1}{2}\sigma^2)T,\; \sigma^2 T\right).

The event "call ends in the money" is ST>KS_T > K, equivalently lnST>lnK\ln S_T > \ln K. Standardising lnST\ln S_T by its mean and standard deviation and using P(Z>x)=N(x)=1N(x)P(Z > x) = N(-x) = 1 - N(x) gives, after a couple of algebraic lines,

Pr(ST>K)  =  N(d2).\Pr^{*}(S_T > K) \;=\; N(d_2).

That is the "cash-leg" probability. The stock-leg probability N(d1)N(d_1) arises if you instead compute the same probability under a different measure — one in which the share itself is the numeraire instead of the bank account. Changing measure shifts the mean of lnST\ln S_T up by σ2T\sigma^2 T, which is exactly the σT\sigma\sqrt{T} shift between d2d_2 and d1d_1.

Below, each bar is the value of N(d2)N(d_2) for a call with K=100K=100, σ=0.20\sigma=0.20, r=0.05r=0.05, T=1T=1, as the spot price S0S_0 moves further into the money. It is the model's answer to the question: "how likely am I to actually exercise this call?"

Deep OTM call (S=70, K=100)N(d₂) = 5.1%
ATM call (S=100, K=100)N(d₂) = 56.0%
ITM call (S=120, K=100)N(d₂) = 85.6%
Deep ITM call (S=140, K=100)N(d₂) = 96.7%

Each bar is the risk-neutral probability that the call finishes in-the-money. Deep OTM ≈ small chance; deep ITM ≈ near certainty.


Interactive Visualization

The figure below plots option price as a function of spot SS. The dashed grey line is the intrinsic value at expiry (max(SK,0)\max(S - K, 0) for a call, max(KS,0)\max(K - S, 0) for a put). The bright curve is the Black-Scholes price today. The green bracket is the time value: how much extra you pay today for the chance that the stock moves favourably before expiry.

Things to try as you move the sliders:

  • Crank σ\sigma up: the curve lifts off the intrinsic line — more uncertainty is more option value.
  • Drag TT down toward zero: the price curve collapses onto the dashed payoff line. At expiry, time value disappears.
  • Crank rr up: the call gets more expensive (the discounted strike is cheaper) and the put gets cheaper.
  • Push the spot far ITM or far OTM: the price approaches its limit (a forward minus discounted strike for deep ITM calls, nearly zero for deep OTM).
Option type:
d₁
0.3500
d₂
0.1500
N(d₁)
0.6368
N(d₂)
0.5596
Call price C
$10.45

Drag the sliders to feel how each parameter pushes the price up or down. The dashed gray line is the payoff at expiry (what the option is worth if today were the expiration day). The colored curve is the Black-Scholes price today. The green bracket at S is the time value — the premium you pay for the chance that the stock moves favorably before expiry.


Worked Example: ATM Call Option

Let us walk through the canonical at-the-money example by hand. This is the example every quant has memorised, because the answers are round and clean — if you ever code Black-Scholes and the numbers don't match, this is the test case that pins down the bug.

Setup: A European call with S0=100S_0 = 100, K=100K = 100, σ=20%\sigma = 20\%, r=5%r = 5\%, T=1T = 1 year. What is the fair price CC?
▸ Click to expand the full hand-traced solution

Step 1 — Compute the diffusion scale σ√T

σT=0.201=0.20.\sigma\sqrt{T} = 0.20 \cdot \sqrt{1} = 0.20. Over one year, the log-stock is normally distributed with standard deviation 0.20 (about 20% as a multiplicative move).

Step 2 — Compute d₁

Plug numbers into the definition:

d1=ln(100/100)+(0.05+12(0.20)2)10.201=0+0.070.20=0.35.d_1 = \dfrac{\ln(100/100) + \left(0.05 + \tfrac{1}{2}(0.20)^2\right)\cdot 1}{0.20\cdot 1} = \dfrac{0 + 0.07}{0.20} = 0.35.

Interpretation: today's log-spot is 0.35 standard deviations above the log-strike, after accounting for risk-neutral drift. A small positive number — the option is just barely tilted toward exercise.

Step 3 — Compute d₂

d2=d1σT=0.350.20=0.15.d_2 = d_1 - \sigma\sqrt{T} = 0.35 - 0.20 = 0.15.

Step 4 — Look up the standard normal CDF

From a normal table (or scipy.stats.norm.cdf):

N(d1)=N(0.35)0.6368,N(d_1) = N(0.35) \approx 0.6368,N(d2)=N(0.15)0.5596.N(d_2) = N(0.15) \approx 0.5596.

So the model says: under risk-neutral probabilities, there is a 55.96% chance the call is exercised. The share-weighted exercise probability is a bit higher, 63.68%, because exercise "happens more heavily" on paths where the stock is worth more.

Step 5 — Compute the discount factor

erT=e0.050.9512.e^{-rT} = e^{-0.05} \approx 0.9512.

So a dollar received in one year is worth about $0.95\$0.95 today. The present value of the strike is KerT=95.12K e^{-rT} = 95.12.

Step 6 — Plug into the formula

C=S0N(d1)KerTN(d2)C = S_0 N(d_1) - K e^{-rT} N(d_2)C=1000.636895.120.5596C = 100 \cdot 0.6368 - 95.12 \cdot 0.5596C=63.683153.2325C = 63.6831 - 53.2325C10.4506.\boxed{C \approx 10.4506.}

Sanity check — does this number feel right?

  1. The intrinsic value today is max(S0K,0)=0\max(S_0 - K, 0) = 0. All $10.45\$10.45 of the price is time value.
  2. That is roughly 10%10\% of the stock price — completely typical for a one-year ATM call with 20% volatility.
  3. If we set T=0T = 0, the price collapses to max(S0K,0)=0\max(S_0 - K, 0) = 0. Time value vanishes.
  4. If we set σ=0\sigma = 0, the call becomes a deterministic forward and the price collapses to max(S0KerT,0)4.88\max(S_0 - K e^{-rT}, 0) \approx 4.88. No randomness, no convexity bonus.

Conclusion: the fair price of this call is about $10.45\$10.45 — and the model can break that number down into a stock leg of $63.68\$63.68 minus a discounted cash leg of $53.23\$53.23.


Python Implementation

Now let us translate the formula directly into Python. The whole thing is twelve real lines of arithmetic — Black-Scholes is shockingly small once you trust the formula.

We are using scipy.stats.norm.cdf for the normal CDF and nothing else. As you read the code-explanation cards on the left, hover over the line on the right to see the exact correspondence — every non-trivial line is traced against the canonical S=K=100S = K = 100 example so you can verify the intermediate values by eye.

The Black-Scholes formula, end to end
🐍black_scholes.py
1NumPy

NumPy gives us np.log, np.sqrt, and np.exp. The same code works whether S is a single float (one option) or a whole NumPy array (a grid of options), because all the operations are vectorised.

2The standard normal CDF lives here

scipy.stats.norm.cdf is the cumulative distribution function N(x) of a standard normal random variable. N(x) = probability that a standard normal sample is ≤ x. It is the single piece of statistics machinery the Black-Scholes formula needs.

EXAMPLE
norm.cdf(0.35) → 0.6368 (≈ N(d1) for our example)
4Function signature — the five Black-Scholes inputs

Every European option price is a function of just five numbers: spot S, strike K, volatility σ, rate r, time T. The option_type flag picks call vs put. These five inputs are the entire 'state of the world' the model needs — everything else (Brownian motion paths, hedging strategy) is internal mathematics.

18Why sqrt(T) keeps appearing

Volatility σ is annualised — it is the standard deviation of log-returns over ONE YEAR. Over T years, log-returns are scaled by σ·√T (this is the diffusion scaling of Brownian motion: variance grows linearly with time, so standard deviation grows like √t). Caching np.sqrt(T) once is just a tiny optimisation.

EXAMPLE
If σ = 0.20 and T = 1 year, σ·√T = 0.20 (one year of volatility)
19d1 — the numerator carried 'with the drift'

d1 is a signed distance, in units of σ·√T, between today's log-spot ln(S) and the strike's log level ln(K), AFTER adjusting for the risk-neutral drift (r + ½σ²)T. For S=100, K=100, σ=0.20, r=0.05, T=1: ln(S/K)=0, drift=(0.05+0.02)·1=0.07, so d1 = 0.07 / 0.20 = 0.35.

EXAMPLE
d1 = (ln(S/K) + (r + ½σ²)T) / (σ√T)  ⇒  d1 = 0.07 / 0.20 = 0.35
20d2 is just d1 shifted by one σ·√T

d2 = d1 − σ√T. The shift looks like a tiny algebraic detail but is the heart of the model: d1 prices the share-receipt leg, d2 prices the cash-payment leg, and the gap σ√T is exactly the diffusion scale of the underlying stock. For our example: d2 = 0.35 − 0.20 = 0.15.

EXAMPLE
d2 = d1 − σ√T  ⇒  d2 = 0.35 − 0.20 = 0.15
23N(d1) — risk-neutral probability weighting for the stock leg

N(d1) is the cumulative standard-normal probability up to d1. Intuitively, it is the probability (under the risk-neutral measure, weighted by the stock's terminal price) that the call ends in the money. For d1 = 0.35, norm.cdf(0.35) ≈ 0.6368.

EXAMPLE
norm.cdf(0.35) → 0.6368 = 63.68%
24N(d2) — risk-neutral probability of exercise

N(d2) is the (plain) risk-neutral probability that the call finishes in the money, i.e. P*(S_T > K). For d2 = 0.15, norm.cdf(0.15) ≈ 0.5596. So an ATM call has a ~56% risk-neutral chance of paying out — but the expected stock you collect, given exercise, is captured by the N(d1) > N(d2) gap.

EXAMPLE
norm.cdf(0.15) → 0.5596 = 55.96%
27The discount factor

exp(−rT) takes the future strike K and pulls it back to today's money. Money paid at time T is worth less today because of the risk-free rate. For r=0.05, T=1: exp(−0.05·1) = 0.9512, so the strike K=100 has a present value of $95.12.

EXAMPLE
np.exp(-0.05 * 1.0) → 0.9512
30Call price — two terms with opposing signs

C = S·N(d1) − K·e^(−rT)·N(d2). Term 1 is the present value of receiving the stock, weighted by the stock-aware exercise probability. Term 2 is the present value of paying the strike, weighted by the plain exercise probability. The call price is the difference.

EXAMPLE
C = 100·0.6368 − 95.12·0.5596 = 63.6831 − 53.2325 = 10.4506 ≈ $10.45
33Put — same shape, mirrored across zero

By symmetry of the normal distribution, N(−x) = 1 − N(x). The put formula swaps the two legs: you now PAY the stock and RECEIVE the strike, each weighted by the mirror-image probability. We could equivalently compute the put from put-call parity: P = C − S + K·e^(−rT). Both give P ≈ $5.57 for our example.

EXAMPLE
P = 95.12·N(−0.15) − 100·N(−0.35) = 95.12·0.4404 − 100·0.3632 = 5.5735
36Defensive raise

If the caller passes a typo like 'call ', 'CALL', or 'european', we fail loudly. Silent type-coercion in pricing code is how trading desks lose money before lunch.

43Canonical sanity check

S = K = 100, σ = 20%, r = 5%, T = 1 year. This is the textbook ATM Black-Scholes example — every quant has its answer memorised. If your implementation does not print Call ≈ 10.4506, something is wrong in the formula, the CDF call, or the units of σ or r.

EXAMPLE
Expected output:
  d1     = 0.350000
  d2     = 0.150000
  N(d1)  = 0.636831
  N(d2)  = 0.559618
  Call   = 10.4506
38 lines without explanation
1import numpy as np
2from scipy.stats import norm
3
4def black_scholes(S, K, sigma, r, T, option_type="call"):
5    """
6    Compute the Black-Scholes price of a European option.
7
8    Parameters
9    ----------
10    S : float        # spot price of the underlying today
11    K : float        # strike price
12    sigma : float    # annualized volatility (e.g. 0.20 = 20%)
13    r : float        # continuously compounded risk-free rate
14    T : float        # time to expiry in years
15    option_type : str  # "call" or "put"
16    """
17    # --- Step 1. Compute d1 and d2 ------------------------------------------
18    sqrtT = np.sqrt(T)
19    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * sqrtT)
20    d2 = d1 - sigma * sqrtT
21
22    # --- Step 2. Standard normal CDFs ---------------------------------------
23    Nd1 = norm.cdf(d1)
24    Nd2 = norm.cdf(d2)
25
26    # --- Step 3. Discount factor for the strike -----------------------------
27    discount = np.exp(-r * T)
28
29    # --- Step 4. Apply the Black-Scholes formula ----------------------------
30    if option_type == "call":
31        price = S * Nd1 - K * discount * Nd2
32    elif option_type == "put":
33        # By put-call parity (or directly from the formula with N(-x))
34        price = K * discount * norm.cdf(-d2) - S * norm.cdf(-d1)
35    else:
36        raise ValueError("option_type must be 'call' or 'put'")
37
38    return price, d1, d2, Nd1, Nd2
39
40
41# ----------------------------------------------------------------------------
42# Try it on the canonical at-the-money example
43# ----------------------------------------------------------------------------
44S, K, sigma, r, T = 100.0, 100.0, 0.20, 0.05, 1.0
45price, d1, d2, Nd1, Nd2 = black_scholes(S, K, sigma, r, T, "call")
46
47print(f"d1     = {d1:.6f}")
48print(f"d2     = {d2:.6f}")
49print(f"N(d1)  = {Nd1:.6f}")
50print(f"N(d2)  = {Nd2:.6f}")
51print(f"Call   = {price:.4f}")

What you should see when you run this

d1     = 0.350000
d2     = 0.150000
N(d1)  = 0.636831
N(d2)  = 0.559618
Call   = 10.4506

Closed-form Greeks fall out of the same formula by differentiating each input. The implementation is just one extra line per Greek — and each one tells the trader something concrete about how the option behaves.

Closed-form Greeks for a European call
🐍black_scholes_greeks.py
4Greeks = derivatives of the formula

The Black-Scholes formula is a smooth function of (S, K, σ, r, T), so we can just differentiate it. Each derivative gets a Greek-letter name and tells the trader how sensitive the price is to one input.

12norm.pdf — the bell-curve density

Where norm.cdf gives the area under the bell curve up to x, norm.pdf(x) = (1/√(2π))·exp(−x²/2) gives the HEIGHT of the curve at x. It shows up in every Greek that involves how concentrated the probability mass is around d1.

EXAMPLE
norm.pdf(0.35) ≈ 0.3752
16Delta = N(d1)

Delta is the slope of the option price as a function of S — how many shares the option behaves like today. For an ATM call, delta ≈ 0.5 (you 'own roughly half a share'). A delta-hedged trader holds −delta shares to neutralise small price moves.

EXAMPLE
Δ = N(0.35) ≈ 0.6368
17Gamma — curvature

Gamma is how fast delta itself changes. Gamma is largest near the strike (where the option is most 'undecided' between exercise and abandonment). Gamma is why delta-hedging is not a one-time trade — you must rebalance as S moves.

EXAMPLE
Γ = pdf(d1) / (S·σ·√T) ≈ 0.3752 / (100·0.20·1) ≈ 0.01876
18Vega — volatility sensitivity

Vega is how much the option price moves when σ moves by 1 (i.e. 100 vol points). Long options are long vega: more uncertainty = more upside. For ATM options, vega is maximal.

EXAMPLE
ν = S·pdf(d1)·√T ≈ 100·0.3752·1 ≈ 37.52
19Theta — time decay

Theta is the rate at which the option loses value as the clock ticks toward expiry (with all else fixed). For a long call, theta is negative — you are 'paying rent' every day for the chance that the stock moves favourably.

20Rho — interest-rate sensitivity

Rho captures how the option reprices when the risk-free rate moves. For a call, rho is positive — a higher r means the discounted strike is cheaper, so the call is worth more. Rho is usually the smallest Greek for short-dated options.

19 lines without explanation
1import numpy as np
2from scipy.stats import norm
3
4def call_greeks(S, K, sigma, r, T):
5    """
6    Closed-form greeks for a European call.
7    Greeks are partial derivatives of the price w.r.t. each input.
8    """
9    sqrtT = np.sqrt(T)
10    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * sqrtT)
11    d2 = d1 - sigma * sqrtT
12
13    pdf_d1 = norm.pdf(d1)            # standard normal density at d1
14    Nd1    = norm.cdf(d1)
15    Nd2    = norm.cdf(d2)
16
17    delta = Nd1                                                       # ∂C/∂S
18    gamma = pdf_d1 / (S * sigma * sqrtT)                              # ∂²C/∂S²
19    vega  = S * pdf_d1 * sqrtT                                        # ∂C/∂σ
20    theta = -(S * pdf_d1 * sigma) / (2 * sqrtT) - r * K * np.exp(-r*T) * Nd2  # ∂C/∂t
21    rho   = K * T * np.exp(-r * T) * Nd2                              # ∂C/∂r
22
23    return dict(delta=delta, gamma=gamma, vega=vega, theta=theta, rho=rho)
24
25# Canonical example
26print(call_greeks(100.0, 100.0, 0.20, 0.05, 1.0))

Put-Call Parity

We can derive the put price from the call without re-doing the whole derivation. Consider a portfolio: buy one call, sell one put, both with the same strike KK and expiry TT. Its payoff at expiry is:

max(STK,0)max(KST,0)=STK.\max(S_T - K, 0) - \max(K - S_T, 0) = S_T - K.

But STKS_T - K is exactly the payoff of a forward contract on the stock. By no-arbitrage, its price today must equal the forward price S0KerTS_0 - K e^{-rT}. So:

  CP=S0KerT.  \boxed{\; C - P = S_0 - K e^{-rT}. \;}

This is put-call parity. It is model-independent — it holds for any European options, not just Black-Scholes ones. Rearranging gives the put formula:

P=KerTN(d2)S0N(d1).P = K e^{-rT} N(-d_2) - S_0 N(-d_1).

For our canonical example, P=95.120.44041000.36325.57P = 95.12 \cdot 0.4404 - 100 \cdot 0.3632 \approx 5.57. We can double-check directly: CP=10.455.57=4.88=10095.12  C - P = 10.45 - 5.57 = 4.88 = 100 - 95.12 \;\checkmark.

Use parity as a free unit test

Any time you implement Black-Scholes, compute both CC and PP from your code and verify CP=S0KerTC - P = S_0 - K e^{-rT} to machine precision. If parity fails by more than ~1e-12, you have a bug in your CDF, your discount factor, or your sign conventions.


Limiting Behavior and Sanity Checks

A good way to feel the formula is to watch what happens at its boundaries. Each limit collapses Black-Scholes back to something simple — and each one tells you the model is doing the right thing.

RegimeWhat happens to d₁ and d₂Call price collapses toIntuition
S → ∞ (deep ITM)Both → +∞, N → 1S₀ − K·e^(−rT)Owning the call is basically owning the stock minus a delayed payment of K.
S → 0 (deep OTM)Both → −∞, N → 00Worthless — the stock has no chance of recovery.
σ → 0 (no volatility)d₁ = d₂ = sign(S₀ − K·e^(−rT)) · ∞max(S₀ − K·e^(−rT), 0)Deterministic forward; option is exercised if and only if the discounted forward beats the strike.
T → 0 (about to expire)σ√T → 0, then d → ±∞ depending on S vs Kmax(S₀ − K, 0)Time value vanishes — only intrinsic value remains.
σ → ∞ (infinite uncertainty)d₁ → +∞, d₂ → −∞S₀The call is as valuable as just owning the stock — the strike becomes irrelevant.

Reality check on σ → ∞

The formula gives the right limit mathematically, but in real markets nobody would ever sell you a stock for a call with σ in the hundreds of percent. Implied volatilities for traded options typically sit between 10% and 100% — anything beyond that is either a meme stock, a takeover candidate, or a numerical glitch in your data pipeline.


Applications

The Black-Scholes formula is the bedrock of an enormous amount of practical machinery. A few highlights:

💹 Market-making and quoting

Every options exchange screen you have ever seen has Black-Scholes (or a richer cousin) running underneath. Bid/ask spreads are quoted around the formula price.

🛡️ Delta hedging

Δ=N(d1)\Delta = N(d_1) tells you how many shares to hold to neutralise small moves in the underlying. Every options desk reruns this calculation hundreds of times a second.

🏢 Employee stock options

U.S. accounting rules (FASB ASC 718) require companies to expense stock-option grants at fair value — and Black-Scholes (or a lattice extension) is the standard valuation tool.

📈 Implied volatility

Run the formula backwards: given a market price CmktC^{mkt}, solve for the σ\sigma that produces it. This implied volatility is how traders actually quote options — in vol points, not dollars.


Summary

  1. The Black-Scholes formula for a European call is C=S0N(d1)KerTN(d2)C = S_0 N(d_1) - K e^{-rT} N(d_2). Read it as "stock leg minus discounted cash leg."
  2. d2d_2 is the z-score of the log-strike under the risk-neutral measure; d1=d2+σTd_1 = d_2 + \sigma\sqrt{T} is the same z-score under the share-numeraire measure.
  3. N(d2)N(d_2) is the probability the call is exercised; N(d1)N(d_1) is the same probability weighted by the share you receive.
  4. For the canonical ATM example (S=K=100,σ=0.20,r=0.05,T=1)(S=K=100,\sigma=0.20,r=0.05,T=1), C$10.45C \approx \$10.45 — every quant's favourite sanity check.
  5. Put-call parity CP=S0KerTC - P = S_0 - K e^{-rT} derives the put price from the call without any new modelling assumptions, and is a free unit test for any implementation.
  6. Every Greek (Delta, Gamma, Vega, Theta, Rho) is one more derivative of the same formula — three lines of code each.
In one breath:
"Black-Scholes is the present value of receiving the stock minus the present value of paying the strike, each weighted by the probability of exercise."
Coming next: in the next section we make the Greeks Δ\Delta, Γ\Gamma, Θ\Theta, V\mathcal{V} — the partial derivatives we just sketched — the protagonists. They are how every options trader actually sees the market: not as prices, but as a portfolio of exposures.
Loading comments...