Introduction
This article builds upon the American option pricing model posted by Andrew Peters and lets you value
options on stocks, futures, currencies, and stock indices with discrete or continuous dividends.
This project was written as part of my Options pricing class to create a Binomial Option Pricing model that could handle several types of options,
including those on underlyings with discrete dividends.
The binomial options pricing model provides a generalizable numerical method for the valuation of options and was first proposed by Cox, Ross, and Rubinstein (1979).
The model uses a "discrete-time" model of the varying price over time of the underlying financial instrument. According to this model, an option's price at any moment
in time can have two possible future states - up or down. Option valuation is then done via application of the risk neutrality assumption over the life of the option,
as the price of the underlying instrument evolves. While the Black-Scholes-Merton formula requires that the option be European style, the Binomial models can handle
American style options with ease. At any point of time, the value of the option is the maximum of the value calculated via its child nodes and the intrinsic value of the option.
The Black-Scholes-Merton formula also assumes no dividend payouts while the Binomial model can handle dividend payments - thus making it flexible enough to handle currencies,
stock options, futures, and index options.
Architecture
I created a BinomialTree
class that is used for interfacing between the Windows Form and the TreeNodeFactory
class. This class invokes the methods necessary
to create the binomial lattice and do the aggregate calculations over it. The TreeNodeFactory
is used to create objects of TreeNode
. Each TreeNode
instance
represents - you guessed it - a node in the binomial tree.
The factory maintains an ArrayList
of all the TreeNode
objects it creates and allows you to create, fetch, and delete TreeNode
s in the binomial lattice.
The enumeration EnumStyle
represents whether the option is American or European. The enumeration EPutCall
from Andrew Peter's code is used,
and represents whether the option is a put or a call.
Building the price tree for the underlying security - no discrete dividends
bool CreateStockPriceTree()
{
_myFactory = new TreeNodeFactory();
for (int jStep = 0; jStep <= _steps; jStep++)
{
for (int i = 0; i <= jStep; i++)
{
_myFactory.createNode(jStep, i, u, d, _stockPrice,_deltaT);
}
}
return true;
}
In the code above - the step variable is used to represent a step in the binomial lattice. For instance - a 12 step lattice for an option maturing in one year would
have each step of one month's duration. The level is a representation of the row number. Since this is a lattice, the ith step would have i+1 levels.
The first node - representing the current time - will be step zero and level 1. The next step would have two nodes -level 1 and 2, and so on.
Computing the option values
public double ComputeOptionValues()
{
for (int ii = 0; ii <= _steps; ii++)
{
_myFactory.getNode(_steps, ii).SetSimple_optionValue(_strike, _putCall);
}
if (_steps > 0)
{
for (int jStep = _steps-1; jStep >= 0; jStep--)
{
for (int i = 0; i <= jStep; i++)
{
_myFactory.getNode(jStep, i).SetCalculatedOptionValue(p,
_myFactory.getNode(jStep + 1, i + 1).OptionValue,
_myFactory.getNode(jStep + 1, i).OptionValue,
_style, _putCall, _strike, _discountFactor);
}
}
}
return _myFactory.getNode(0,0).OptionValue;
}
For the last step in the binomial lattice, the payoffs are calculated using the formula for intrinsic value of an option - Max(S-K) for calls and Max(K-S) for puts.
For nodes at all preceding levels, the node values are calculated using the maximum of either the intrinsic value, or the value calculated using:
C = max { [p*CU + (1-p)*CD]*EXP( - r * t / n), S - K }
or,
P = max { [p*PU + (1-p)*PD]*EXP( - r * t / n), K - S }
where CU is the value of the call option if the price moves up and CD is the value if the price moves down.
TreeNode
handles these valuations and sets its option price:
public bool SetCalculatedOptionValue(double p, double optionValUpChild,
double _optionValueDownChild, EnumStyle style, EPutCall putOrCall,
double strike, double discountFactor)
{
if (style == EnumStyle.European)
{
_optionValue= (p * (optionValUpChild) +
(1 - p) * _optionValueDownChild) * discountFactor;
}
else
{
double tmpOptionVal = (p * (optionValUpChild) +
(1 - p) * _optionValueDownChild) * discountFactor;
if (putOrCall == EPutCall.Call)
{
_optionValue = Math.Max(SimpleCall(stockPrice, strike), tmpOptionVal);
}
else
{
_optionValue = Math.Max(SimplePut(stockPrice, strike), tmpOptionVal);
}
}
return true;
}
Factoring in discrete dividends
While this model can handle continuous dividend yields by simply factoring that value into its calculation of p
, handling discrete dividends requires some extra work.
This approach is suggested by Hull in his excellent treatise on option pricing: Options,
Futures, and other derivatives(6th edition). We simply discount the present value of all dividends from the initial price of the underlying,
when creating the tree. Then, at each node, we add the present values of the dividends at that point in time. We modify CreateStockPriceTree
to the code below:
bool CreateStockPriceTree()
{
_stockPrice = GetDividendAdjustedUnderlying();
_myFactory = new TreeNodeFactory();
_myFactory.ResetNodes();
for (int jStep = 0; jStep <= _steps; jStep++)
{
for (int i = 0; i <= jStep; i++)
{
_myFactory.createNode(jStep, i, u, d, _stockPrice,_deltaT);
}
}
for (int jStep = 0; jStep <= _steps; jStep++)
{
for (int i = 0; i <= jStep; i++)
{
_myFactory.getNode(jStep, i).AddDividendPresentValues(_deltaT, _riskFreeRate,
_dividend1, _dividend1Date, _dividend2, _dividend2Date,
_dividend3, _dividend3Date, _dividend4, _dividend4Date);
}
}
return true;
}
double GetDividendAdjustedUnderlying()
{
return _stockPrice - PresentValue(_dividend1, _dividend1Date)
- PresentValue(_dividend2, _dividend2Date)
- PresentValue(_dividend3, _dividend3Date)
- PresentValue(_dividend4, _dividend4Date);
}
The code in TreeNode
that adds back the dividend present values to the node's stock price is:
public bool AddDividendPresentValues(double deltaT,double riskfreeRate,
double dividend1, double dividend1date,
double dividend2, double dividend2date, double dividend3, double dividend3date,
double dividend4, double dividend4date)
{
stockPrice += DividendPresentValue(dividend1, dividend1date, riskfreeRate, deltaT);
stockPrice += DividendPresentValue(dividend2, dividend2date, riskfreeRate, deltaT);
stockPrice += DividendPresentValue(dividend3, dividend3date, riskfreeRate, deltaT);
stockPrice += DividendPresentValue(dividend4, dividend4date, riskfreeRate, deltaT);
return true;
}
Please note that in the entire project, the dates used are not calendar dates but lengths of time in years. If you want to extend it to use actual dates, it should be a trivial change.
The computation of option values proceeds in the same way for discrete dividends as it did before.
Feedback
I would be delighted to hear your comments, suggestions, or idle chatter. Please email me at tanveeransari@hotmail.com.
Tanveer Ansari specializes in application of .NET and Java to building automated trading systems. He also builds statistical (time series and bayesian) models to predict asset prices.
He is available for technology consulting for the financial markets at info@tanveeransari.com