Click here to Skip to main content
Click here to Skip to main content

Option pricing with discrete dividends using the Binomial Tree model

By , 17 Jun 2007
Rate this:
Please Sign up or sign in to vote.

Screenshot - option.gif

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 TreeNodes 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

/// <summary>
/// Create the Tree of Prices of Underlying
/// </summary>  
/// <returns />
bool CreateStockPriceTree()
{
    _myFactory = new TreeNodeFactory();
    
    //CREATE TREE OF PRICES OF UNDERLYING
    //loop once per step
    for (int jStep = 0; jStep <= _steps; jStep++)
    {
        //loop once per level
        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 the last column set the option values to simple payoffs
    for (int ii = 0; ii <= _steps; ii++)
    {
        _myFactory.getNode(_steps, ii).SetSimple_optionValue(_strike, _putCall);
    }
    //for all other columns set payoff to calculated payoff 
    if (_steps > 0)
    {
        //Iterate backward through tree from second last column
        for (int jStep = _steps-1; jStep >= 0; jStep--)
        {
            //loop once per level
            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//American option - return max of calculated or intrinsic value
    {
        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:

/// <summary>
/// Create the Tree of Prices of Underlying - this version
/// handles upto 4 discrete dividends
/// </summary>
bool CreateStockPriceTree()
{
    //if there are discrete dividends then create tree first using S*
    _stockPrice = GetDividendAdjustedUnderlying();
    //after that add present value of dividends to each node in another pass

    _myFactory = new TreeNodeFactory();
    _myFactory.ResetNodes();
    
    //CREATE TREE OF PRICES OF UNDERLYING
    //loop once per step
    for (int jStep = 0; jStep <= _steps; jStep++)
    {
        //loop once per level
        for (int i = 0; i <= jStep; i++)
        {
            _myFactory.createNode(jStep, i, u, d, _stockPrice,_deltaT);
        }
    }

    //now add Present Values of dividends to prices of underlying
    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;
}
/// Discount the present values of the dividends from the initial stock price
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Tanveer Ansari 1
Software Developer (Senior)
United States United States
Tanveer Ansari specializes in application of .NET technologies 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 tanveeransari@hotmail.com

Comments and Discussions

 
GeneralGREAT! Pinmembertwisterjosh19-Jun-07 3:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140421.2 | Last Updated 17 Jun 2007
Article Copyright 2007 by Tanveer Ansari 1
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid