Skip to main content

class for creating binomial trees for options pricing

Project description

Binomial Tree for Options Pricing

Motivation:

Started as a project for learning in relation to school but turned out as a tool that could be useful for more.

What does it do?

This class will construct/calculate/make/whatever a binomial tree with given parameters and calculate option prices for both American and European Call and Put options.

  • The class will make tree objects with Dataframe representation (except for non-recombining trees).
  • The write() method will generate an Excel file with the result.

Dividends

The class can take dividends into account (dividend yield and discrete dividends). It has 2 ways of solving for discrete dividends, the 'F solution' and 'non-recombining'.

F solution

Subtracts the present value from current spot, and makes binomial tree based on this 'pre-paid forward'.

Non-recombining tree

As the name suggests, the tree does not recombine after dividend payout and calculates the option premium as normal (assumes that we can trade just before and after stock goes ex-div)


Installation and import

Installation

The project can be installed from pip with the command:
pip install binotree


Quickstart

Passing arguments

import binotree as bt


parameters = dict(fname = 'NormalTree', 
                  spot = 50, strike = 50, 
                  T = 3/12, dt = 1/12, dtfreq = 'm',
                  vola = 0.30, r = 0.03)

treeObject = bt.tree(params = parameters)


The class can also take in the parameters directly as keywords:

import binotree as bt


treeObject = bt.tree(fname = 'NormalTree', 
                     spot = 50, strike = 50, 
                     T = 3/12, dt = 1/12, dtfreq = 'm',
                     vola = 0.30, r = 0.03)


In the case of both a parameters dictionary and keywords, the two will merge, and keywords will override any conflicting parameters:

import binotree as bt


parameters = dict(fname = 'NormalTree', 
                  spot = 50, strike = 50, 
                  T = 3/12, dt = 1/12, dtfreq = 'm',
                  vola = 0.30, r = 0.03)

treeObject = bt.tree(params = parameters, vola = 0.20)

(here the vola specification from the dictionary will be replaced with 0.20)

Access the binomial tree from console

European call/put and american call/put are all calculated by default (can be changed through the maketrees parameter).
The bt.tree object will store a tree object for each option type calculated.
Access the european call tree as such:

treeObject.ecTree
        dt ->      0/12      1/12      2/12      3/12
         Spot                                  64.834
  [Intrinsic]                                [14.834]
    (Premium)                                (14.834)
                                    59.4555          
                                   [9.4555]          
                                   (9.5803)          
                          54.5232             54.5232
                         [4.5232]            [4.5232]
                         (5.8343)            (4.5232)
                   50.0                50.0          
                  [0.0]               [0.0]          
               (3.4209)            (2.2235)          
                          45.8521             45.8521
                            [0.0]               [0.0]
                          (1.093)               (0.0)
                                    42.0483          
                                      [0.0]          
                                      (0.0)          
                                                38.56
                                                [0.0]
                                                (0.0)


In case your tree is too big for a proper representation in the console, you can access any node you want by calling the tree object:

treeObject.ecTree(up = 1, down = 0)
{'Spot': 54.5232,
 'Intrinsic': 4.5232,
 'Premium': 5.8343,
 'Delta': 0.7781,
 'Bond': -36.5877}

Write to excel file

Simply call the write() method to write to excel file. Pass the direc parameter in construction to specify directory (if none is passed, the working directory is used).

import binotree as bt


parameters = dict(fname = 'NormalTree', 
                  spot = 50, strike = 50, 
                  T = 3/12, dt = 1/12, dtfreq = 'm',
                  vola = 0.30, r = 0.03)

treeObject = bt.tree(params = parameters, direc = 'your/directory/here')

treeObject.write()

# The following print message will show where your file was made:
# File was made at: 'your/directory/here/NormalTree.xlsx

The file should look something like this:

(each option type is given its own sheet in the excel file)


Full parameter specification

Parameters specification


How to pass parameters/arguments:

There are 2 ways of parsing arguments:

  1. A dictionary
  2. Keyword arguments (kwargs)

If both a dictionary and keyword arguments are parsed they will join together. Keyword arguments will override any parameters passed in both the dictionary and as keyword arguments.


Which parameters to pass:

If nothing is passed, the help() method will print help for specifying parameters

Spot and strike

Both must be passed

  • spot
  • strike

Time and period specification

Must be in terms of years (e.g., maturity in 6 months would be T = 6/12 ).
The variable dtfreq can be passed as a string ('d', 'w', or 'm') for prettier formatting in output.

2 of 3 must be passed

  • T
  • dt
  • periods

Interest rate, dividend yield, and continuous compounding

0 of 3 must be passed

  • r
  • rcont
  • divyield

Volatility and up/down movements

1 of 3 must be passed

  • vola
  • u
  • d

For custom function for calculating up/down movements, see udfunc specification.


Dividends

0 of 2 must be passed

  • discdiv
  • nonrec

Directory for Excel output

0 of 4 must be passed

  • direc
  • folname
  • fname
  • write

Various

0 of 5 must be passed

  • collapsed
  • maketrees
  • headerformat
  • rounding
  • makedfs
  • portfolios
  • showIntrinsic

Examples of use

imports

import binotree as bt

Normal tree

Simple 3-period binomial tree:

parsNormal = dict(fname = 'NormalTree', 
                  spot = 100, strike = 95, 
                  dt = 1/12, periods = 3, 
                  vola = 0.20, r = 0.05, 
                  showIntrinsic = True, # True is default
                  dtfreq = 'm', rounding = 4)  

