Introduction

A stock option gives its holder the right — but not the obligation — to buy or sell a stock at a fixed strike price on (or before) expiry. How much is that right worth today?

The insight behind the binomial model, introduced by Cox, Ross and Rubinstein in 1979, is disarmingly simple: divide time to expiry into nn equal steps. In each step the stock price either multiplies by an up factor uu or a down factor dd. At expiry every node carries a known payoff. Work backwards through the tree, discounting each node's value, and you get the fair price at the root.

The model is recombining: an up move followed by a down move lands on the same node as a down move followed by an up move (u⋅d=1u \cdot d = 1), so the tree has n+1n + 1 terminal nodes instead of 2n2^{n}. That makes the whole calculation run in O(n2)O(n^{2}) time — fast enough to be practical long before continuous calculus is tractable.

As n→∞n \to \infty and the step size Δt=T/n→0\Delta t = T/n \to 0, the discrete tree converges to the famous Black-Scholes formula — the continuous limit of the same risk-neutral argument.

The Lattice in Action

Adjust the sliders to build a binomial lattice. Each node shows the stock price; the highlighted bottom row shows the option payoff at expiry. The model folds those payoffs back to give the fair price today (top-left node). Increase the number of steps and watch the price converge toward the Black-Scholes value.

<!-- Controls for the binomial lattice demo -->
<div class="controls">
  <label>Steps: <span id="stepsVal">8</span>
    <input type="range" id="steps" min="2" max="20" value="8">
  </label>
  <label>Volatility: <span id="volVal">20</span>%
    <input type="range" id="vol" min="5" max="80" value="20">
  </label>
  <label>Strike: lt;span id="strikeVal">100</span>
    <input type="range" id="strike" min="80" max="120" value="100">
  </label>
</div>
<div class="results">
  <div class="result-box">
    <div class="result-label">Binomial price</div>
    <div class="result-value" id="binomialPrice">—</div>
  </div>
  <div class="result-box">
    <div class="result-label">Black-Scholes</div>
    <div class="result-value" id="bsPrice">—</div>
  </div>
  <div class="result-box">
    <div class="result-label">Difference</div>
    <div class="result-value" id="diffVal">—</div>
  </div>
