Skip to main content

No-Arbitrage and Binomial Option Pricing

A call might pay 20 at expiry, or it might pay nothing. What should it cost today? If stock and a bond can reproduce its payment in every possible state, the option must cost as much as that portfolio. A binomial tree restricts each next step to two states, making the pricing argument possible to work through node by node.

Financial Markets and Mathematical Modeling introduces option rights, expiry payoffs, and profit after the premium. All numbers below are hypothetical, amounts use one currency unit, and each option covers one share of a stock that pays no dividends.

Payoff, price, and arbitrage​

For strike KK and stock price STS_T at expiry, call and put payoffs are:

CT=max⁡(ST−K,0),PT=max⁡(K−ST,0).C_T=\max(S_T-K,0),\qquad P_T=\max(K-S_T,0).

The payoff depends on the expiry state; C0C_0 and P0P_0 are the prices paid today for those rights. European options permit exercise only at expiry. American options also permit early exercise.

An arbitrage is a strategy requiring no net investment, with no future loss in any state and a gain in at least one state with positive probability. Assume both stock-price states have positive probability and the relevant trades can be executed. The MIT OpenCourseWare options recitation derives replication pricing and put-call parity from the requirement that identical payoffs have identical costs. Otherwise, buying the cheaper portfolio and selling the dearer one leaves a certain surplus.

The argument allows borrowing and lending at the same risk-free rate, fractional positions in stock and options, and short selling. It ignores fees, taxes, bid–ask spreads, and margin constraints. These conditions make the arbitrage trades below feasible.

One period: buy half a share and borrow​

Set today's stock price to S0=100S_0=100. After one period it can only be Su=120S_u=120 or Sd=80S_d=80. The risk-free growth factor is R=1.05R=1.05: an investment of 1 becomes 1.05, a 5% rate for this period. A European call has strike K=100K=100.

Expiry stateStock priceCall payoff
Up12020
Down800

Replicate it with Δ\Delta shares and a risk-free bond worth B0B_0 today. The bond pays RB0RB_0 at expiry; B0<0B_0<0 means borrowing. Match both states:

120Δ+1.05B0=20,80Δ+1.05B0=0.\begin{aligned} 120\Delta+1.05B_0&=20,\\ 80\Delta+1.05B_0&=0. \end{aligned}

Subtracting gives 40Δ=2040\Delta=20, hence Δ=0.5\Delta=0.5. Substitution in the down-state equation gives:

B0=−401.05=−38.095238…,C0=ΔS0+B0=25021≈11.904762.B_0=\frac{-40}{1.05}=-38.095238\ldots,\qquad C_0=\Delta S_0+B_0=\frac{250}{21}\approx11.904762.

Buy half a share and borrow 38.095238, for a net cost of 11.904762. The loan requires repayment of 40 at expiry:

Expiry stateHalf-share valueLoan repaymentNet portfolio valueCall payoff
Up60−402020
Down40−4000

The portfolio matches both outcomes, so its cost fixes the option price. No estimate of the probability of an up move is needed.

If this European call trades at 14, sell one and establish the replicating portfolio. The initial surplus is 14−250/21=44/21≈2.09523814-250/21=44/21\approx2.095238. Invest it at the risk-free rate to receive 2.2 at expiry. The portfolio's payoff exactly cancels the liability on the written call, leaving a gain in both states. If the option trades below replication cost, reverse the trades: buy the option, sell the replicating portfolio short, and invest the difference. Amounts are displayed to six decimal places; calculations retain unrounded values.

Where the risk-neutral probability comes from​

For a general one-period tree, write u=Su/S0u=S_u/S_0 and d=Sd/S0d=S_d/S_0, with 0<d<u0<d<u. No-arbitrage between stock and the bond requires:

d<R<u.d<R<u.

If R≥uR\ge u, short the stock and invest the proceeds: after returning the stock, there is no loss in either state and a gain in the down state. If R≤dR\le d, borrowing to buy stock also produces an arbitrage. Strict inequalities give positive pricing weights to both states.

A portfolio replicating any terminal payments Vu,VdV_u,V_d has:

Δ=Vu−VdS0(u−d),B0=uVd−dVuR(u−d).\Delta=\frac{V_u-V_d}{S_0(u-d)},\qquad B_0=\frac{uV_d-dV_u}{R(u-d)}.

Substitute these into V0=ΔS0+B0V_0=\Delta S_0+B_0 and rearrange:

q=R−du−d,V0=qVu+(1−q)VdR.q=\frac{R-d}{u-d},\qquad V_0=\frac{qV_u+(1-q)V_d}{R}.

qq is the risk-neutral probability of an up move. It satisfies qu+(1−q)d=Rqu+(1-q)d=R: under these weights, the stock's average growth factor equals the risk-free growth factor. Here u=1.2u=1.2 and d=0.8d=0.8, so:

q=1.05−0.81.2−0.8=0.625,C0=0.625×20+0.375×01.05=25021≈11.904762.q=\frac{1.05-0.8}{1.2-0.8}=0.625,\qquad C_0=\frac{0.625\times20+0.375\times0}{1.05}=\frac{250}{21}\approx11.904762.

The 62.5% is a pricing weight obtained from replication, not a forecast of the actual frequency of up moves. The real probability pp is relevant to forecasting returns and risk. Averaging option payoffs under pp and discounting at the risk-free rate generally fails to reproduce the replication price. Risk-neutral valuation does not require investors to be indifferent to risk.

Put-call parity: check another price relation​

For European options on the same non-dividend-paying stock, with the same strike and expiry, compare a call plus a bond paying KK at expiry with a put plus one share. Both portfolios pay max⁡(ST,K)\max(S_T,K) at expiry, so:

C0+KR=P0+S0,C0−P0=S0−KR.C_0+\frac{K}{R}=P_0+S_0,\qquad C_0-P_0=S_0-\frac{K}{R}.

In the one-period example, the put pays 0 in the up state and 20 in the down state:

P0=0.625×0+0.375×201.05=7.142857….P_0=\frac{0.625\times0+0.375\times20}{1.05}=7.142857\ldots.
PortfolioCost todayUp-state expiry valueDown-state expiry value
Call + bond paying 100 at expiry250/21+2000/21=750/7≈107.142857250/21+2000/21=750/7\approx107.142857120100
Put + one share50/7+100=750/7≈107.14285750/7+100=750/7\approx107.142857120100

The price difference agrees too: C0−P0=100−100/1.05=100/21≈4.761905C_0-P_0=100-100/1.05=100/21\approx4.761905. Over multiple periods, replace K/RK/R with the present value of the strike at expiry. With a continuously compounded annual rate rr and maturity TT, this is Ke−rTKe^{-rT}. Dividends require an adjustment, and American options can be exercised at different times, so this European equality cannot be applied directly to them.

Multiple periods: work backward from expiry​

Cox, Ross, and Rubinstein's 1979 paper, Option Pricing: A Simplified Approach, appeared in Journal of Financial Economics 7(3), pages 229–263. Section 3 of the readable original paper extends replication to multiple periods; Section 6 addresses dividends and puts.

With fixed u,du,d, up then down and down then up reach the same stock price because ud=duud=du. The tree therefore recombines. After step ii with jj up moves, the stock price is:

Si,j=S0ujdi−j,j=0,…,i.S_{i,j}=S_0u^jd^{i-j},\qquad j=0,\ldots,i.

Fill the terminal layer with expiry payoffs, then work back one layer at a time. For a European put:

Pn,j=max⁡(K−Sn,j,0),Pi,j=qPi+1,j+1+(1−q)Pi+1,jR.P_{n,j}=\max(K-S_{n,j},0),\qquad P_{i,j}=\frac{qP_{i+1,j+1}+(1-q)P_{i+1,j}}{R}.

This is backward induction. At each node, replicate the option's two next-step values. On reaching the next node, rebalance the stock and bond holdings. The old portfolio's value funds the new one without additional cash: the strategy is self-financing. A portfolio bought once and never adjusted generally replicates only a one-period option.

American puts: test exercise at every node​

At each exercise node, an American option compares continuation value Hi,jH_{i,j} with immediate exercise value Ei,jE_{i,j}:

Hi,j=qPi+1,j+1A+(1−q)Pi+1,jAR,Ei,j=max⁡(K−Si,j,0),Pi,jA=max⁡(Hi,j,Ei,j).\begin{aligned} H_{i,j}&=\frac{qP^{\mathrm A}_{i+1,j+1}+(1-q)P^{\mathrm A}_{i+1,j}}{R},\\ E_{i,j}&=\max(K-S_{i,j},0),\\ P^{\mathrm A}_{i,j}&=\max(H_{i,j},E_{i,j}). \end{aligned}