binoNormal = bt.tree(params = parsNormal)

Tree preview

The binomial tree for the European Call is accessed by binoNormal.ecTree

Callable tree

In case your binomial tree is big and won't print neatly you can access each node by calling the tree object with up and down passed:

write() method

typing binoNormal.write() in the console an Excel file will be generated. Either in the current working directory, or passed directory through the direc parameter.
The location of the file should be printed.

binoNormal.write(fname_override = 'NEW_FILENAME',
                 width = int("{your file window width}"), height = int("{file window height}"))

File was made at: {your directory here}/NEW_FILENAME.xlsx


Plotting methods

The plotting methods can take in keywords to alter the original parameters


Plotting deltas w.r.t. current spot:

binoNormal.ecPlotDeltas()


Changing periods for plot to make it smoother:

binoNormal.ecPlotDeltas(periods = 30)


Plotting price w.r.t. current spot:

binoNormal.ecPlotPrice()


Changing strike for plot:

binoNormal.ecPlotPrice(strike = 40)


Plotting price w.r.t. periods used in binomial tree:

binoNormal.ecPlotPeriods()


Plotting binomial spot tree with distribution of last period:

binoNormal.plotSpots()


Changing number of periods in tree (with T remaining the same)

binoNormal.plotSpots(periods = 30)


Replicating portfolios

The program calculates option prices in each node through risk-neutral pricing, then calculates the replicating portfolios after (it was faster that way).
Any difference between the risk-neutral pricing result, and the replicating portfolio pricing should only be due to rounding errors.

Setting the portoflios parameter to True will include the replicating portfolios as separate sheets in the Excel file. (This will slow down excecution, especially if periods is high)

binoNormal = bt.tree(params = parsNormal, 
                     rounding = 2, 
                     portfolios = True,  
                     write = True # setting write to True makes an Excel file from construction
                     )
**! The errors are to be fixed !**

Discrete dividends

Discrete dividends can be passed through the discdiv parameter:

discdiv = [(1/12, 2)]

F tree

For discrete dividends, the F solution will be the default as it is faster than nonrec:

parsF = dict(fname = 'Ftree', 
             spot = 50, strike = 50, 
             dt = 1/12, periods = 3, 
             vola = 0.30, r = 0.03, 
             dtfreq = 'm')

binoF = bt.tree(params = parsF, 
                discdiv = [(1/12, 2)])

Non-recombining tree

For discrete dividends -> non-recombining tree.
Obtained by passing nonrec as True

parsNonrec = dict(fname = 'nonrecTree',  
                  spot = 50, strike = 50,  
                  dt = 1/12, periods = 3,  
                  vola = 0.30, r = 0.03,  
                  dtfreq = 'm')

binoNonrec = bt.tree(params = parsNonrec, 
                     discdiv = [(1/12, 2)], nonrec = True)

binoNonrec.write()

Object as callable

The tree object is callable, meaning an instance of the object can be used as a function.
This can be handy for getting values in loops or quickly getting new values without re-specifying all the parameters.
As a default the class will make american call and put, aswell as european call and put, unless the maketrees keyword states otherwise. If only one or some specific option types are needed, it would be more efficient to specify which types to make.

Example:

As periods becomes large (i.e., dt becomes small), the rounding parameter needs to be sufficiently large to avoid miscalculation.

pars = dict(fname = 'myTree', 
            spot = 50, strike = 50, 
            dt = 1/12, periods = 3, 
            vola = 0.30, r = 0.03, 
            dtfreq = 'm', rounding = 8)

binoNormal = bt.tree(params = pars, 
                     maketrees = ['ec', 'ep'])

ec_ep_50periods = binoNormal(['ecOptionPrice', 'epOptionPrice'], periods = 50)  
ec_ep_50periods = {'ecOptionPrice': 3.15373942, 
                   'epOptionPrice': 2.78014216}

Returns the european call and put price with all parameters remaining the same, except periods being 50.

In a loop:

ecList = []

for i in range(1, 100):
    ecList.append(binoNormal(['ecOptionPrice'], maketrees = ['ec'], periods = i))

Makes a list of the european call price.


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

binotree-1.0.3.tar.gz (2.3 MB view details)

Uploaded Source

Built Distribution

binotree-1.0.3-py3-none-any.whl (2.3 MB view details)

Uploaded Python 3

File details

Details for the file binotree-1.0.3.tar.gz.

File metadata

  • Download URL: binotree-1.0.3.tar.gz
  • Upload date:
  • Size: 2.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/3.10.0 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.5

File hashes

Hashes for binotree-1.0.3.tar.gz
Algorithm Hash digest
SHA256 f3d7fe377f79fd3eea2b52cdbeb08c8c5da62998bd972df7f423d337c456bf71
MD5 8f5f51c9a7340b92ec9abed03f31c1ed
BLAKE2b-256 2bb298c23ef8d08016c6eb353fdbd2bc90e061c82e93e648d3922a209ae19eb5

See more details on using hashes here.

File details

Details for the file binotree-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: binotree-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 2.3 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/3.10.0 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.5

File hashes

Hashes for binotree-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 567e7bf26b719c89b18f059d60491e982fad57a65273d21e9b18af8840bd36a8
MD5 208ffbbb081bea62ab473cb5090e8b3b
BLAKE2b-256 349f5c0588c93dcb572678485d28bf4feb6fa4366d65cb85ab6320ceb95bba69

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page