</div>
<canvas id="chart" width="480" height="200"></canvas>
<div class="hint-bar" id="hintBar">Adjust sliders to see how the binomial price converges to Black-Scholes.</div>
/* Styles for the binomial option pricing demo */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; padding: .5rem; background: transparent; }
.controls { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .8rem; }
label { font-size: .85rem; color: #444; display: flex; align-items: center; gap: .5rem; }
input[type=range] { flex: 1; cursor: pointer; }
.results { display: flex; gap: .6rem; margin-bottom: .8rem; }
.result-box { flex: 1; background: #e8eef3; border-radius: 8px; padding: .5rem .7rem; text-align: center; }
.result-label { font-size: .72rem; color: #666; margin-bottom: .2rem; }
.result-value { font: 700 1.1rem ui-monospace, monospace; color: #1d3557; }
canvas { display: block; width: 100%; max-width: 480px; background: #f7f9fb; border-radius: 8px; border: 1px solid #dde3ea; }
.hint-bar { font-size: .8rem; color: #555; margin-top: .5rem; min-height: 1.2em; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Fixed model parameters: spot price, risk-free rate, time to maturity
const S0 = 100;   // spot price (current stock price)
const r = 0.05;   // annual risk-free rate (5%)
const T = 1.0;    // time to maturity in years

// Black-Scholes closed-form for a European call (Abramowitz & Stegun normal CDF approximation)
function normCDF(x) {
  const a1=0.254829592,a2=-0.284496736,a3=1.421413741,a4=-1.453152027,a5=1.061405429,p=0.3275911;
  const sign = x < 0 ? -1 : 1;
  x = Math.abs(x) / Math.sqrt(2);
  const t = 1.0 / (1.0 + p * x);
  const y = 1.0 - (((((a5*t+a4)*t)+a3)*t+a2)*t+a1)*t*Math.exp(-x*x);
  return 0.5 * (1.0 + sign * y);
}
function blackScholes(S, K, T, r, sigma) {
  // d1 and d2 from the Black-Scholes formula
  const d1 = (Math.log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * Math.sqrt(T));
  const d2 = d1 - sigma * Math.sqrt(T);
  return S * normCDF(d1) - K * Math.exp(-r * T) * normCDF(d2);
}

// Cox-Ross-Rubinstein binomial model: compute option price for n steps
function binomialPrice(S, K, T, r, sigma, n) {
  const dt = T / n;
  const u = Math.exp(sigma * Math.sqrt(dt));   // up factor per step
  const d = 1 / u;                               // down factor (recombining tree)
  const p = (Math.exp(r * dt) - d) / (u - d);   // risk-neutral up probability
  const disc = Math.exp(-r * dt);                // one-step discount factor
  // terminal payoffs at expiry
  const vals = [];
  for (let j = 0; j <= n; j++) {
    const ST = S * Math.pow(u, n - j) * Math.pow(d, j);
    vals.push(Math.max(ST - K, 0));
  }
  // backward induction through the tree
  for (let i = n - 1; i >= 0; i--) {
    for (let j = 0; j <= i; j++) {
      vals[j] = disc * (p * vals[j] + (1 - p) * vals[j + 1]);
    }
  }
  return vals[0];
}

// compute binomial prices for a range of step counts
function computeSeries(K, sigma) {
  const ns = [2,3,4,5,6,7,8,9,10,12,14,16,18,20];
  return ns.map(n => ({ n, price: binomialPrice(S0, K, T, r, sigma, n) }));
}

// draw convergence chart on canvas
function drawChart(series, bsVal, K, sigma) {
  const canvas = document.getElementById('chart');
  const ctx = canvas.getContext('2d');
  const W = canvas.width, H = canvas.height;
  ctx.clearRect(0, 0, W, H);

  const prices = series.map(p => p.price);
  const allPrices = [...prices, bsVal];
  const minP = Math.max(0, Math.min(...allPrices) - 0.5);
  const maxP = Math.max(...allPrices) + 0.5;
  const pad = { l: 40, r: 20, t: 16, b: 30 };

  const toX = (i) => pad.l + (i / (series.length - 1)) * (W - pad.l - pad.r);
  const toY = (v) => pad.t + (1 - (v - minP) / (maxP - minP)) * (H - pad.t - pad.b);

  // draw horizontal Black-Scholes reference line
  ctx.setLineDash([4, 4]);
  ctx.strokeStyle = '#e63946';
  ctx.lineWidth = 1.5;
  ctx.beginPath();
  ctx.moveTo(pad.l, toY(bsVal));
  ctx.lineTo(W - pad.r, toY(bsVal));
  ctx.stroke();
  ctx.setLineDash([]);

  // draw binomial price curve
  ctx.strokeStyle = '#1d3557';
  ctx.lineWidth = 2;
  ctx.beginPath();
  series.forEach((pt, i) => {
    const x = toX(i), y = toY(pt.price);
    i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
  });
  ctx.stroke();

  // draw data-point dots
  series.forEach((pt, i) => {
    ctx.fillStyle = '#1d3557';
    ctx.beginPath();
    ctx.arc(toX(i), toY(pt.price), 3, 0, 2 * Math.PI);
    ctx.fill();
  });

  // draw axis labels
  ctx.fillStyle = '#666';
  ctx.font = '10px system-ui';
  ctx.textAlign = 'center';
  series.forEach((pt, i) => {
    if (i === 0 || pt.n % 4 === 0) ctx.fillText(pt.n, toX(i), H - 6);
  });
  ctx.textAlign = 'right';
  ctx.fillText('

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

+ minP.toFixed(1), pad.l - 4, toY(minP)); ctx.fillText('

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

+ maxP.toFixed(1), pad.l - 4, toY(maxP)); } function update() { const n = +document.getElementById('steps').value; const sigma = +document.getElementById('vol').value / 100; const K = +document.getElementById('strike').value; document.getElementById('stepsVal').textContent = n; document.getElementById('volVal').textContent = Math.round(sigma * 100); document.getElementById('strikeVal').textContent = K; const bp = binomialPrice(S0, K, T, r, sigma, n); const bsp = blackScholes(S0, K, T, r, sigma); const diff = Math.abs(bp - bsp); document.getElementById('binomialPrice').textContent = '

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

+ bp.toFixed(4); document.getElementById('bsPrice').textContent = '

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

+ bsp.toFixed(4); document.getElementById('diffVal').textContent = '

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

+ diff.toFixed(4); const series = computeSeries(K, sigma); drawChart(series, bsp, K, sigma); const pct = (diff / bsp * 100).toFixed(2); document.getElementById('hintBar').textContent = i18nFmt('With %n% steps the binomial price differs from Black-Scholes by $%diff% (%pct%).', { n: n, diff: diff.toFixed(4), pct: pct }); } ['steps', 'vol', 'strike'].forEach(id => document.getElementById(id).addEventListener('input', update)); update();
Result
Console

Notice how even 4–5 steps give a good approximation, and by 20 steps the binomial price is within a fraction of a cent of the Black-Scholes closed form. The tree trades continuous mathematics for a simple loop — and the two answers agree in the limit.

The Real Complexity

Why does the binomial model matter computationally, not just financially?

  • Naive enumeration of all price paths gives 2n2^{n} leaves — hopeless beyond a handful of steps.
  • Recombination collapses the tree: up then down equals down then up, leaving only n+1n + 1 terminal nodes at step nn. Total work is O(n2)O(n^{2}), and it fits in O(n)O(n) space with a rolling array.
  • American options — which can be exercised early — have no clean closed form under Black-Scholes. The binomial tree handles them naturally: at each interior node, compare the continuation value with the immediate exercise payoff and take the max.
  • Convergence rate: the error versus Black-Scholes is O(1/n)O(1/n) for European calls, so doubling the steps halves the error. Practitioners use n≈100n \approx 100–10001000 depending on the required precision.
  • Exotic path dependence (barrier options, lookback options) requires tracking extra state per node but the lattice structure remains; dynamic programming on the tree generalises naturally.

The binomial model is also a gateway to understanding risk-neutral pricing: the up/down probabilities pp and 1−p1-p are chosen so every asset grows at the risk-free rate, not the subjective expected return. The actual probability the stock goes up never appears — only the no-arbitrage constraint matters.

Where It Matters

The binomial lattice is one of the most versatile tools in quantitative finance:

  • Equity options: the original use case — calls and puts on individual stocks, handling both European and American exercise styles.
  • Interest-rate trees: models such as Ho-Lee and Black-Derman-Toy build a binomial tree of short rates to price bonds, caps, floors and swaptions.
  • Real options: capital-budgeting decisions (expand, defer, abandon a project) are modelled as options on uncertain future cash flows; the lattice prices the managerial flexibility explicitly.
  • Credit derivatives: simplified lattice models price convertible bonds and credit default options where early exercise and credit events interact.
  • Algorithm education: because the backward induction is a pure dynamic programming computation on a DAG, the binomial tree is one of the clearest real-world examples of that paradigm.

Wherever continuous-time stochastic calculus is too heavy — or produces no closed form — the lattice provides a transparent, tuneable approximation.

Conclusion

The binomial model is a masterclass in discretising a hard continuous problem. Replace Brownian motion with coin flips, fold payoffs backwards through a recombining tree, and — almost magically — the answer converges to the same number that the Black-Scholes partial differential equation gives in the limit n→∞n \to \infty.

Its computational footprint is modest: O(n2)O(n^{2}) work, O(n)O(n) space. Its conceptual payoff is enormous: risk-neutral pricing, no-arbitrage arguments, and the link between discrete dynamic programming and continuous stochastic calculus all live inside one simple lattice.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/binomial-option-pricing/Content licensed under CC BY-NC 4.0.