Black-Scholes Formula: European Option Pricing & Greeks

Michael BrenndoerferNovember 28, 202558 min read

Covers the Black-Scholes formula for European options with Python implementation. Topics include derivation, the Greeks, put-call parity.

Quantitative FinanceAll chapters
Part 5 of 15Stochastic Calculus and Pricing Theory
Chapter 30Black-Scholes Formula and European Option Pricing
Reading the full chapter · 11 sections · 58 min11 sections · 58 min

All 11 sections · 58 min read

Black-Scholes Formula and European Option PricingFull chapter · Sections in this chapter1 / 11 ↓
Track your reading progress

Sign in to mark sections as read and track your learning journey

Sign in →
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Black-Scholes Formula and European Option Pricing

In the previous chapter, we derived the Black-Scholes-Merton partial differential equation (PDE), which describes how the price of a derivative must evolve to prevent arbitrage opportunities. That PDE, while elegant, doesn't immediately tell us what an option is worth. To price an option, we need to solve the PDE subject to the appropriate boundary conditions.

This chapter presents the solution: the famous Black-Scholes formula for European options. Published by Fischer Black and Myron Scholes in 1973, with an alternative derivation and extensions published by Robert Merton that same year, this formula transformed finance by providing a closed-form European option price grounded in dynamic replication and no-arbitrage reasoning. The formula gave market participants a systematic way to connect option prices with the cost of dynamically hedging their payoffs. Cboe reports growth from 5.6 million contracts in 1974 to roughly 1.3 billion across its exchanges in 2014, including futures. The 1997 Nobel committee credited the pricing methodology with advances in valuation and risk management.

The formula expresses an option's price in terms of five observable or estimable quantities: the current stock price, the strike price, time to expiration, the risk-free interest rate, and the volatility of the underlying asset. The expected return of the stock does not appear in the formula. As we learned when studying risk-neutral valuation, this non-dividend-paying stock has expected growth rate rr under the pricing measure. More generally, the martingale condition applies to appropriately discounted total gains, including dividends, rather than to every ex-dividend asset price.

We'll work through the solution to the Black-Scholes PDE, interpret each component of the resulting formula, implement it in Python, and verify that it satisfies fundamental relationships like put-call parity. We'll close with an introduction to the Greeks, the sensitivity measures that quantify how option prices respond to changes in the underlying parameters.

Solving the Black-Scholes PDE

Recall from the previous chapter that the Black-Scholes PDE for a derivative V(S,t)V(S,t) on a non-dividend-paying stock is:

∂V∂t+12σ2S2∂2V∂S2+rS∂V∂S−rV=0\frac{\partial V}{\partial t} + \frac{1}{2}\sigma^2 S^2 \frac{\partial^2 V}{\partial S^2} + rS\frac{\partial V}{\partial S} - rV = 0

where:

  • VV: price of the derivative
  • tt: time
  • SS: price of the underlying asset
  • σ\sigma: volatility of the underlying asset
  • rr: risk-free interest rate

This equation captures a fundamental requirement: the price of any derivative must evolve in time so no riskless arbitrage profit can be extracted. Each term in the equation plays a specific role. The first term represents how the option price changes with the passage of time alone. The second term, involving the second derivative with respect to the stock price, captures the effect of the stock's random fluctuations, which is precisely why the volatility parameter appears squared and multiplied by S2S^2. The third term accounts for the drift in the option price due to the expected growth of the stock under risk-neutral dynamics. The last term discounts the derivative value at rate rr. Together, the PDE terms make the self-financing delta-hedged position with value V−SVSV-SV_S earn the risk-free rate; the unhedged derivative need not have that expected return under the physical measure.

To find the price of a European call option, we must solve this PDE subject to the boundary condition at expiration:

C(S,T)=max⁡(S−K,0)C(S,T) = \max(S - K, 0)

where:

  • C(S,T)C(S,T): value of the call option at expiration
  • SS: stock price at expiration
  • KK: strike price
  • TT: expiration time

This boundary condition states something intuitive: at the moment of expiration, an option is worth exactly its intrinsic value. If the stock price exceeds the strike, the call holder can buy the stock at KK and immediately sell it at SS, pocketing the difference. If the stock price falls below the strike, the call expires worthless. The mathematical challenge lies in determining what the option should be worth at any time before expiration, given that it will satisfy this terminal condition.

We seek the financially admissible solution, with 0≤C(S,t)≤S0\leq C(S,t)\leq S and at most linear growth as SS increases. These restrictions exclude nonfinancial solutions on the unbounded stock-price domain.

Transformation to the Heat Equation

Assume S,K>0S,K>0, constant σ>0\sigma>0 and constant rr. Introduce remaining time τ=T−t\tau=T-t, measured in years when the rate and volatility use annual units. As τ\tau increases, we move backward from the known expiry payoff. Set x=ln⁡(S/K)x=\ln(S/K), the dimensionless log-moneyness. Multiplying SS by a factor adds the logarithm of that factor to xx. For example, when K=\100,stockpricesof, stock prices of $50andand$200maptomap to-\ln 2andand+\ln 2$.

Normalize and discount the option value by writing

V(S,t)=Ke−rτv(x,τ).V(S,t)=K e^{-r\tau}v(x,\tau).

Here vv is dimensionless; τ\tau still has units of time. The chain rule gives

Vt=Ke−rτ(rv−vτ),VS=Ke−rτSvx,VSS=Ke−rτS2(vxx−vx).V_t=K e^{-r\tau}(rv-v_\tau),\qquad V_S=\frac{K e^{-r\tau}}{S}v_x,\qquad V_{SS}=\frac{K e^{-r\tau}}{S^2}(v_{xx}-v_x).

Substituting these derivatives into the pricing PDE and cancelling Ke−rτK e^{-r\tau} leaves a constant-coefficient equation:

vτ=σ22vxx+(r−σ22)vx.v_\tau=\frac{\sigma^2}{2}v_{xx}+ \left(r-\frac{\sigma^2}{2}\right)v_x.

Write a=σ2/2a=\sigma^2/2 and b=r−σ2/2b=r-\sigma^2/2. To remove both the drift term and the zero-order term that the next substitution creates, set

v=eαx+βτu,α=−b2a=12−rσ2,β=−b24a=−σ2α22.v=e^{\alpha x+\beta\tau}u,\qquad \alpha=-\frac{b}{2a}=\frac12-\frac{r}{\sigma^2},\qquad \beta=-\frac{b^2}{4a}=-\frac{\sigma^2\alpha^2}{2}.

The constant α\alpha is dimensionless, while β\beta has inverse-time units. Direct differentiation gives uτ=auxx+(2aα+b)ux+(aα2+bα−β)uu_\tau=a u_{xx}+(2a\alpha+b)u_x+(a\alpha^2+b\alpha-\beta)u. Our choices make both extra coefficients zero, so

uτ=σ22uxx.u_\tau=\frac{\sigma^2}{2}u_{xx}.

This is the heat equation with diffusivity σ2/2\sigma^2/2. The terminal call payoff becomes its initial condition at τ=0\tau=0:

u(y,0)=e−αy(ey−1)+.u(y,0)=e^{-\alpha y}(e^y-1)^+.

The notation z+=max⁡(z,0)z^+=\max(z,0) clips negative values to zero. Thus this initial function is zero for y≤0y\leq0. For τ>0\tau>0, the whole-line heat kernel is the Gaussian density

G(x−y,τ)=1σ2πτexp⁡ ⁣(−(x−y)22σ2τ).G(x-y,\tau)= \frac{1}{\sigma\sqrt{2\pi\tau}} \exp\!\left(-\frac{(x-y)^2}{2\sigma^2\tau}\right).

It weights transformed payoff values at log-price endpoints yy. The kernel integrates to one; u(y,0)u(y,0) is a transformed payoff, not a probability density. Convolving the two gives

u(x,τ)=∫0∞[e(1−α)y−e−αy]G(x−y,τ) dy.u(x,\tau)= \int_0^\infty \left[e^{(1-\alpha)y}-e^{-\alpha y}\right]G(x-y,\tau)\,dy.

To evaluate this integral, let z=στz=\sigma\sqrt{\tau} and define Ic=∫0∞ecyG(x−y,τ) dyI_c=\int_0^\infty e^{cy}G(x-y,\tau)\,dy. Completing the square in its exponent gives

cy−(x−y)22z2=−(y−x−cz2)22z2+cx+c2z22,Ic=ecx+c2z2/2N ⁣(x+cz2z).cy-\frac{(x-y)^2}{2z^2} =-\frac{(y-x-cz^2)^2}{2z^2}+cx+\frac{c^2z^2}{2}, \qquad I_c=e^{cx+c^2z^2/2}N\!\left(\frac{x+cz^2}{z}\right).

Here NN is the standard normal cumulative distribution function. Hence u=I1−α−I−αu=I_{1-\alpha}-I_{-\alpha}. Multiplying by the two scaling factors recovers C=Ke−rτeαx+βτuC=K e^{-r\tau}e^{\alpha x+\beta\tau}u. Because β=−σ2α2/2\beta=-\sigma^2\alpha^2/2 and ασ2=σ2/2−r\alpha\sigma^2=\sigma^2/2-r, the first term simplifies to SN(d1)SN(d_1) and the second to Ke−rτN(d2)Ke^{-r\tau}N(d_2), where

d1=x+(r+σ2/2)τστ,d2=x+(r−σ2/2)τστ.d_1=\frac{x+(r+\sigma^2/2)\tau}{\sigma\sqrt{\tau}}, \qquad d_2=\frac{x+(r-\sigma^2/2)\tau}{\sigma\sqrt{\tau}}.

The next section states the resulting prices and interprets these standardized terms.

The General Solution

Working backward through the transformations, reversing each change of variables in sequence, the solution for a European call option emerges as:

C(S,t)=S⋅N(d1)−Ke−r(T−t)N(d2)C(S,t) = S \cdot N(d_1) - K e^{-r(T-t)} N(d_2)

where:

  • C(S,t)C(S,t): call option price
  • SS: current stock price
  • N(⋅)N(\cdot): cumulative standard normal distribution function
  • d1,d2d_1, d_2: standardized moneyness terms
  • KK: strike price
  • rr: risk-free interest rate
  • T−tT-t: time to expiration

This formula expresses the option price as the difference between two terms, each involving the cumulative normal distribution function N(⋅)N(\cdot). The function N(x)N(x) gives the probability that a standard normal random variable is less than xx, and it appears here because the underlying stock price follows a lognormal distribution under geometric Brownian motion.

The terms d1d_1 and d2d_2 are defined as:

d1=ln⁡(S/K)+(r+σ22)(T−t)σT−td_1 = \frac{\ln(S/K) + (r + \frac{\sigma^2}{2})(T-t)}{\sigma\sqrt{T-t}}

where:

  • SS: current stock price
  • KK: strike price
  • rr: risk-free rate
  • σ\sigma: volatility
  • T−tT-t: time to expiration

The numerator of d1d_1 contains two parts. The first, ln⁡(S/K)\ln(S/K), measures the current moneyness of the option in logarithmic terms. A positive value indicates the option is in-the-money, while a negative value indicates it is out-of-the-money. The second part, (r+σ2/2)(T−t)(r + \sigma^2/2)(T-t), equals the risk-neutral expected log-price drift (r−σ2/2)(T−t)(r - \sigma^2/2)(T-t) plus the variance adjustment σ2(T−t)\sigma^2(T-t). It shifts d2d_2 to d1d_1; it is not the expected log-price drift itself. The denominator, σT−t\sigma\sqrt{T-t}, normalizes this quantity by the standard deviation of the log-price at expiration, converting it into a standardized z-score.

The second standardized term is:

d2=d1−σT−t=ln⁡(S/K)+(r−σ22)(T−t)σT−td_2 = d_1 - \sigma\sqrt{T-t} = \frac{\ln(S/K) + (r - \frac{\sigma^2}{2})(T-t)}{\sigma\sqrt{T-t}}

where:

  • d1d_1: first standardized term
  • σ\sigma: volatility
  • T−tT-t: time to expiration
  • SS: current stock price
  • KK: strike price
  • rr: risk-free rate

Notice that d2d_2 differs from d1d_1 only in the sign of the σ2/2\sigma^2/2 term in the numerator. This sign change determines the probabilistic interpretation developed below. The relationship d2=d1−σT−td_2 = d_1 - \sigma\sqrt{T-t} shows that the two quantities differ by exactly one standard deviation of the log-return.

For a European put option, we can either solve the PDE with the put boundary condition P(S,T)=max⁡(K−S,0)P(S,T) = \max(K-S, 0), or use put-call parity. The result is:

P(S,t)=Ke−r(T−t)N(−d2)−S⋅N(−d1)P(S,t) = K e^{-r(T-t)} N(-d_2) - S \cdot N(-d_1)

where:

  • P(S,t)P(S,t): put option price
  • KK: strike price
  • rr: risk-free rate
  • T−tT-t: time to expiration
  • SS: current stock price
  • N(⋅)N(\cdot): cumulative standard normal distribution function
  • d1,d2d_1, d_2: standardized moneyness terms

The put formula has a parallel structure to the call formula but with the terms reversed and the signs of the arguments to N(⋅)N(\cdot) flipped. This symmetry reflects the complementary nature of calls and puts: a call benefits when the stock rises above the strike, while a put benefits when the stock falls below the strike. The relationship between the two formulas is made precise by put-call parity.

These are the celebrated Black-Scholes formulas. Let's examine what each term means.

Anatomy of the Black-Scholes Formula

The call option formula C=SN(d1)−Ke−rτN(d2)C = SN(d_1) - Ke^{-r\tau}N(d_2) (where τ=T−t\tau = T-t) has a clear interpretation when viewed through the lens of risk-neutral valuation. To understand the formula, we must connect it to risk-neutral pricing, where a derivative's price is its discounted expected payoff:

C=e−rτEQ[max⁡(ST−K,0)]C = e^{-r\tau} \mathbb{E}^{\mathbb{Q}}[\max(S_T - K, 0)]

where:

  • CC: call option price
  • rr: risk-free rate
  • τ\tau: time to expiration
  • EQ\mathbb{E}^{\mathbb{Q}}: expectation under the risk-neutral measure Q\mathbb{Q}
  • STS_T: stock price at expiration
  • KK: strike price

This expectation says that we imagine a world where all investors are indifferent to risk, so the stock grows at the risk-free rate on average. In this risk-neutral world, we calculate the average payoff of the option and then discount it back to today. This procedure gives the correct arbitrage-free price even though the real world is not risk-neutral.

This expectation can be decomposed into two pieces:

C=e−rτEQ[ST⋅1ST>K]−e−rτK⋅PQ(ST>K)C = e^{-r\tau} \mathbb{E}^{\mathbb{Q}}[S_T \cdot \mathbf{1}_{S_T > K}] - e^{-r\tau} K \cdot \mathbb{P}^{\mathbb{Q}}(S_T > K)

where:

  • CC: call option price
  • rr: risk-free rate
  • τ\tau: time to expiration
  • STS_T: stock price at expiration
  • KK: strike price
  • 1ST>K\mathbf{1}_{S_T > K}: indicator function (1 if ST>KS_T > K, 0 otherwise)
  • PQ\mathbb{P}^{\mathbb{Q}}: probability under the risk-neutral measure

This decomposition separates the option's payoff into its two components: receiving the stock and paying the strike. The indicator function 1ST>K\mathbf{1}_{S_T > K} equals 1 when the option finishes in-the-money and 0 otherwise. The first term captures the expected value of receiving the stock in those scenarios where exercise occurs. The second term captures the expected cost of paying the strike price, again only in scenarios where exercise occurs.

The second term is straightforward: Ke−rτN(d2)K e^{-r\tau} N(d_2) is the present value of paying the strike, weighted by the risk-neutral probability N(d2)N(d_2) that the option finishes in-the-money. This term has a clean economic interpretation. You can think of it as the cost of a contingent payment: you will pay KK at expiration, but only if ST>KS_T > K. The probability of this event under risk-neutral dynamics is N(d2)N(d_2), and we discount the expected payment back to today at the risk-free rate.

The first term requires more care. S⋅N(d1)S \cdot N(d_1) is the discounted expected stock receipt restricted to exercise outcomes: e−rτEQ[ST1ST>K]e^{-r\tau}\mathbb{E}^{\mathbb{Q}}[S_T\mathbf{1}_{S_T>K}]. This is an unconditional expectation with an indicator, not an expectation conditional on exercise. If A={ST>K}A=\{S_T>K\}, then e−rτEQ[ST∣A]=SN(d1)/N(d2)e^{-r\tau}\mathbb{E}^{\mathbb{Q}}[S_T\mid A]=S N(d_1)/N(d_2) when the exercise probability is positive. High-stock-price outcomes receive more weight in the expected stock receipt than in the exercise probability. The next paragraph gives N(d1)N(d_1) its precise share-measure interpretation.

Technically, N(d1)N(d_1) is the probability that ST>KS_T > K under a different probability measure, sometimes called the stock measure or share measure. This alternative measure reweights outcomes according to the stock price, giving more weight to high-stock-price scenarios. Under this measure, the probability of exercise is higher than N(d2)N(d_2) because we are overweighting exactly those outcomes where exercise occurs. The difference between N(d1)N(d_1) and N(d2)N(d_2) captures this reweighting effect.

VisualizationOut [3]
CollapseExpand
Line chart showing N(d1) and N(d2) as functions of stock price from 70 to 130. The solid N(d1) curve is consistently above the dashed N(d2) curve, with a shaded region between them highlighting the measure difference and reference lines at a probability of 0.5 and the 100-dollar strike.
The risk-neutral probability $N(d_2)$ and the share-measure probability $N(d_1)$ as functions of moneyness. Both probabilities increase with moneyness, but $N(d_1)$ is always higher, which reflects the correlation between high stock prices and exercise events.

The Role of Each Parameter

The five inputs to the Black-Scholes formula each affect option prices in intuitive ways. Understanding these relationships builds intuition for how options behave and why traders care about each parameter.

  • Stock price (SS): Higher stock prices increase call values and decrease put values. This is the most direct relationship: a call gives you the right to buy at KK, so the higher SS is relative to KK, the more valuable that right. If the stock is already trading at $120 and your strike is $100, the option has $20 of intrinsic value plus whatever time value remains. Mathematically, the stock price enters the formula directly in the first term and indirectly through d1d_1 and d2d_2.

  • Strike price (KK): Higher strikes decrease call values and increase put values when the other inputs are fixed. A call has a positive expiry payoff only when the stock finishes above its strike. For example, calls struck at \100andand$110havedifferentexercisethresholds.Apurchasedcall′sprofitalsodependsonitspremiumandfinancing;ignoringfinancing,expirybreak−evenisthestrikeplusthepremium.Thestrikeentersboththediscountedpaymentandthelog−moneynessinhave different exercise thresholds. A purchased call's profit also depends on its premium and financing; ignoring financing, expiry break-even is the strike plus the premium. The strike enters both the discounted payment and the log-moneyness ind_1andandd_2$.

  • Time to expiration (τ=T−t\tau = T-t): More remaining time often raises an option's value, but the effect depends on the option type and inputs. A European put can fall in value as remaining maturity increases, even when interest rates are positive. Near expiration, at-the-money options can experience especially rapid time decay. Theta captures this local calendar-time effect with other inputs fixed.

  • Risk-free rate (rr): Higher rates increase call values and decrease put values. The intuition is that buying a call is like a leveraged position in the stock. You get stock exposure while keeping your capital earning interest elsewhere. Higher rates make this implicit financing benefit more useful. Additionally, higher rates reduce the present value of the strike payment, making it cheaper in today's dollars to acquire the stock at expiration.

  • Volatility (σ\sigma): Higher volatility increases both call and put values with the other inputs fixed. Under the model's pricing measure, changing volatility leaves the terminal stock-price mean SerτSe^{r\tau} unchanged and changes the dispersion of outcomes. The convex vanilla payoffs benefit from that extra dispersion: a call struck at \100payspays$20ifthestockfinishesatif the stock finishes at$120andzeroifitfinishesatand zero if it finishes at$80.Thesearepayoffexamples,notprobabilitiesassignedtoexactendpoints.Greatervolatilitydoesnotmakeeveryupper−taileventmorelikely.Atverylowvolatilitythecallapproaches. These are payoff examples, not probabilities assigned to exact endpoints. Greater volatility does not make every upper-tail event more likely. At very low volatility the call approaches \max(S-Ke^{-r\tau},0)$, so its value still depends on carry and remaining maturity.

Volatility as the Key Unknown

The stock price is observed, while the strike and expiration are contract terms. An appropriate pricing rate or discount curve must be selected from market data and matched to the currency, maturity and compounding convention. Volatility remains a central modeling challenge: future realized volatility must be forecast, while implied volatility can be calibrated from an admissible market premium. We'll return to implied volatility and the volatility smile in a later chapter.

Understanding d1d_1 and d2d_2

The quantities d1d_1 and d2d_2 are standardized measures of "moneyness," expressing how far in- or out-of-the-money the option is, adjusted for time and volatility. These quantities serve as the arguments to the cumulative normal distribution function, converting the lognormal distribution of stock prices into a tractable form.

Consider d2d_2 first:

d2=ln⁡(S/K)+(r−σ22)τστd_2 = \frac{\ln(S/K) + (r - \frac{\sigma^2}{2})\tau}{\sigma\sqrt{\tau}}

where:

  • SS: stock price
  • KK: strike price
  • rr: risk-free rate
  • σ\sigma: volatility
  • τ\tau: time to expiration

To understand d2d_2, we need to recall how the stock price evolves under geometric Brownian motion. The numerator ln⁡(S/K)+(r−σ22)τ\ln(S/K) + (r - \frac{\sigma^2}{2})\tau is the expected log-return of the stock under the risk-neutral measure, relative to the strike. The term r−σ2/2r - \sigma^2/2 appears rather than just rr because of the difference between arithmetic and geometric means. When a variable follows geometric Brownian motion with drift μ\mu, its expected logarithm grows at rate μ−σ2/2\mu - \sigma^2/2, not μ\mu. This correction factor, sometimes called the Itô correction or convexity adjustment, arises from the nonlinear relationship between a variable and its logarithm.

Recall that under geometric Brownian motion with drift rr, the expected log-price is:

E[ln⁡ST]=ln⁡S+(r−σ22)τ\mathbb{E}[\ln S_T] = \ln S + (r - \frac{\sigma^2}{2})\tau

where:

  • E[ln⁡ST]\mathbb{E}[\ln S_T]: expected log stock price at time TT
  • ln⁡S\ln S: log of current stock price
  • rr: risk-free rate
  • σ\sigma: volatility
  • τ\tau: time to expiration

So the numerator equals E[ln⁡ST]−ln⁡K=E[ln⁡(ST/K)]\mathbb{E}[\ln S_T] - \ln K = \mathbb{E}[\ln(S_T/K)]. This is the expected value of the log of the ratio of the terminal stock price to the strike. When this is positive, the stock is expected to end up above the strike on average. The denominator στ\sigma\sqrt{\tau} is the standard deviation of this log-return. The volatility of the log-price after time τ\tau is στ\sigma\sqrt{\tau}, which reflects the diffusion of prices over time. Thus d2d_2 measures how many standard deviations the expected log-price exceeds the log-strike, which is exactly the input you'd need to find P(ST>K)\mathbb{P}(S_T > K) using the normal distribution.

The quantity d1d_1 exceeds d2d_2 by στ\sigma\sqrt{\tau}. Completing the square in the lognormal density shows that EQ[ST1{ST>K}]=SerτN(d1)\mathbb{E}^{\mathbb Q}[S_T\mathbf1_{\{S_T>K\}}]=Se^{r\tau}N(d_1). This is the stock receipt weighted across all outcomes, with zero contribution when exercise does not occur. To obtain the expectation conditional on exercise, divide by N(d2)N(d_2) when that probability is positive.

The technical explanation involves a change of measure: for this non-dividend stock, N(d1)N(d_1) is the probability of the call event ST>KS_T>K under the stock-numeraire or share measure. The density change weights outcomes by the terminal stock price, increasing the probability of this upper-tail event. It decreases the probability of the complementary lower-tail event ST<KS_T<K; the comparison is not the same for put exercise.

Put-Call Parity Revisited

As we learned when studying option basics, put-call parity is a fundamental relationship linking European call and put prices:

C−P=S−Ke−rτC - P = S - Ke^{-r\tau}

where:

  • CC: call option price
  • PP: put option price
  • SS: stock price
  • KK: strike price
  • rr: risk-free rate
  • τ\tau: time to expiration

This equality does not require the Black-Scholes stock-price distribution. It follows from matching European calls and puts on a non-dividend stock under the stated frictionless trading and financing assumptions. The long-call, short-put portfolio pays ST−KS_T-K. Buying a share and borrowing Ke−rτKe^{-r\tau} today, with KK repaid at expiration, has the same payoff. No arbitrage therefore equates their current values.

Let's verify that the Black-Scholes formulas satisfy put-call parity. This verification serves two purposes: it confirms that our formulas are internally consistent, and it demonstrates the elegant symmetry properties of the normal distribution.

Starting with the Black-Scholes call and put formulas:

C=SN(d1)−Ke−rτN(d2)P=Ke−rτN(−d2)−SN(−d1)\begin{aligned} C &= S N(d_1) - K e^{-r\tau} N(d_2) \\ P &= K e^{-r\tau} N(-d_2) - S N(-d_1) \end{aligned}

where:

  • C,PC, P: call and put option prices
  • SS: stock price
  • KK: strike price
  • rr: risk-free rate
  • τ\tau: time to expiration
  • N(⋅)N(\cdot): cumulative standard normal distribution
  • d1,d2d_1, d_2: moneyness terms

We compute the difference C−PC - P to verify the relationship. The key mathematical fact we will use is the symmetry of the standard normal distribution: N(x)+N(−x)=1N(x) + N(-x) = 1 for any value of xx. This follows from the fact that the normal distribution is symmetric around zero, so the probability of being less than xx plus the probability of being greater than xx (which equals the probability of being less than −x-x) must sum to one.

C−P=[SN(d1)−Ke−rτN(d2)]−[Ke−rτN(−d2)−SN(−d1)](substitute formulas)=S[N(d1)+N(−d1)]−Ke−rτ[N(d2)+N(−d2)](group terms)=S⋅1−Ke−rτ⋅1(symmetry: N(x)+N(−x)=1)=S−Ke−rτ(simplify)\begin{aligned} C - P &= [S N(d_1) - K e^{-r\tau} N(d_2)] - [K e^{-r\tau} N(-d_2) - S N(-d_1)] && \text{(substitute formulas)} \\ &= S [N(d_1) + N(-d_1)] - K e^{-r\tau} [N(d_2) + N(-d_2)] && \text{(group terms)} \\ &= S \cdot 1 - K e^{-r\tau} \cdot 1 && \text{(symmetry: } N(x) + N(-x) = 1\text{)} \\ &= S - K e^{-r\tau} && \text{(simplify)} \end{aligned}

where:

  • CC: call price
  • PP: put price
  • SS: stock price
  • KK: strike price
  • rr: risk-free rate
  • τ\tau: time to expiration

The Black-Scholes formulas are internally consistent and satisfy the no-arbitrage constraint of put-call parity. This verification is more than a mathematical exercise. It confirms that the formulas respect the fundamental arbitrage relationships that must hold in any well-functioning market. Any pricing model, no matter how sophisticated, must satisfy put-call parity. If a proposed option pricing formula violated this relationship, we would know immediately that it contains an error.

VisualizationOut [4]
CollapseExpand
Line chart with two overlapping lines: C minus P from Black-Scholes as a solid curve and the forward value S minus K times exp(-rT) as a dashed curve. The lines lie exactly on top of each other across stock prices from 70 to 130, confirming put-call parity.
Comparison of the difference between call and put prices and the forward value $S - Ke^{-rT}$. The solid and dashed curves overlap perfectly, confirming that the Black-Scholes formulas satisfy the no-arbitrage put-call parity relationship.

Implementing the Black-Scholes Formula

Let's implement the Black-Scholes formula in Python and explore its behavior. These educational functions use scalar inputs with S,K,σ>0S,K,\sigma>0 and positive remaining time for the pre-expiry formulas, with a separate expiry-payoff branch. They assume finite, numerically usable inputs and are not general-range pricing routines. The validator explicitly rejects zero volatility, which would require a separate deterministic-limit formula. Negative remaining maturity is rejected; zero remaining maturity returns the expiry payoff.

PythonIn [5]
CollapseExpand
import numpy as np
from scipy.stats import norm


def validate_bs_inputs(S, K, T, r, sigma, option_type="call", q=0.0):
    """Validate this chapter's finite scalar educational pricing domain.

    S, K and sigma must be positive; remaining maturity T may be zero.
    Rates r and continuous yield q may have either sign.
    Zero volatility is excluded, rather than evaluated through a singular formula.
    Numeric inputs must be representable as finite Python floats.
    """
    from numbers import Real

    values = (S, K, T, r, sigma, q)
    if not all(isinstance(value, Real) for value in values):
        raise ValueError("Pricing inputs must be finite real scalars")
    try:
        S, K, T, r, sigma, q = map(float, values)
    except (OverflowError, TypeError, ValueError) as error:
        raise ValueError("Pricing inputs must be finite real scalars") from error
    if not all(np.isfinite(value) for value in (S, K, T, r, sigma, q)):
        raise ValueError("Pricing inputs must be finite real scalars")
    if S <= 0 or K <= 0 or sigma <= 0 or T < 0:
        raise ValueError("S, K and sigma must be positive; T must be nonnegative")
    if not isinstance(option_type, str) or option_type not in ("call", "put"):
        raise ValueError("option_type must be 'call' or 'put'")
    return S, K, T, r, sigma, q


def black_scholes_call(S, K, T, r, sigma):
    """
    Calculate Black-Scholes price for a European call option.

    Parameters:
        S: Current stock price
        K: Strike price
        T: Time to expiration (in years)
        r: Risk-free interest rate (annualized)
        sigma: Volatility (annualized)

    Returns:
        Call option price

    Inputs are finite real scalars with S,K,sigma>0 and T>=0; T=0
    returns the expiry payoff. The implementation assumes numerically usable
    intermediates and does not support arbitrary numerical ranges.
    """
    S, K, T, r, sigma, _ = validate_bs_inputs(S, K, T, r, sigma)
    if T == 0:
        return max(S - K, 0)  # At expiration, return intrinsic value

    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)

    call_price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    return call_price


def black_scholes_put(S, K, T, r, sigma):
    """
    Calculate a scalar European put price for finite inputs with S,K,sigma>0.
    T is nonnegative remaining maturity; T=0 returns the expiry payoff.
    This educational implementation assumes numerically usable intermediates.
    """
    S, K, T, r, sigma, _ = validate_bs_inputs(S, K, T, r, sigma, "put")
    if T == 0:
        return max(K - S, 0)

    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)

    put_price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
    return put_price

Now let's calculate option prices for a specific example:

PythonIn [6]
CollapseExpand
# Example parameters
S = 100  # Current stock price: $100
K = 105  # Strike price: $105
T = 0.5  # Time to expiration: 6 months
r = 0.05  # Risk-free rate: 5%
sigma = 0.20  # Volatility: 20%

call_price = black_scholes_call(S, K, T, r, sigma)
put_price = black_scholes_put(S, K, T, r, sigma)
ConsoleOut [7]
CollapseExpand
Black-Scholes Option Pricing Example
========================================
Stock Price (S):     $100.00
Strike Price (K):    $105.00
Time to Expiry (T):  0.50 years (6 months)
Risk-free Rate (r):  5.0%
Volatility (σ):      20.0%
----------------------------------------
Call Option Price:   $4.5817
Put Option Price:    $6.9892

The call option on this slightly out-of-the-money stock has a lower value than the put, which holds intrinsic value. Let's verify put-call parity holds:

PythonIn [8]
CollapseExpand
# Verify put-call parity: C - P = S - K*exp(-rT)
lhs = call_price - put_price
rhs = S - K * np.exp(-r * T)
parity_difference = abs(lhs - rhs)
ConsoleOut [9]
CollapseExpand
Put-Call Parity Verification
========================================
C - P = -2.4075
S - K*exp(-rT) = -2.4075
Difference: 0.00e+00
Put-call parity holds

At these example inputs, the implementation agrees with put-call parity to floating-point precision.

Examining the Intermediate Calculations

Understanding the intermediate values d1d_1 and d2d_2 helps build intuition for how the formula works:

PythonIn [10]
CollapseExpand
def compute_d1_d2(S, K, T, r, sigma):
    """Compute d1/d2 for finite scalar S,K,T,sigma>0 and finite r."""
    S, K, T, r, sigma, _ = validate_bs_inputs(S, K, T, r, sigma)
    if T == 0:
        raise ValueError("d1 and d2 require positive remaining maturity")
    log_moneyness = np.log(S / K)
    d1_shift = (r + 0.5 * sigma**2) * T
    diffusion = sigma * np.sqrt(T)

    d1 = (log_moneyness + d1_shift) / diffusion
    d2 = d1 - diffusion

    return d1, d2, log_moneyness, d1_shift, diffusion


d1, d2, log_moneyness, d1_shift, diffusion = compute_d1_d2(S, K, T, r, sigma)
ConsoleOut [11]
CollapseExpand
Breakdown of d1 and d2 Calculations
=============================================
ln(S/K) = ln(100/105) = -0.0488
d1 numerator shift (r + σ²/2)T = 0.0350
Diffusion σ√T = 0.1414
---------------------------------------------
d1 = (ln(S/K) + shift) / diffusion = -0.0975
d2 = d1 - σ√T = -0.2389
---------------------------------------------
N(d1) = 0.4612 (probability under share measure)
N(d2) = 0.4056 (risk-neutral probability ITM)

The negative d2d_2 value tells us there's less than a 50% risk-neutral probability that this option finishes in-the-money. The value of N(d2)N(d_2) calculated above represents the precise probability of the stock price exceeding the strike at expiration under the risk-neutral measure.

Key Parameters

The key parameters for the Black-Scholes implementation are:

  • SS: Current stock price. Higher prices increase call values and decrease put values.
  • KK: Strike price. The reference price for the option's payoff.
  • TT: Time to expiration in years. Longer times generally increase option values.
  • rr: Risk-free interest rate (annualized). Higher rates favor calls over puts.
  • σ\sigma: Volatility (annualized). Controls the dispersion of terminal stock prices; with the other inputs fixed, higher volatility increases both call and put values.

Option Price Sensitivity to Inputs

Let's visualize how option prices change with stock price, volatility and remaining maturity, holding the other inputs fixed. These examples build intuition for the Greeks introduced later in this chapter.

PythonIn [12]
CollapseExpand
# Calculate price sensitivity to spot price
spot_range = np.linspace(70, 130, 100)
calls_by_spot = [black_scholes_call(s, K, T, r, sigma) for s in spot_range]
puts_by_spot = [black_scholes_put(s, K, T, r, sigma) for s in spot_range]
VisualizationOut [13]
CollapseExpand
Line chart showing call price increasing and put price decreasing as stock price rises from 70 to 130.
Call and put option prices as a function of the underlying stock price. The call value increases with stock price while the put value decreases. Both curves show characteristic convexity near the strike price.

The curves show the characteristic "hockey stick" shape approaching expiration, but smoothed by time value. Notice how both options have positive value even when out-of-the-money. This is the time value component.

PythonIn [14]
CollapseExpand
# Calculate price sensitivity to volatility
vol_range = np.linspace(0.05, 0.60, 100)
calls_by_vol = [black_scholes_call(S, K, T, r, v) for v in vol_range]
puts_by_vol = [black_scholes_put(S, K, T, r, v) for v in vol_range]
VisualizationOut [15]
CollapseExpand
Line chart showing both call and put prices increasing as volatility rises from 5% to 60%.
Call and put option prices versus volatility with the other inputs fixed. The prices rise strictly in this nondegenerate model. A quote strictly inside the model's attainable price range has one finite positive implied volatility; strict monotonicity alone does not guarantee a solution for every quote.

With S,K,τ>0S,K,\tau>0 and the rate fixed, the call price approaches max⁡(S−Ke−rτ,0)\max(S-Ke^{-r\tau},0) as volatility tends to zero and approaches SS as volatility increases without bound. Thus a price strictly between those limits has one finite positive implied volatility. For a put, the corresponding open interval is between max⁡(Ke−rτ−S,0)\max(Ke^{-r\tau}-S,0) and Ke−rτKe^{-r\tau}. At a boundary, outside these intervals, or at expiry, a finite positive implied volatility is not guaranteed. The rate must also be selected using an appropriate discount curve and convention.

PythonIn [16]
CollapseExpand
# Calculate price sensitivity to time
time_range = np.linspace(0.01, 1.0, 100)
calls_by_time = [black_scholes_call(S, K, t, r, sigma) for t in time_range]
puts_by_time = [black_scholes_put(S, K, t, r, sigma) for t in time_range]
VisualizationOut [17]
CollapseExpand
Line chart of call and put prices over 1 year to 0.01 years of remaining maturity, with the time axis reversed. The call declines and the put has a slight near-expiry upturn.
Call and put option prices versus remaining time to expiration. Moving left to right toward expiration, the call declines while the put rises slightly near expiration. Both converge to their intrinsic payoffs as remaining time tends to zero; the approach need not be monotonic.

In this example, the call falls as expiration approaches, while the put rises slightly near expiration. Both prices converge to their intrinsic payoffs as remaining maturity tends to zero, but not necessarily monotonically. Theta measures the local calendar-time change with other inputs held fixed.

VisualizationOut [18]
CollapseExpand
3D surface plot of call option price as a function of stock price (80 to 120) and time to expiration (0.24 to 12 months). The surface rises with both stock price and time, with the highest values at high stock prices and long maturities.
Call option prices across stock price and time to expiration. Prices rise as the stock moves further above the strike and are higher at longer maturities, while values near and below the strike fall toward intrinsic value as expiration approaches.

Introduction to the Greeks

The Greeks are partial derivatives of the option price with respect to various inputs. They quantify how sensitive an option's model price is to small changes in those inputs. Understanding the Greeks is essential for risk management and hedging. Each Greek measures a different dimension of local, model-based sensitivity; this set does not capture every risk, including model misspecification or liquidity risk.

The Greeks derive their importance from the dynamic nature of hedging. As we learned when studying the derivation of the Black-Scholes PDE, perfect replication within that model requires continuous adjustment of a hedge portfolio. Delta gives the model's stock hedge ratio, while the other Greeks help assess how that hedge and the option value respond as inputs change. These sensitivities do not eliminate errors from discrete rebalancing or departures from the model's assumptions.

The Greeks

The Greeks are usually named after Greek letters and measure the sensitivity of option prices to changes in underlying parameters. The five primary Greeks are Delta, Gamma, Theta, Vega (whose name is not a Greek letter), and Rho.

Delta: Sensitivity to Stock Price

Delta (Δ\Delta) measures the local rate of change of the option price with respect to the stock price, holding the other inputs fixed. Multiplying delta by a stock-price change gives a first-order estimate of the option-price change, not an exact repricing for a finite $1 move. Delta answers the practical question: if the stock moves a little, how much does your option position change in value?

Δcall=∂C∂S=N(d1)\Delta_{\text{call}} = \frac{\partial C}{\partial S} = N(d_1)

where:

  • Δcall\Delta_{\text{call}}: delta of the call option
  • CC: call option price
  • SS: stock price
  • N(d1)N(d_1): cumulative normal distribution value at d1d_1

The result that call delta equals N(d1)N(d_1) comes directly from differentiating the Black-Scholes formula. The derivative of the first term S⋅N(d1)S \cdot N(d_1) with respect to SS is not simply N(d1)N(d_1) because d1d_1 itself depends on SS. However, when we carefully apply the chain rule, the additional terms cancel out, leaving just N(d1)N(d_1). This cancellation is not coincidental; it reflects a deep property of the Black-Scholes formula related to the self-financing nature of the replicating portfolio.

Δput=∂P∂S=N(d1)−1=−N(−d1)\begin{aligned} \Delta_{\text{put}} &= \frac{\partial P}{\partial S} \\ &= N(d_1) - 1 \\ &= -N(-d_1) \end{aligned}

where:

  • Δput\Delta_{\text{put}}: delta of the put option
  • PP: put option price
  • SS: stock price
  • N(d1)N(d_1): cumulative normal distribution value at d1d_1
  • N(−d1)N(-d_1): cumulative normal distribution value at −d1-d_1

Call deltas range from 0 to 1, while put deltas range from -1 to 0 in this non-dividend model. A spot-at-the-money call often has delta near 0.5 for short remaining maturity and modest carry, but its exact delta is N((r/σ+σ/2)τ)N((r/\sigma+\sigma/2)\sqrt{\tau}). Delta gives a first-order estimate for a small stock move. A deep in-the-money call approaches delta 1, while a deep out-of-the-money call approaches delta 0.

Delta also has an interpretation as a hedge ratio: to hedge a short call position, you should hold Δ\Delta shares of stock. If you sell a call with delta 0.5, you need to buy 0.5 shares to neutralize your exposure to small stock price movements. This hedge ratio must be continuously updated as the stock price moves and as time passes, which is why delta hedging is dynamic rather than static.

Gamma: Sensitivity of Delta to Stock Price

Gamma (Γ\Gamma) measures the local rate of change of delta with respect to the stock price, holding the other inputs fixed. Multiplying gamma by a small stock-price change approximates the change in delta. This second-order sensitivity helps assess how stable the delta hedge will be. High gamma means that even small moves in the stock price can significantly change the delta, requiring frequent rebalancing of the hedge.

Γ=∂2V∂S2=N′(d1)SσT−t\Gamma = \frac{\partial^2 V}{\partial S^2} = \frac{N'(d_1)}{S \sigma \sqrt{T-t}}

where:

  • Γ\Gamma: gamma of the option
  • VV: option price (call or put)
  • SS: stock price
  • N′(d1)N'(d_1): standard normal probability density at d1d_1
  • σ\sigma: volatility
  • T−tT-t: time to expiration

The function N′(x)=e−x2/2/2πN'(x)=e^{-x^2/2}/\sqrt{2\pi} is the standard normal probability density. Gamma measures the stock-price derivative of call delta N(d1)N(d_1), which is the call exercise probability under the share measure. It is not the derivative of the risk-neutral exercise probability N(d2)N(d_2).

Gamma is the same for calls and puts with the same strike and expiration. This equality follows from put-call parity: since C−P=S−Ke−rτC - P = S - Ke^{-r\tau}, and the right-hand side is linear in SS, the second derivative with respect to SS must be identical for calls and puts.

High gamma means delta changes rapidly with the stock price, requiring frequent hedge rebalancing. As expiration approaches, gamma becomes concentrated near the money, but its exact maximum depends on the variable being changed. At fixed S,τ,r,σS,\tau,r,\sigma, gamma peaks across strikes at K=Sexp⁡((r+σ2/2)τ)K=S\exp((r+\sigma^2/2)\tau). At fixed K,τ,r,σK,\tau,r,\sigma, its peak across stock prices is S=Kexp⁡(−(r+3σ2/2)τ)S=K\exp(-(r+3\sigma^2/2)\tau). Long gamma gives positive local price curvature; total profit also depends on time decay, financing and the trading strategy.

Theta: Sensitivity to Time

Theta (Θ\Theta) measures the local rate of change of the option price as calendar time tt advances, holding the expiration date TT and the other inputs fixed. Since remaining maturity is T−tT-t, this is the negative of the derivative with respect to remaining maturity. Theta can have either sign: a negative value indicates time decay, while a positive value indicates a local increase in price as time passes. With time measured in years, the formula below gives theta per year.

Θcall=∂C∂t=−SN′(d1)σ2T−t−rKe−r(T−t)N(d2)\Theta_{\text{call}} = \frac{\partial C}{\partial t} = -\frac{S N'(d_1) \sigma}{2\sqrt{T-t}} - rKe^{-r(T-t)}N(d_2)

where:

  • Θcall\Theta_{\text{call}}: theta of the call option
  • SS: stock price
  • N′(d1)N'(d_1): standard normal PDF at d1d_1
  • σ\sigma: volatility
  • T−tT-t: time to expiration
  • rr: risk-free rate
  • KK: strike price
  • N(d2)N(d_2): cumulative normal CDF at d2d_2

The formula consists of two components, each with a distinct economic interpretation:

  • −SN′(d1)σ2T−t-\frac{S N'(d_1) \sigma}{2\sqrt{T-t}}: Represents the erosion of value due to the resolution of uncertainty (time decay at fixed volatility). As time passes, there is less time for favorable price movements to occur. This term is always negative, which reflects the fact that options lose optionality value over time.
  • −rKe−r(T−t)N(d2)- rKe^{-r(T-t)}N(d_2): Represents the financing contribution from deferring the strike payment. For positive rates, the call's deferral benefit shrinks as expiration approaches. This contribution vanishes at zero rates and reverses sign at negative rates. In put theta, the financing term has the opposite sign because puts involve receiving rather than paying the strike.

Theta is often negative for long option positions, but time decay is not universal. A sufficiently deep in-the-money European put can have positive theta when interest rates are positive, because receiving the strike sooner can outweigh the loss of optionality. Near expiration, at-the-money options can have especially large negative theta, making time decay a practical concern for their holders.

The Black-Scholes PDE links theta and gamma through Θ+12σ2S2Γ=r(V−SΔ)\Theta + \tfrac{1}{2}\sigma^2 S^2\Gamma = r(V-S\Delta), where VV is the option value. The right-hand side accounts for financing the delta-hedged position. Positive gamma therefore does not, by itself, force theta to be negative; the option value, delta, stock price, and interest rate also enter the relationship.

Vega: Sensitivity to Volatility

Vega (ν\nu or V\mathcal{V}) is the local derivative of option value with respect to volatility expressed as a decimal. Despite being called "vega," this Greek is not named after an actual Greek letter, but the convention is so established that the name persists. Vega is useful when a position expresses a view on volatility. Future realized volatility must be estimated, while implied volatility can be inferred from an option's quoted market price when that price lies within the model's admissible range.

ν=∂V∂σ=ST−t⋅N′(d1)\nu = \frac{\partial V}{\partial \sigma} = S \sqrt{T-t} \cdot N'(d_1)

where:

  • ν\nu: vega of the option
  • VV: option price
  • SS: stock price
  • T−tT-t: time to expiration
  • N′(d1)N'(d_1): standard normal PDF at d1d_1

A change in decimal volatility of 0.010.01, such as 20%20\% to 21%21\%, is one percentage point. Traders commonly quote vega as the raw derivative divided by 100100. Multiplying that quotation by a one-percentage-point change gives a first-order price estimate, not an exact finite-change gain.

Vega is the same for calls and puts and is positive in the stated pre-expiry domain: S>0S>0, T−t>0T-t>0 and N′(d1)>0N'(d_1)>0. Thus a small volatility increase raises both vanilla option prices with the other inputs fixed.

Vega is often concentrated near the money, but the location of its maximum depends on which inputs are held fixed. At fixed stock price, remaining maturity, interest rate and volatility, it peaks across strikes at d1=0d_1=0, or K=Sexp⁡((r+σ2/2)(T−t))K=S\exp((r+\sigma^2/2)(T-t)), not necessarily at K=SK=S. Increasing maturity raises the T−t\sqrt{T-t} factor but also changes N′(d1)N'(d_1), so vega need not increase over every maturity interval.

Trading volatility can involve exposure to changes in implied volatility or to differences between realized and implied volatility. The examples here isolate vega exposure, with the other inputs held fixed. For the non-dividend-paying European call and put here, with S,K>0S,K>0, positive volatility and time remaining before expiry, a long option has positive vega; holding the other inputs fixed, a rise in implied volatility raises its model value. A short option has the opposite exposure. Total profit also depends on stock moves, time decay, financing and other changes.

Rho: Sensitivity to Interest Rate

Rho (ρ\rho) is the local derivative of option price with respect to the interest rate expressed as a decimal. Its contribution to risk depends on the size of the rate change and the contract's maturity. Comparisons with other Greeks require specified input changes because the derivatives use different units.

ρcall=∂C∂r=K(T−t)e−r(T−t)N(d2)\rho_{\text{call}} = \frac{\partial C}{\partial r} = K(T-t)e^{-r(T-t)}N(d_2)

where:

  • ρcall\rho_{\text{call}}: rho of the call option
  • KK: strike price
  • T−tT-t: time to expiration
  • rr: risk-free rate
  • N(d2)N(d_2): cumulative normal CDF at d2d_2

Call rho is positive because higher interest rates reduce the present value of the strike payment while leaving the current stock price unchanged. A call holder benefits from this because they pay the strike in the future, and higher rates make that future payment cheaper in today's dollars.

ρput=∂P∂r=−K(T−t)e−r(T−t)N(−d2)\rho_{\text{put}} = \frac{\partial P}{\partial r} = -K(T-t)e^{-r(T-t)}N(-d_2)

where:

  • ρput\rho_{\text{put}}: rho of the put option
  • PP: put option price
  • KK: strike price
  • T−tT-t: time to expiration
  • rr: risk-free rate
  • N(−d2)N(-d_2): cumulative normal CDF at −d2-d_2

Put rho is negative because the put holder receives the strike at exercise, and a higher rate reduces its present value. Rho contains a remaining-maturity factor, but discounting and N(d2)N(d_2) also depend on maturity. Its magnitude need not grow proportionally or increase over every maturity interval.

Interest-rate sensitivity reflects the cost of carrying a hedged option position. Longer-dated equity options can be more sensitive to rate changes than near-term options, although the exact maturity dependence is not universal. Assess the exposure using a specified rate change and the position's rho.

Computing the Greeks

Let's implement and calculate the Greeks for our example option:

PythonIn [19]
CollapseExpand
from numbers import Real


def black_scholes_greeks(S, K, T, r, sigma, option_type="call"):
    """
    Calculate price and Greeks for a European option before expiration.

    S, K, T (remaining maturity in years) and sigma must be positive real
    finite scalars; r must be real and finite. All numeric inputs must be
    representable as finite Python floats. option_type is the scalar string
    'call' or 'put'.
    Returns annual and daily calendar-time theta, raw vega and vega per
    percentage point. Expired payoffs belong to the separate pricing functions.
    This educational float implementation rejects unusable or nonfinite
    intermediates/results with a numerical range ValueError; it is not an
    arbitrary-range pricer. Benign underflow to zero is allowed.
    """
    if not all(isinstance(value, Real) for value in (S, K, T, r, sigma)):
        raise ValueError("S, K, T, r and sigma must be real finite scalars")
    try:
        S, K, T, r, sigma = map(float, (S, K, T, r, sigma))
    except (OverflowError, TypeError, ValueError) as error:
        raise ValueError("S, K, T, r and sigma must be real finite scalars") from error
    if not all(np.isfinite(value) for value in (S, K, T, r, sigma)):
        raise ValueError("S, K, T, r and sigma must be real finite scalars")
    if S <= 0 or K <= 0 or T <= 0 or sigma <= 0:
        raise ValueError(
            "S, K, T and sigma must be strictly positive before expiration"
        )
    if not isinstance(option_type, str) or option_type not in ("call", "put"):
        raise ValueError("option_type must be 'call' or 'put'")

    try:
        with np.errstate(over="raise", divide="raise", invalid="raise", under="ignore"):
            sqrt_T = np.sqrt(T)
            d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * sqrt_T)
            d2 = d1 - sigma * sqrt_T

            # Standard normal PDF at d1
            n_d1 = norm.pdf(d1)

            # Common terms
            discount = np.exp(-r * T)
            if not all(np.isfinite(value) for value in (d1, d2, discount)):
                raise ValueError(
                    "Inputs exceed the numerical range of this implementation"
                )

            if option_type == "call":
                price = S * norm.cdf(d1) - K * discount * norm.cdf(d2)
                delta = norm.cdf(d1)
                theta = -S * n_d1 * sigma / (2 * sqrt_T) - r * K * discount * norm.cdf(
                    d2
                )
                rho = K * T * discount * norm.cdf(d2)
            else:
                price = K * discount * norm.cdf(-d2) - S * norm.cdf(-d1)
                delta = norm.cdf(d1) - 1  # Equivalent to -N(-d1)
                theta = -S * n_d1 * sigma / (2 * sqrt_T) + r * K * discount * norm.cdf(
                    -d2
                )
                rho = -K * T * discount * norm.cdf(-d2)

            # Gamma and Vega are the same for calls and puts
            gamma_denominator = S * sigma * sqrt_T
            if not np.isfinite(gamma_denominator) or gamma_denominator <= 0:
                raise ValueError(
                    "Inputs exceed the numerical range of this implementation"
                )
            gamma = n_d1 / gamma_denominator
            vega = S * sqrt_T * n_d1

            # Convert theta to daily and vega to per one percentage point of volatility
            theta_daily = theta / 365
            vega_percent = vega / 100

            greeks = {
                "price": price,
                "delta": delta,
                "gamma": gamma,
                "theta": theta,
                "theta_daily": theta_daily,
                "vega": vega,
                "vega_pct": vega_percent,
                "rho": rho,
            }
            if not all(np.isfinite(value) for value in greeks.values()):
                raise ValueError(
                    "Inputs exceed the numerical range of this implementation"
                )
    except (OverflowError, FloatingPointError, ZeroDivisionError) as error:
        raise ValueError(
            "Inputs exceed the numerical range of this implementation"
        ) from error
    return greeks


call_greeks = black_scholes_greeks(S, K, T, r, sigma, "call")
put_greeks = black_scholes_greeks(S, K, T, r, sigma, "put")
ConsoleOut [20]
CollapseExpand
Greeks for European Options
=======================================================
Greek        Call                 Put                 
-------------------------------------------------------
Price        $4.5817              $6.9892             
Delta        0.4612               -0.5388             
Gamma        0.0281               0.0281              
Theta (ann)  -7.6919              -2.5715             
Theta (day)  -0.0211              -0.0070             
Vega (/1pp)  0.2808               0.2808              
Rho          20.7672              -30.4366

Let's interpret these values:

ConsoleOut [21]
CollapseExpand

First-order estimates from the Greeks (other inputs held fixed):
-------------------------------------------------------
• If the stock rises $1, the call gains approximately $0.46
  and the put loses approximately $0.54
• Over one day, the call loses approximately $0.0211
• If volatility rises one percentage point (20% to 21%), the call gains approximately $0.2808
• Gamma of 0.0281 means delta changes ~0.03
  for each $1 move in the stock

Visualizing Delta Across Strikes

PythonIn [22]
CollapseExpand
# Calculate delta across strikes
strike_range = np.linspace(70, 130, 100)
call_deltas = []
put_deltas = []

for k in strike_range:
    cg = black_scholes_greeks(S, k, T, r, sigma, "call")
    pg = black_scholes_greeks(S, k, T, r, sigma, "put")
    call_deltas.append(cg["delta"])
    put_deltas.append(pg["delta"])
VisualizationOut [23]
CollapseExpand
Line chart showing call delta decreasing from near 1 toward 0 and put delta from near 0 toward -1 as strike increases from 70 to 130.
Call and put delta as a function of strike price. Deep in-the-money calls have delta near 1, while deep out-of-the-money calls have delta near 0. Put delta follows a parallel pattern shifted by -1.

The plot illustrates how delta varies across different strike prices. For deep in-the-money calls (low strikes), delta approaches 1, indicating the option moves tick-for-tick with the stock. For deep out-of-the-money calls (high strikes), delta approaches 0. This plot varies strike while keeping the stock price fixed. Gamma instead measures how delta changes with the stock price, holding strike and the other inputs fixed.

VisualizationOut [24]
CollapseExpand
Line chart showing gamma versus strike price for four remaining maturities: about 1 week, 3 months, 6 months, and 1 year. The shortest-maturity curve has a sharp peak near the spot price of 100, while longer-dated options have flatter, wider profiles.
Gamma across strike prices for options with different times to expiration. Near-expiration options exhibit dramatically higher gamma near the strike, which reflects the knife-edge nature of exercise decisions as expiration approaches.
VisualizationOut [25]
CollapseExpand
Heatmap of gamma sampled at stock prices from 80 to 120 and remaining maturities from 0.24 to 12 months. The strongest values occur near the 105-dollar strike at short maturities, with lower values farther from that region.
Gamma sensitivity across stock price and time to expiration. The concentration of high gamma values (dark red) for at-the-money options near expiration creates the 'gamma mountain,' indicating regions of highest hedging instability.
VisualizationOut [26]
CollapseExpand
Line chart of daily theta in dollars versus days to expiration from 0 to 365. Theta is most negative near zero days and approaches zero for longer-dated options, with an annotation highlighting the acceleration near expiration.
Theta (daily time decay) for at-the-money options as expiration approaches. The decay accelerates dramatically in the final weeks, illustrating why short-dated options are often described as 'melting ice cubes.

The next chapter covers the Greeks in detail, including their use in hedging strategies, portfolio risk management, and the dynamics of delta-hedged positions.

Extending to Dividend-Paying Stocks

The basic Black-Scholes formula assumes the stock pays no dividends. For stocks that pay a continuous dividend yield qq, we can modify the formula by replacing SS with Se−qτSe^{-q\tau}. The intuition behind this adjustment is that dividend payments reduce the effective growth rate of the stock price. An investor who holds the stock receives dividends, but an investor who holds a call option does not. The option holder misses out on this cash flow, making the option less valuable.

The modified call pricing formula becomes:

C=Se−qτN(d1)−Ke−rτN(d2)C = Se^{-q\tau}N(d_1) - Ke^{-r\tau}N(d_2)

where:

  • CC: call option price
  • SS: stock price
  • qq: continuous dividend yield
  • τ\tau: time to expiration
  • N(⋅)N(\cdot): cumulative standard normal CDF
  • KK: strike price
  • rr: risk-free rate

The factor e−qτe^{-q\tau} is the continuous-yield carry adjustment. Under the pricing measure, the ex-dividend stock price grows on average at rate r−qr-q, while the stock's dividend-reinvested total gains have expected return rr. This is a multiplicative adjustment, not a subtraction of the nominal dollars of dividends paid over the option's life.

The parameters d1d_1 and d2d_2 are modified as follows:

d1=ln⁡(S/K)+(r−q+σ22)τστd_1 = \frac{\ln(S/K) + (r - q + \frac{\sigma^2}{2})\tau}{\sigma\sqrt{\tau}}

where:

  • SS: stock price
  • KK: strike price
  • rr: risk-free rate
  • qq: dividend yield
  • σ\sigma: volatility
  • τ\tau: time to expiration

The key change is that r−qr - q replaces rr in the drift term. The effective growth rate of the stock under the risk-neutral measure is now the risk-free rate minus the dividend yield. This makes sense: dividends represent cash flowing out of the stock, reducing its expected appreciation rate.

d2=d1−στd_2 = d_1 - \sigma\sqrt{\tau}

where:

  • d1d_1: standardized moneyness term
  • σ\sigma: volatility
  • τ\tau: time to expiration

The relationship between d1d_1 and d2d_2 remains unchanged; they still differ by exactly στ\sigma\sqrt{\tau}.

The dividend yield reduces the call value and increases the put value. Intuitively, dividends represent cash flows that benefit stockholders but not call option holders (who don't receive dividends until they exercise). Put holders, conversely, benefit from dividends because dividends reduce the stock price, making it more likely that the put will finish in-the-money.

PythonIn [27]
CollapseExpand
def black_scholes_dividend(S, K, T, r, sigma, q, option_type="call"):
    """
    Scalar European pricing with continuous dividend yield q.

    Requires finite real inputs with S,K,sigma>0 and T>=0; r and q may
    have either sign. option_type must be call or put. T=0 gives the
    expiry payoff. Zero volatility is explicitly excluded. This educational
    implementation assumes numerically usable intermediates.
    """
    S, K, T, r, sigma, q = validate_bs_inputs(S, K, T, r, sigma, option_type, q)
    if T == 0:
        if option_type == "call":
            return max(S - K, 0)
        else:
            return max(K - S, 0)

    sqrt_T = np.sqrt(T)
    d1 = (np.log(S / K) + (r - q + 0.5 * sigma**2) * T) / (sigma * sqrt_T)
    d2 = d1 - sigma * sqrt_T

    if option_type == "call":
        price = S * np.exp(-q * T) * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    else:
        price = K * np.exp(-r * T) * norm.cdf(-d2) - S * np.exp(-q * T) * norm.cdf(-d1)

    return price


# Compare prices with and without dividend
q = 0.02  # 2% dividend yield
call_no_div = black_scholes_call(S, K, T, r, sigma)
call_with_div = black_scholes_dividend(S, K, T, r, sigma, q, "call")
put_no_div = black_scholes_put(S, K, T, r, sigma)
put_with_div = black_scholes_dividend(S, K, T, r, sigma, q, "put")
ConsoleOut [28]
CollapseExpand
Effect of Dividend Yield on Option Prices
==================================================
Dividend yield: 2.0%
--------------------------------------------------
Option          No Dividend     With Dividend  
Call            $4.5817         $4.1367        
Put             $6.9892         $7.5393        
--------------------------------------------------
Call reduction due to dividend: $0.4450
Put increase due to dividend: $0.5501

The output shows that the dividend yield reduces the call price and increases the put price. This occurs because the dividend drops the expected stock price at expiration, making the call less likely to finish in-the-money and the put more likely.

VisualizationOut [29]
CollapseExpand
Line chart showing call and put option prices versus strike price from 80 to 120. Solid lines represent no-dividend prices and dashed lines show prices with a 2% dividend yield. The dashed call curve sits below the solid call curve, while the dashed put curve sits above the solid put curve.
Effect of dividend yield on option prices across different strikes. Calls decrease in value with dividends (dashed versus solid call curve), while puts increase (dashed versus solid put curve). The effect is most pronounced for in-the-money calls.

Key Parameters

The key parameters for the Black-Scholes model with dividends are:

  • SS: Current stock price.
  • KK: Strike price.
  • TT: Time to expiration.
  • rr: Risk-free interest rate.
  • σ\sigma: Volatility.
  • qq: Continuous dividend yield. Represents cash flows paid to shareholders that option holders do not receive. Higher dividends decrease call values and increase put values.

Limitations of the Black-Scholes Model

While the Black-Scholes formula revolutionized option pricing and remains foundational, its assumptions limit its applicability in real markets.

Constant volatility is a restrictive modelling assumption. Empirical studies consistently show that volatility varies over time and exhibits clustering, with volatile periods tending to follow volatile periods. Implied volatilities from traded options also vary systematically with strike price (the volatility smile) and with time to expiration (the term structure of volatility). These patterns directly contradict the constant volatility assumption and require more sophisticated models to explain.

The assumption of geometric Brownian motion implies that log-returns are normally distributed. Observed log-return distributions often have heavier tails than a normal distribution. Many equity-index return samples also show negative skewness, although the sign and size of asymmetry depend on the asset, time horizon and sample. For a distribution with a finite third moment and nonzero variance, negative skewness means that the standardized third central moment is negative; it does not impose a universal ordering of positive and negative tail probabilities. These empirical features warn against relying on a constant-volatility lognormal model as a description of observed returns. They do not, by themselves, establish that a particular option is underpriced: that comparison depends on the volatility input, calibration and observed market premium.

The model assumes continuous trading with no transaction costs, allowing perfect delta hedging. In practice, transaction costs make continuous rebalancing impossible, and the discrete nature of trading introduces hedging errors. The model also assumes the ability to borrow and short-sell without restrictions at the risk-free rate, which may not hold for all market participants.

The displayed vanilla formulas price European exercise and do not generally include American early-exercise value. American contracts require an optimal-stopping method within the pricing framework. A non-dividend American call at nonnegative rates is a special case where early exercise gives no advantage and the European call formula applies. Path-dependent payoffs and multiple underlying assets also require methods suited to those contracts.

Despite these limitations, Black-Scholes is a useful benchmark for option pricing. Market participants often express or compare option values in implied-volatility terms. Depending on the market, options may be quoted in premium or volatility units; a pricing model suited to the contract translates between them. Understanding Black-Scholes deeply is essential before moving to more complex models.

Summary

The Black-Scholes formula for European option pricing is:

C=SN(d1)−Ke−rτN(d2)C = SN(d_1) - Ke^{-r\tau}N(d_2)

where:

  • CC: call option price
  • SS: stock price
  • N(⋅)N(\cdot): cumulative standard normal CDF
  • d1,d2d_1, d_2: standardized moneyness terms
  • KK: strike price
  • rr: risk-free interest rate
  • τ\tau: time to expiration
P=Ke−rτN(−d2)−SN(−d1)P = Ke^{-r\tau}N(-d_2) - SN(-d_1)

where:

  • PP: put option price
  • KK: strike price
  • rr: risk-free interest rate
  • τ\tau: time to expiration
  • N(⋅)N(\cdot): cumulative standard normal CDF
  • d1,d2d_1, d_2: standardized moneyness terms
  • SS: stock price

Key insights:

  • Solution from the PDE: The Black-Scholes formula arises from solving the Black-Scholes PDE (derived in the previous chapter) subject to the option's terminal payoff condition. The solution involves transforming the PDE to the heat equation and applying the risk-neutral valuation principle.

  • Probabilistic interpretation: For the European call, N(d2)N(d_2) is its risk-neutral exercise probability and N(d1)N(d_1) is its exercise probability under the share measure. The term SN(d1)SN(d_1) is the discounted expected stock receipt restricted to exercise outcomes.

  • Five inputs: The formula takes stock price, strike, remaining maturity, interest rate and volatility. Volatility must be forecast or inferred from a compatible market premium, and the pricing rate must be selected using suitable market conventions.

  • Monotonic relationships: Call prices increase with stock price, volatility, and interest rate, and decrease with strike price. Put prices exhibit the opposite relationships for stock price and rate. Both option types increase with volatility; the remaining-time effect is not universal for European puts.

  • The Greeks: Delta and Gamma describe stock-price sensitivity and curvature; Theta measures calendar-time sensitivity, Vega volatility sensitivity, and Rho interest-rate sensitivity. This list contains no strike derivative. The next chapter applies these measures to hedging and risk management.

  • Model limitations: Constant volatility, normally distributed log-returns, continuous trading, and European exercise only are assumptions that don't perfectly match reality. Understanding these limitations guides when to use more sophisticated models.

The Black-Scholes formula provides a foundation for studying option valuation and hedging under a tractable model. Delta hedging, implied volatility and risk-neutral pricing are tools we can carry into the models and methods that follow.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about the Black-Scholes formula and European option pricing.

Black-Scholes Formula and European Option Pricing

Question 1 of 80 of 8 completed
In the Black-Scholes call option formula C=SN(d1)−Ke−rTN(d2)C=SN(d_1)-Ke^{-rT}N(d_2), what does the term Ke−rTN(d2)Ke^{-rT}N(d_2) represent?
Track your reading progress

Sign in to mark sections as read and track your learning journey

Sign in →
Join the discussionAsk a question or share what you learned.

Comments

Add to the conversation

A question, a correction, or an example from your own work.

No comments yet. Be the first to share your thoughts!

A different angle
All writing
Quantitative Finance · Vol. 2

Implied Volatility and Volatility Smile

Compute implied volatility using Newton-Raphson and bisection methods. Examines volatility smile, skew patterns, and the VIX index with Python code.

54 min read
Quantitative Finance · Vol. 2

The Greeks and Option Risk Management: Delta, Gamma & More

Covers option Greeks: delta, gamma, theta, vega, and rho. Topics include sensitivity analysis, delta hedging, and portfolio risk management techniques.

59 min read
Quantitative Finance · Vol. 2

Black-Scholes PDE: Derivation & Delta Hedging Explained

Derive the Black-Scholes-Merton PDE with Itô's lemma, delta hedging, and no-arbitrage assumptions, then connect the equation to option pricing.

45 min read

About the author

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2025blackscholes-2, author = {Michael Brenndoerfer}, title = {Black-Scholes Formula: European Option Pricing & Greeks}, year = {2025}, url = {https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-10-24} }
APAAcademic
Michael Brenndoerfer (2025). Black-Scholes Formula: European Option Pricing & Greeks. Retrieved from https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks
MLAAcademic
Michael Brenndoerfer. "Black-Scholes Formula: European Option Pricing & Greeks." 2026. Web. October 24, 2026. <https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks>.
CHICAGOAcademic
Michael Brenndoerfer. "Black-Scholes Formula: European Option Pricing & Greeks." Accessed October 24, 2026. https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks.
HARVARDAcademic
Michael Brenndoerfer (2025) 'Black-Scholes Formula: European Option Pricing & Greeks'. Available at: https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks (Accessed: October 24, 2026).
SimpleBasic
Michael Brenndoerfer (2025). Black-Scholes Formula: European Option Pricing & Greeks. https://mbrenndoerfer.com/writing/black-scholes-formula-european-option-pricing-greeks
Newsletter

Stay up to date

Get new articles, book updates, and notes on AI and technology.

Unsubscribe at any time. Privacy policy