Monte Carlo framework


Detailed Description

Warning: this section of the documentation is currently outdated.

This framework (corresponding to the ql/MonteCarlo directory) contains basic building blocks for the numerical calculation of the integral

\[ \int_{\Omega} f(\mathbf{x}) p(\mathbf{x}) d \mathbf{x} \]

where $ p(\mathbf{x}) $ is a normalized probability function. Monte Carlo methods solve the above integral by approximating it with the discrete sum

\[ \frac{1}{N} \sum_{i=1}^{N} f(\mathbf{x}_i) w(\mathbf{x}_i) \]

where the $ \mathbf{x}_i $ are drawn from $ p(\mathbf{x}) $, possibly with a weight $ w(\mathbf{x}_i) $ --- which otherwise can be considered uniformly equal to 1.

The above sum has a straightforward interpretation in the case of a derivative product, namely, the $ \mathbf{x}_i $ are $ N $ generated random paths which the value of the underlying can possibly follow, while the $ f(\mathbf{x}_i) $ are the values of the derivative on each of such paths. The sum above can therefore be taken as an estimate of the price of the derivative, namely, the average of its value on all possible paths --- or rather all considered paths. Such a method enables the user to construct pricing classes for an unlimited range of derivatives, most notably path-dependent ones which cannot be priced by means of finite difference methods.

It must also be mentioned that for all such methods, the error $ e $ on the estimated value is proportional to the square root of the number of samples $ N $. A number of so-called variance-reduction methods have been found which allows one to reduce the coefficient of proportionality between $ e $ and $ 1/\sqrt{N} $.

Separate implementations are provided in the library for the three components of the above average, namely, the random drawing of the $ \mathbf{x}_i $, the evaluation of the $ f(\mathbf{x}_i) $, and the averaging process itself. The QuantLib::MonteCarloModel class acts as a glue for such three steps --- which are outlined in the following sections --- and provides the interface of the resulting Monte Carlo model to the end user.

Path generation

The Black-Scholes equation

\[ \frac{\partial f}{\partial t} + \frac{\sigma^2}{2} \frac{\partial^2 f}{\partial x^2} + \nu \frac{\partial f}{\partial x} - r f = 0, \]

where $ r $ is the risk-free rate, $ \sigma $ is the volatility of the underlying, and $ \nu = r - \sigma^2/2 $, has the form of a diffusion process. According to this heuristic interpretation (1), paths followed by the logarithm of the underlying would be Brownian random walks with a constant drift $ \nu $ per unit time and a standard deviation $ \sigma \sqrt{T} $ over a time $ T $.

Therefore, the paths to be generated for a Monte Carlo model of the Black-Scholes equation will be vectors of successive variations of the logarithm of the underlying price over $ M $ consecutive time intervals $ \Delta t_i, i = 0 \dots M-1 $. Each such variation will be drawn from a Gaussian distribution with average $ \nu \Delta T_i $ and standard deviation $ \sigma \sqrt{\Delta T_i} $ --- or possibly $ \nu_i \Delta T_i $ and $ \sigma_i \sqrt{\Delta T_i} $ should $ \nu $ and $ \sigma $ vary in time.

The QuantLib::Path class stores the variation vector decomposed in its drift (determined) and diffusion (random) components. As shown below, this allows the implementation of antithetic variance reduction techniques.

The QuantLib::MultiPath class is a straightforward extension which acts as a vector of Path objects.

Classes are provided which generate paths and multi-paths with the desired drift and diffusion components, namely, QuantLib::PathGenerator and QuantLib::MultiPathGenerator.

For the time being, the path generator is initialized with a constant drift and variance. This requirement will most likely be relaxed in the next release. The multi-path generator is initialized with an array of constant drifts---one for each single asset---and a covariance matrix which encapsulates the relations between the diffusion components of the single assets.

The time discretization of the (multi)paths can be specified either as a given number of equal time steps over a given time span, or as a vector of explicitly specified times at which the path will be sampled.

Pricing an instrument on a path

The QuantLib::PathPricer class is the base class from which path pricers must inherit. The only method which subclasses are required to implement is
double operator()(const P&) const;
where P can be Path or MultiPath depending on the derivative whose value must be calculated.

Similarly, the term path will be used in the following discussion as meaning either path or multi-path depending on the context. The term single path is not to be taken as opposite to multi-path, but rather as meaning ``a single instance of a (multi)path" as opposed to the set of all generated (multi)paths.

