Package: binotree
Binomial Tree for Options PricingMotivation: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).Thewrite()method will generate an Excel file with the result.DividendsThe class can take dividends into account (dividend yieldanddiscrete dividends).
It has 2 ways of solving for discrete dividends, the 'F solution' and 'non-recombining'.F solutionSubtracts the present value from current spot, and makes binomial tree based on this
'pre-paid forward'.Non-recombining treeAs 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 importInstallationThe project can be installed frompipwith the command:pip install binotreeQuickstartPassing argumentsimportbinotreeasbtparameters=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:importbinotreeasbttreeObject=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:importbinotreeasbtparameters=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 consoleEuropean call/put and american call/put are all calculated by default
(can be changed through themaketreesparameter).Thebt.treeobject will store a tree object for each option type calculated.Access the european call tree as such:treeObject.ecTreedt ->      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 fileSimply call thewrite()method to write to excel file. Pass thedirecparameter
in construction to specify directory
(if none is passed, the working directory is used).importbinotreeasbtparameters=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.xlsxThe file should look something like this:(each option type is given its own sheet in the excel file)Full parameter specificationParameters specificationHow to pass parameters/arguments:There are 2 ways of parsing arguments:A dictionaryKeyword 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, thehelp()method will print help for specifying parametersSpot and strikeBoth must be passedspotstrikeTime and period specificationMust be in terms of years (e.g., maturity in 6 months would beT = 6/12).The variabledtfreqcan be passed as a string ('d','w', or'm') for
prettier formatting in output.2 of 3 must be passedTdtperiodsInterest rate, dividend yield, and continuous compounding0 of 3mustbe passedrrcontdivyieldVolatility and up/down movements1 of 3 must be passedvolaudFor custom function for calculating up/down movements,
seeudfunc specification.Dividends0 of 2mustbe passeddiscdivnonrecDirectory for Excel output0 of 4mustbe passeddirecfolnamefnamewriteVarious0 of 5mustbe passedcollapsedmaketreesheaderformatroundingmakedfsportfoliosshowIntrinsicExamples of useimportsimportbinotreeasbtNormal treeSimple 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 defaultdtfreq='m',rounding=4)binoNormal=bt.tree(params=parsNormal)Tree previewThe binomial tree for the European Call is accessed bybinoNormal.ecTreeCallable treeIn case your binomial tree is big and won't print neatly you can access each node by
calling the tree object withupanddownpassed:write()methodtypingbinoNormal.write()in the console an Excel file will be generated. Either in the
current working directory, or passed directory through thedirecparameter.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.xlsxPlotting methodsThe plotting methods can take in keywords to alter the original parametersPlotting 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 (withTremaining the same)binoNormal.plotSpots(periods = 30)ReplicatingportfoliosThe 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 theportofliosparameter toTruewill include the replicating portfolios as
separate sheets in the Excel file. (This will slow down excecution, especially ifperiodsis 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 dividendsDiscrete dividends can be passed through thediscdivparameter:discdiv=[(1/12,2)]F treeFor 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 treeFor discrete dividends -> non-recombining tree.Obtained by passingnonrecasTrueparsNonrec=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 callableThe 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 themaketreeskeyword 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=[]foriinrange(1,100):ecList.append(binoNormal(['ecOptionPrice'],maketrees=['ec'],periods=i))Makes a list of the european call price.