Code Monkey home page Code Monkey logo

willowtree's Introduction

Willow Tree

willowtree is an open source Python implementation of Michael Curran's derivatives pricing model of the same name.

Curran, M. (2001): Willow Power: Optimizing Derivative Pricing Trees

willow-tree

What is the Willow Tree?

The willow tree is a highly efficient, recombining lattice designed for fast and accurate pricing of derivative contracts. It models the standard Brownian motion directly, by means of a discrete time Markov chain, and the resulting estimate can serve as the basis for more complex processes, such as the geometric Brownian motion.

The lattice has two distinctive features:

  • it expands as the square root of time, in accordance with the Brownian motion and unlike the binomial model, which grows linearly in time. It opens quite fast at the beginning, covering a high-probability region neglected by standard trees, and slowly later on, being constrained within a set confidence region of the normal marginal distribution. This aspect both prevents the waste of time and computational resources on the tails of the distribution, areas with little impact on the definition of the current price of the security, and avoids the arbitrary practice of pruning the tree, namely, disregarding branches, along with their offsprings, located in low probability regions;

  • it has a constant number of nodes per time step. With time, this number grows linearly, and not quadratically, as it does in the binomial model.

These features increase the efficiency of the lattice, because they force the paths to travel across a smaller structure squeezed in the body of the desired density, and allow for a fast convergence to the true, unknown price distribution.

Main Features

Being a proxy for the standard Brownian motion, willowtree can:

  • help price a wide array of European and American derivative contracts;
  • be considerably faster than other lattices, such as the binomial and trinomial, especially in higher dimensions: once a set of transition matrices is generated, it can be stored and becomes available for future use;
  • serve as building block for more complex processes (e.g. the geometric Brownian motion) and models (e.g. stochastic volatility, interest rate), of particular relevance in finance, engineering, and physics.

Documentation

A detailed history of the model, as well as the mathematical theory behind it, are available in the companion handbook.

Dependencies

willowtree requires Python 3.5+, and is built on top of the following modules:

  • NumPy: v. 1.13+
  • SciPy: v. 0.19+
  • Matplotlib: v. 2.0+
  • Seaborn: v. 0.8+

Installation

The source code is currently hosted on GitHub at: https://github.com/federicomariamassari/willowtree. Either clone or download the git repository. To clone the repository, on either Terminal (macOS) or Command Prompt (Windows) enter the folder inside which you want the repository to be, possibly changing directory with cd <desired path>, and execute:

$ git clone https://github.com/federicomariamassari/willowtree.git

When the process is over, navigate through folder willowtree using cd willowtree and run:

$ python3 setup.py install

or, if only Python 3 is present on your system, simply:

$ python setup.py install

Then, within a Python environment, e.g. IDLE or Jupyter Notebook, execute:

import willowtree

or use wt as alias:

import willowtree as wt

Finally, call any of its modules, e.g. sampling, as either: willowtree.sampling or wt.sampling based on the previous choice.

To check which version of willowtree is actually installed, use willowtree.__version__.

For help on individual functions, call the built-in function help, e.g. help(willowtree.sampling) or help(sampling) if you chose from willowtree import sampling.

License

willowtree is offered under the MIT License.

Contributing

willowtree is a small but continuously evolving project open to anyone willing to contribute—simply fork the repository and modify its content. Any improvements, especially in making the code more readable (or Pythonic) or faster is more than welcome. For git commits, it is desirable to follow Udacity's Git Commit Message Style Guide.

Feel free to bookmark, or "star", the repository if you find this project interesting!

Future Directions

Presently, willowtree only handles one-dimensional lattices, implemented according to Xu, Hong, and Qin's methodology. Future versions will try to focus on:

  • presenting more algorithms to build the tree (e.g. Haussmann and Yan, 2004);
  • accounting for multi-dimensionality (e.g. Lu and Xu, 2017).

Latest Updates

October 28, 2017

Following commit 3531721, willowtree is now a package which can be installed from setup.py.

October 24, 2017

Following commit ab317d5 the willow tree has become a very precise and robust algorithm. It returns well-behaved Markov chains by generating accurate transition matrices and, if this is not possible, by either replacing wrong ones with interpolated versions (giving rise to the characteristic black patches, as in the figure below) or shortening the chain as appropriate.

