Why a Binomial Tree Must Compare Early Exercise Value
Summary
The document presents a binomial option pricing implementation that produces matching prices for American and European calls, then asks why. In a binomial tree, European value is calculated by discounting expected terminal payoffs backward. American value must also be checked at each node against the payoff from exercising immediately; the node value is the larger of continuation value and exercise value. The posted code includes this comparison when its American flag is enabled, but the document does not contain a diagnosis or follow-up answer identifying the cause of the matching outputs.
The example also illustrates implementation details that can affect a tree: recursive node evaluation, memoization, rounded underlying prices, and risk-neutral probabilities. It gives no tested correction or performance measurements, so it is best read as a debugging prompt rather than a verified implementation guide. For a non-dividend-paying stock, early exercise of an American call is generally not optimal under standard assumptions, so equal American and European call values may be expected; dividends or other model features can change that conclusion.
Key ideas
- An American option tree compares immediate exercise value with continuation value at every node.
- European option values depend on terminal payoffs and backward discounting without early exercise.
- Matching American and European call values can be expected for non-dividend-paying stocks under standard assumptions.
- Rounding, memoization, and model assumptions are implementation details worth checking when debugging a tree.
Tags
Full text
# Binomial Model Implementation Trouble - American and European options come out equal
# Binomial Model Implementation Trouble - American and European options come out equal
I'm Trying to implement the binomial option price model in python and get reasonable performance by using memoization. I checked the output against a black and scholes model and for European options it seems to be working. However, when try to price an American option, I get the same result as a European and I can't for the life of me figure out why. Can anyone help or point me in the right direction ? Thanks
```
import numpy as np
from functools import lru_cache
steps =40
riskFreeRate=0.215
stepSize = 1/36
@lru_cache(maxsize=1000000) # Memoize the result to reduce number of calls
def callOption(price,strike=100,sigma=0.1,american=False):
u =np.exp(sigma*np.sqrt(stepSize)) #The factor by which price increases
d =np.exp(-1*sigma*np.sqrt(stepSize)) # factor by which price descreases
p =(np.exp(riskFreeRate*stepSize) -d) / (u-d) #Probability that price goes up
@lru_cache(maxsize=steps**2) # Per memoized callOption, memoize the value at a given step
def atTime(step):
exVal = np.max([price-strike,0]) # The excercise value at this time
if step==steps:
val =np.max([price-strike,0]) # if this is a terminal node
else:
pd = np.round(price*d,3) # The new up price,
pu = np.round(price*u,3) # The new down price
#Rounding the prices means we remeber fewer nodes with minimal affect on accuracy
down = callOption(price=pd,sigma=sigma,strike=strike,american=american)(step+1) # Get the value of the next node when price went down
up = callOption(price=pu,sigma=sigma,strike=strike,american=american)(step+1) # Get the value of the next node when price went up
discount = np.exp(-1*riskFreeRate*stepSize) # the discount rate
val = (p*up+(1-p)*down)*discount # THis is the binomial value of the option at this node
if american :
#If its an american option, the value is the greater of the binomial value or excercise value
val = np.max([val,exVal])
return val
return atTime
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.