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 and stock price at expiry, call and put payoffs are:
The payoff depends on the expiry state; and 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 . After one period it can only be or . The risk-free growth factor is : an investment of 1 becomes 1.05, a 5% rate for this period. A European call has strike .
Replicate it with shares and a risk-free bond worth today. The bond pays at expiry; means borrowing. Match both states:
Subtracting gives , hence . Substitution in the down-state equation gives:
Buy half a share and borrow 38.095238, for a net cost of 11.904762. The loan requires repayment of 40 at expiry:
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 . 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 and , with . No-arbitrage between stock and the bond requires:
If , 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 , borrowing to buy stock also produces an arbitrage. Strict inequalities give positive pricing weights to both states.
A portfolio replicating any terminal payments has:
Substitute these into and rearrange:
is the risk-neutral probability of an up move. It satisfies : under these weights, the stock's average growth factor equals the risk-free growth factor. Here and , so:
The 62.5% is a pricing weight obtained from replication, not a forecast of the actual frequency of up moves. The real probability is relevant to forecasting returns and risk. Averaging option payoffs under 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 at expiry with a put plus one share. Both portfolios pay at expiry, so:
In the one-period example, the put pays 0 in the up state and 20 in the down state:
The price difference agrees too: . Over multiple periods, replace with the present value of the strike at expiry. With a continuously compounded annual rate and maturity , this is . 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 , up then down and down then up reach the same stock price because . The tree therefore recombines. After step with up moves, the stock price is:
Fill the terminal layer with expiry payoffs, then work back one layer at a time. For a European put:
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 with immediate exercise value :
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: , year, continuously compounded annual rate , and annual volatility parameter . Each step lasts half a year. The CRR choice is:
For , this gives , , , and . 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:
At the half-year down node, the stock is worth 86.812345. Continuation is worth:
Immediate exercise pays , so the American holder should exercise at this node. At the up node, both exercise and continuation are worth 0. Working back to today:
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.
are model inputs, not stock-price forecasts derived from no-arbitrage. Once chosen, they must still satisfy . CRR's 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 , constant , and fixed while . Recompute 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 . The central limit theorem then gives a normal terminal log return with limiting mean and variance , 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 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.