willow-tree

Why the black patches? Adjacent, well-defined transition matrices have positive probabilities in different cells. When these matrices are used to interpolate one in between, the resulting object is less sparse, with a larger number of paths drawn.

Known Issues

  • Inability to choose gamma = 0, with gamma in [0, 1], as parameter value in the model. Commit f014907 partially fixes the issue by increasing gamma by steps of 1e-9 (first two seconds of runtime), 1e-6 (additional 8 seconds), and 1e-2 until the optimisation is successful. This method ensures that a solution is found with a value of gamma as close as possible to the one supplied by the user, and in a reasonable amount of time.

  • Significant slowness for n > 20. The bottleneck is the linear programming algorithm: each iteration (for a particular tolerance level) may take a very long time, and cannot be stopped unless the optimizer is run in a separate process, using Python's multiprocessing module. This may not be a problem if the matrices are to be stored and used at a later time, but it is nevertheless something that should be dealt with.

For a list of all open and closed issues, please visit the issue section.

willowtree's People

Contributors

federicomariamassari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

willowtree's Issues

Bug: LP algorithm occasionally returns probabilities outside range.

When n << k, the linear programming algorithm occasionally returns probabilities which are outside the range [0, 1]. For instance, when n = 11 and k = 20, with gamma = 0.1, the command P[P<0] produces:

array([-0.0014, -0.0477, -0.0067, -0.1186, -0.0222, -0.0024, -0.038 ,
       -0.0844, -0.1443, -0.0119, -0.21  , -0.0259, -0.0394])

Since the sum of the probabilities in each row of the Markov chain must be one, some zero probabilities are actually given a small positive value. This results in spurious paths being drawn (i.e. unusually long paths almost crossing an entire segment of the lattice structure), as in the last two steps of the figure below.

replaced2w

Enhancement: Scrap last matrices in the chain if bad.

Commit 02d210a improves the stability of the linear programming function, which now replaces any badly specified transition matrix with a new one, obtained through linear interpolation of the two nearest, well-defined, matrices.

However, the interpolation algorithm breaks if the last matrix in the Markov chain is bad (exit flag: -1).

It would be better to return a shorter Markov chain, obtained by scrapping all adjacent bad matrices at the end of the sequence, rather than simply breaking the algorithm and returning a wrong chain.

Enhancement: Replace wrongly specified transition matrices.

Commit ae8d537 introduces function lp, which uses linear programming to find the set of transition matrices part of the Markov chain.

Although the matrices are generally well-defined, occasionally some may not be. This happens, for instance, when k, the number of time steps, is much larger than n, the number of space nodes.

Consider the case n = 20, k = 29, in the figure below. One can clearly see that two of the generated transition matrices are wrong.

to_replace

Inspection of the flag array, which assigns a value to each terminated linear programming problem (0: success; -1: failure), shows that these are P[14] and P[24]:

failure = np.nonzero(flag)[0]

produces as output array([14, 24]).

Curran [1] provides a formula to linearly interpolate from two known well-defined transition matrices which must be, respectively, on the left and on the right of a bad matrix. A future commit should replace such bad matrices with interpolated ones, in order to produce correct willow trees.

[1] Curran, M.: Willow Power: Optimizing Derivative Pricing Trees, ALGO Research Quarterly, Vol. 4, No. 4, p. 15, December 2001

Enhancement: Plot willow tree even if no transition matrix is well-defined. Case: k > 1.

At the moment, when no transition matrix in the Markov chain is well-defined, the algorithm breaks.
This occurs, for instance, with n = 5 (originally n = 2), gamma = 0.36 (originally gamma = 0), and k = 4.

Optimisation could not be terminated with supplied parameters.
Optimisation successful with n = 5 and gamma = 0.360000000.
Total running time: 25.10s
Warning: P[0] wrongly specified.
Replacing with interpolated matrix if possible.
Warning: P[1] wrongly specified.
Replacing with interpolated matrix if possible.
Warning: P[2] wrongly specified.
Replacing with interpolated matrix if possible.

Causing the following IndexError:

IndexError: index 0 is out of bounds for axis 0 with size 0

Bug: Probabilities on rows of transition matrices do not sum to 1.