The terminal layer still contains expiry payoffs. A finite tree tests exercise only on its dates, approximating an American option's continuous exercise opportunities. On the same tree, the American price is at least the European price, since the holder can always choose to wait until expiry.

Use a second, two-step example: S0=K=100S_0=K=100, T=1T=1 year, continuously compounded annual rate r=0.05r=0.05, and annual volatility parameter σ=0.20\sigma=0.20. Each step lasts half a year. The CRR choice is:

Δt=Tn,u=eσΔt,d=u−1,R=erΔt.\Delta t=\frac{T}{n},\qquad u=e^{\sigma\sqrt{\Delta t}},\qquad d=u^{-1},\qquad R=e^{r\Delta t}.

For n=2n=2, this gives u≈1.151910u\approx1.151910, d≈0.868123d\approx0.868123, R≈1.025315R\approx1.025315, and q≈0.553908q\approx0.553908. The 5% here is a continuously compounded annual rate, unlike the one-period simple rate in the first example. Terminal stock prices and put payoffs are:

PathTerminal stock pricePut payoff
Two down moves75.36383224.636168
One up, one down, in either order100.0000000.000000
Two up moves132.6896440.000000

At the half-year down node, the stock is worth 86.812345. Continuation is worth:

H1,0=(1−q)×24.636168…+q×0R≈10.718647.H_{1,0}=\frac{(1-q)\times24.636168\ldots+q\times0}{R} \approx10.718647.

Immediate exercise pays 100−86.812344…≈13.187655100-86.812344\ldots\approx13.187655, so the American holder should exercise at this node. At the up node, both exercise and continuation are worth 0. Working back to today:

P0E=(1−q)×10.718646…R≈4.663444,P0A=(1−q)×13.187655…R≈5.737654.P^{\mathrm E}_0=\frac{(1-q)\times10.718646\ldots}{R}\approx4.663444,\qquad P^{\mathrm A}_0=\frac{(1-q)\times13.187655\ldots}{R}\approx5.737654.

Immediate exercise today is worth 0, so the American holder should still wait. The early-exercise right adds about 1.074211. At a positive interest rate, the value of receiving the exercise proceeds sooner can outweigh the value of keeping the option alive. That is why early exercise can matter for puts even without dividends.

Assumptions and the Black–Scholes–Merton limit​

These trees use a constant rate and fixed up and down factors. The CRR construction chooses the factors from a constant volatility parameter. It also assumes no dividends, no trading costs, equal borrowing and lending rates, short selling and fractional shares, and exact rebalancing at every node. Changes in rates, volatility, dividends, funding, or trading constraints can change prices and optimal exercise decisions.

u,du,d are model inputs, not stock-price forecasts derived from no-arbitrage. Once chosen, they must still satisfy d<R<ud<R<u. CRR's σ\sigma sets the size of each log-price move; with finitely many steps, it need not equal the exact standard deviation of the terminal one-year log return.

Section 5 of the original paper establishes the Black–Scholes limit. Hold S0,K,TS_0,K,T, constant rr, and σ>0\sigma>0 fixed while n→∞n\to\infty. Recompute u,d,Ru,d,R from the formulas above at every refinement and use the risk-neutral probabilities. For European calls and puts on a non-dividend-paying stock under these frictionless conditions, tree prices converge to Black–Scholes–Merton prices. Under the risk-neutral weights, successive moves are independent and their log sizes shrink with Δt\sqrt{\Delta t}. The central limit theorem then gives a normal terminal log return with limiting mean (r−σ2/2)T(r-\sigma^2/2)T and variance σ2T\sigma^2T, so the terminal stock price has the lognormal limit used in BSM. Matching the mean and variance alone would not establish this distributional limit.

Adding layers while keeping the original u,du,d unchanged alters the risk over the whole horizon and does not yield this limit. More steps also do not fix omitted jumps, changing volatility, or trading costs. An American put tree approximates the optimal stopping value in the corresponding model; the European BSM formula cannot replace the early-exercise test.

Compare both puts on one tree in Python​

Save the following as binomial_example.py and run python3 binomial_example.py. It uses only the Python standard library. Numeric inputs are converted to floats and must be finite; stock price, strike, maturity, and volatility parameter must be positive; steps must be a positive integer; and the tree must satisfy the no-arbitrage inequality. The growth factors and every stock node must fit in positive finite floats, the computed probability must lie strictly between 0 and 1, and option values must remain finite. Invalid inputs and trees outside this numerical range raise ValueError; the code also converts overflow from Python's math functions to ValueError. The example does not handle the degenerate zero-volatility tree.