The above method encapsulates the pricing of the derivative on a single path and must return its value had the evolution of the underlying(s) followed the path passed as argument. For this reason, control variate techniques (see below) must not be implemented at this level since they would cause the returned value to differ from the actual price of the derivative on the path.

Instead, antithetic variance-reduction techniques can be effectively implemented at this level and indeed are used in the pricers currently included in the library.

In short, such techniques consist in pricing an option on both the given path and its antithetic, the latter being a path with the same drift and the opposite diffusion component. The value of the sample is defined as the average of the prices on the two paths.

A generic implementation of antithetic techniques could consist of a path pricer class which takes a concrete path pricer upon construction and whose operator() simply proxies two calls to the contained pricer, passing the given path and its antithetic, and averages the result. However, this would not take full advantage of the technique.

In fact, it must be noted that using antithetic paths not only reduces the variance per se but also allows to factor out calculations commons to a path and its antithetic, thus reducing greatly the computation time. Therefore, such techniques are best implemented inside the path pricer itself, whose algorithm can fully exploit such factorization.

A number of path pricers are available in the library and listed in reference manual.

Accumulating and averaging samples

The class QuantLib::MonteCarloModel encapsulates the general structure of a Monte Carlo calculations, namely, the generation of a number of paths, the pricing of the derivative on each path, and the averaging of the results to yield the actual derivative price.

As outlined above, the first two steps are delegated to a path generator and a path pricer. The third step is also delegated to an object which accumulates weighted values and returns the statistic properties of the set of such values. One such class provided by the library is QuantLib::Statistics.

The concern of the Monte Carlo model is therefore to act as a glue between such three components and can be expressed by the following pseudo-code:

given pathGenerator, pathPricer, accumulator; for i in number of samples { path,weight = pathGenerator.next(); price = pathPricer(path); accumulator.add(price,weight); }

The Monte Carlo model also provides the user with the possibility to take advantage of control-variate techniques.

Such techniques consist in pricing a portfolio from which the price of the derivative can be deduced, but with a lower variance than the derivative alone.

In our current implementation, static-hedge control variate is used, namely, the formed portfolio is long of the derivative we need to price and short of a similar derivative whose price can be calculated analytically. The value of the portfolio on a given path will of course be given by the difference of the values of the two derivatives on such path. However, due to the similarity between the derivatives, the portfolio price will have a lower variance than either derivative alone since any variation in the price of the latter will be partly compensated by a similar variation in the price of the other. Lastly, given the portfolio price, the price of the derivative we are interested in can be deduced by adding the analytic value of the other.

In order to use such technique, the user must provide the model with a path pricer for the additional option and the value of the latter. The action of the Monte Carlo model is in this case expressed as:

given pathGenerator, pathPricer, cvPathPricer, cvPrice, accumulator; for i in number of samples { path,weight = pathGenerator.next(); portfolioPrice = pathPricer(path) - cvPathPricer(path); accumulator.add(portfolioPrice+cvPrice,weight); }

Martingale (a.k.a. dynamic-hedge) control variate techniques are planned for future releases.

A QuantLib::McPricer class is also available which wraps the typical usage of a Monte Carlo model.

Details on the Monte Carlo Pricer interface will be available in the Pricers section.

Examples of Monte Carlo models

As a simple example, we will use the outlined tools to price an European option by means of Monte Carlo techniques.

Given a current underlying price $ u_0 $ and a path $ p = [ p_1, \dots, p_N ] $ where every variation $ p_i $ is the sum of a drift term $ d_i $ and a random diffusion term $ r_i $, the price of the underlying at maturity is

\[ u = u_0 \prod_1^N e^{p_i} = u_0 \exp \left( \sum_1^N p_i \right) = u_0 \exp \left( \sum_1^N d_i + \sum_1^N r_i \right) \]

while the price on the antithetic path --- i.e., same drift and opposite diffusion --- is

\[ u_0 \exp \left( \sum_1^N d_i - \sum_1^N r_i \right). \]

The corresponding path pricer can be implemented as:

class EuropeanPathPricer : public PathPricer<Path> { public: EuropeanPathPricer(Option::Type type, double underlying, double strike, DiscountFactor discount, bool useAntithetic) // just store the needed parameters : type_(type), underlying_(underlying), strike_(strike), discount_(discount), useAntithetic_(useAntithetic) {} // here is the logic double operator()(const Path& path) const { size_t n = path.size(); // factor out the sums in the formula above double sum_d = 0.0, sum_r = 0.0; for (size_t i = 0; i < n; i++) { sum_d += path.drift()[i]; sum_r += path.diffusion()[i]; } // calculate final underlying price on path double price = underlying_*QL_EXP(sum_d+sum_r); // calculate payoff double payoff; switch (type_) { case Option::Call; payoff = QL_MAX(price-strike,0.0); break; // other cases are left as an exercise to the reader ... } // current value of the option is the discounted payoff double optionValue = payoff*discount_; // stop here if not antithetic... if (!useAntithetic_) return optionValue; // ...otherwise calculate the value on the antithetic path double antiPrice = underlying_*QL_EXP(sum_d-sum_r); // calculate payoff and option value as above ... // return the average of the results on the two paths return (optionValue + antiOptionValue)/2.0; } private: // stored parameters ... };

The path pricer can now be used in a model. Let us assume the following parameters:

Option::Type type = Option::Call; double underlying = 100.0, strike = 95.0; Time residualTime = 1.0; Rate dividendYield = 0.03, riskFreeRate = 0.05; double volatility = 0.10;

The path generator can be instantiated as

// parameters of the Black-Scholes equation double vol2 = volatility*volatility; double nu = riskFreeRate - dividendYield - vol2/2.0; // in this case we are only interested in the final underlying price. // Therefore, we can cover all the residual time in one big time step. int timeSteps = 1; Handle<GaussianPathGenerator> pathGenerator( new GaussianPathGenerator(nu,vol2,residualTime,timeSteps));
where QuantLib::GaussianPathGenerator is a typedef to a path generator using the default choice for a Gaussian random number generator.

The path pricer is instantiated as

// discount at maturity DiscountFactor discount = QL_EXP(-riskFreeRate*residualTime); bool antithetic = true; Handle<PathPricer<Path> > pathPricer( new EuropeanPathPricer(type,underlying,strike,discount,antithetic));

The model can now be created and used as following:

// number of samples to be generated size_t samples = 1000000; // pass the path generator and pricer we just created and a // newly instantiated Statistics object MonteCarloModel<Statistics,GaussianPathGenerator,PathPricer> model( pathGenerator,pathPricer,Statistics()); model.addSamples(samples); // now get the results: the option price is given by value with // a confidence level given by error value = model.sampleAccumulator().mean(); error = model.sampleAccumulator().errorEstimate();

More examples of path pricers can be found in the ql/MonteCarlo directory, while examples of more sophisticated pricers which uses them in Monte Carlo models can be found in the ql/Pricers directory.

Notes

(1) A more rigorous approach would lead us to integrate the above equation by means of Green functions or Laplace transforms. Both such methods would show that the price at time $ t = 0 $ of an option with payoff $ G(S(T)) $ where $ S(T) $ is the underlying price at expiry is given by the integral

\[ \int_{-\infty}^{\infty} e^{-rT} G(S_0 e^\xi) \frac{1}{\sqrt{2 \pi \sigma^2 T}} \exp \left( -\frac{(\xi - \nu T)^2}{2 \sigma^2 T} \right) \mathrm{d} \xi \]

where $ S_0 $ is the price of the underlying at $ t = 0 $. It can be seen that the above integral is of the form shown at the beginning of this section, namely, the pricing function is

\[ f(x) = e^{-rT} G(S_0 e^x) \]

and can be interpreted as the option payoff discounted to the present time, while the probability distribution is

\[ p(x) = \frac{1}{\sqrt{2 \pi \sigma^2 T}} \exp \left( -\frac{(x - \nu T)^2}{2 \sigma^2 T} \right). \]

which again shows that the logarithms of the underlying prices at time $ T $ are distributed as a Gaussian with average $ \nu T $ and standard deviation $ \sigma \sqrt{T} $.


Classes

class  BrownianBridge
 Builds Wiener process paths using Gaussian variates. More...

class  MonteCarloModel
 General purpose Monte Carlo model for path samples. More...

class  MultiPath
 Correlated multiple asset paths. More...

class  MultiPathGenerator
 Generates a multipath from a random number generator. More...

class  Path
class  PathGenerator
 Generates random paths using a sequence generator. More...

class  PathPricer
 base class for path pricers More...

struct  Sample
 weighted sample More...


QuantLib.org
QuantLib
Hosted by
SourceForge.net Logo
Documentation generated by
doxygen