Occasionally, linear programming returns transition matrices whose probabilities in each row do not sum to one. For example, with n = 20, gamma = 0.3, k = 10, and although extra_precision is set to True, the algorithm gives:

[P[i].sum(axis=1) for i in range(len(P))]
[array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,
         1.,  1.,  1.,  1.,  1.,  1.,  1.]),
 array([ 1.        ,  1.        ,  1.        ,  1.        ,  0.99989258,
         1.        ,  0.97871713,  0.99999619,  0.99217539,  1.        ,
         0.9807556 ,  1.00298074,  1.00321644,  1.        ,  0.99150473,
         0.99843469,  1.00141081,  0.98617653,  1.00841513,  1.        ]),
 array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,
         1.,  1.,  1.,  1.,  1.,  1.,  1.]),
 array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,
         1.,  1.,  1.,  1.,  1.,  1.,  1.]),
 array([ 1.        ,  1.00000001,  1.        ,  0.99899848,  1.00219072,
         0.99999895,  0.99987461,  1.00062558,  0.99999999,  0.99899456,
         0.99999998,  1.00025193,  0.9996113 ,  0.99960293,  0.99932418,
         0.99937719,  1.0006753 ,  1.000327  ,  0.99911012,  1.        ]),
 array([ 1.        ,  1.00000001,  1.        ,  0.99893545,  1.00232859,
         0.99999888,  0.99986672,  1.00066495,  0.99999999,  0.99893128,
         0.99999998,  1.00026779,  0.99958684,  0.99957794,  0.99928165,
         0.999338  ,  1.00071779,  1.00034758,  0.99905412,  1.        ])]

Enhancement: Use Python's multiprocessing to speed up the algorithm.

Currently, the linear programming problem is the bottleneck of the willow tree algorithm, since the additional constraint on probabilities, i.e. return no p such that p < 0 or p > 1, make it considerably sluggish for ~n >= 20.

Python's multiprocessing module should allow to terminate any linear programming problem if it takes too long, to continue with the next one, and to replace the wrong transition matrix with an interpolated version, if possible.

Enhancement: Scrap first matrices in the chain if bad.

The case in which a bad transition matrix occurs at the beginning of a Markov chain is much less common than the opposite one (see issue #2), but nevertheless breaks the interpolation algorithm. This happens, for example, when n = 9, k = 20, and gamma = 0.

Vector q should automatically link to the first available well-defined transition matrices, and the first bad ones should be scrapped.

Bug: Last replaceable matrix in the chain not replaced; vector t always shortened.

Commit 7fb3f7a improves the stability of the interpolation algorithm but introduces two important issues. The first issue is that the algorithm completely ignores the last matrix of the chain which could easily be interpolated because in-between two well-defined ones. The second is that t, the vector of time nodes, is always shortened, even when it is not required (as in the case in which the last transition matrix is well-defined).

Last replaceable matrix in the chain not replaced

Consider the case n = 14, k = 22, gamma = 0.2, T = 1. When the algorithm is run, the output is:

P[0] successfully generated.
...
P[11] successfully generated.
Warning: P[12] wrongly specified. Replacing with interpolated matrix if possible.
P[13] successfully generated.
Warning: P[14] wrongly specified. Replacing with interpolated matrix if possible.
P[15] successfully generated.
Warning: P[16] wrongly specified. Replacing with interpolated matrix if possible.
P[17] successfully generated.
...
P[20] successfully generated.

The first two matrices are then replaced with their linearly interpolated versions:

Interpolation of P[12] successful.
Interpolation of P[14] successful.

However, the last one P[16], which is also a good candidate for interpolation since it is between two well-defined transition matrices, is not.

Vector of time nodes shortened every time

In the same example, although no matrix in the chain needs to be scrapped, vector t is nevertheless shortened by one step:

Vector t has been shortened. T = 0.9545

Bug: IndexError when P[0] is bad and only one matrix in the chain is well-behaved.

Currently, when P[0] is bad and only one matrix in the Markov chain is well-behaved, the algorithm returns an IndexError in the lp function:

IndexError: index 1 is out of bounds for axis 0 with size 1

This error is connected to how array t is shortened to account for irrreplaceable transition matrices at the two ends of the chain.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.