j counts up moves, so values[j] is the down child and values[j+1] the up child. Both options share the stock price, strike, rate, volatility, maturity, and step count. american=True adds the exercise comparison at each node. The two-step run prints the American node trace, followed by comparisons on finer trees.

from math import exp, isfinite, log, sqrt


def price_put(s0, strike, years, rate, sigma, steps, american=False, trace=False):
try:
s0, strike, years, rate, sigma = map(float, (s0, strike, years, rate, sigma))
except (TypeError, ValueError, OverflowError) as error:
raise ValueError("numeric inputs must be representable as floats") from error
inputs = (s0, strike, years, rate, sigma)
if not all(isfinite(x) for x in inputs):
raise ValueError("inputs must be finite")
if min(s0, strike, years, sigma) <= 0:
raise ValueError("s0, strike, years, sigma must be positive")
if type(steps) is not int or steps < 1:
raise ValueError("steps must be a positive integer")
log_s0 = log(s0)
try:
dt = years / steps
move = sigma * sqrt(dt)
u, d = exp(move), exp(-move)
growth = exp(rate * dt)
lowest = exp(log_s0 - steps * move)
highest = exp(log_s0 + steps * move)
except OverflowError as error:
raise ValueError("tree exceeds floating-point range") from error
if not all(isfinite(x) and x > 0 for x in (u, d, growth, lowest, highest)):
raise ValueError("tree exceeds floating-point range")
if not d < growth < u:
raise ValueError("tree must satisfy d < exp(rate * dt) < u")
q = (growth - d) / (u - d)
if not 0 < q < 1:
raise ValueError("risk-neutral probability is outside floating-point range")

def stock_at(i, j):
return s0 if i == 0 else exp(log_s0 + (2*j - i) * move)

values = [max(strike - stock_at(steps, j), 0.0)
for j in range(steps + 1)]
if trace:
print(f"u={u:.6f}; d={d:.6f}; R={growth:.6f}; q={q:.6f}")
print("terminal_puts=" + ", ".join(f"{v:.6f}" for v in values))
for i in range(steps - 1, -1, -1):
previous = []
for j in range(i + 1):
stock = stock_at(i, j)
continuation = ((1-q) * values[j] + q * values[j+1]) / growth
exercise = max(strike - stock, 0.0)
value = max(exercise, continuation) if american else continuation
if not isfinite(value):
raise ValueError("option value exceeds floating-point range")
previous.append(value)
if trace:
decision = "exercise" if american and exercise > continuation else "hold"
print(f"i={i}; j={j}; S={stock:.6f}; "
f"continue={continuation:.6f}; exercise={exercise:.6f}; "
f"value={value:.6f}; decision={decision}")
values = previous
return values[0]


parameters = (100.0, 100.0, 1.0, 0.05, 0.20)
eu = price_put(*parameters, 2)
am = price_put(*parameters, 2, american=True, trace=True)
print(f"n=2; European={eu:.6f}; American={am:.6f}; premium={am-eu:.6f}")
for n in (50, 200, 800):
eu = price_put(*parameters, n)
am = price_put(*parameters, n, american=True)
print(f"n={n}; European={eu:.6f}; American={am:.6f}; premium={am-eu:.6f}")
u=1.151910; d=0.868123; R=1.025315; q=0.553908
terminal_puts=24.636168, 0.000000, 0.000000
i=1; j=0; S=86.812345; continue=10.718647; exercise=13.187655; value=13.187655; decision=exercise
i=1; j=1; S=115.190991; continue=0.000000; exercise=0.000000; value=0.000000; decision=hold
i=0; j=0; S=100.000000; continue=5.737654; exercise=0.000000; value=5.737654; decision=hold
n=2; European=4.663444; American=5.737654; premium=1.074211
n=50; European=5.533634; American=6.073728; premium=0.540094
n=200; European=5.563534; American=6.086383; premium=0.522849
n=800; European=5.571027; American=6.089402; premium=0.518375

The two-step tree is convenient for hand calculation but gives a coarse price approximation. These finer-tree results show that the early-exercise premium also depends on discretization. To estimate actual returns and the risk of holding stock, see Returns, Diversification, and Portfolio Risk. The Quantitative Finance overview connects the other topics.

Explore connectionsOpen network