finMath.net

Monte-Carlo Simulation of a Black Scholes Model

Getting started

The experiments below use Java JShell started from a Maven project as a starting point (if you already started JShell from finmath-experiments you may continue in that shell, although it is safer to /exit that shell and restart a new one).
  1. Open a command shell
  2. Type mkdir git (to create a folder git, if you do not have one)
  3. Type cd git (to enter your git folder)
  4. Next, clone (i.e. download) the repository (git), change to the cloned directory (cd) and start jshell via Maven (mvn) by typing the following three commands:
Terminal Window

				git clone https://github.com/finmath/finmath-experiments        
				cd finmath-experiments
				mvn clean compile jshell:run
			

Experiment 0-4: Monte-Carlo Simulation and Valuation

Run the following experiment from your JShell (which was launched from finmath-experiments).

Experiment 0

The following will create an object of type TimeDiscretizationFromArray (from the package net.finmath.time) and then print the object (using the toString()-method). The time discretization starts in 0.0 and has 100 time steps of size 0.1.
JShell:

				var td = new net.finmath.time.TimeDiscretizationFromArray(0.0, 100, 0.1);
				td.toString();
			
We may shorten the name of object by importing a classes from the package or all classes from the packages (like name-spaces), e.g. here from net.finmath.time via import net.finmath.time.*;.

Experiment 1

In the following experiment we create a class of type BrownianMotionLazyInit (from the package net.finmath.montecarlo) which represent samples of a set of (independent) normal distributed random variables \( \Delta W(t_{i}) \) (the so called Brownian increments). The arguments of BrownianMotionLazyInit are (timeDiscretization, numberOfFactors, numberOfPaths, seed), where numberOfFactors refers to the vector dimension of \( \Delta W(t_{i}) \). In the following we create a one factor (i.e., one dimensional) Brownian motion:

JShell:

				import net.finmath.montecarlo.*;
				import net.finmath.plots.*;
				import net.finmath.time.*;
				
				var td = new TimeDiscretizationFromArray(0.0, 100, 0.1);
				var bm = new BrownianMotionLazyInit(td, 1, 10000, 3213);   // change number of paths
				var x = bm.getBrownianIncrement(0,0);
			
To plot a histogram of the random variable x enter
JShell:

				var plot = Plots.createPlotOfHistogram(x, 100, 5.0);
				plot.setTitle("Histogram").setXAxisLabel("value").setYAxisLabel("frequency");
				plot.show();
			
For fun, you may also create an animation:
JShell:

				for(int i=2; i<100; i+=1) {
					int numberOfPaths = i*i*Math.max(i/10,1);
					Plots.updatePlotOfHistogram(plot, (new BrownianMotionLazyInit(td, 1, numberOfPaths, 3213)).getBrownianIncrement(0,0), 100, 5.0);
					Thread.sleep(100);
				}
			

Experiment 2

Given a Brownian motion providing the Brownian increments \( \Delta W(t_{i}) \), we create a model (here a BlackScholesModel) and from that a simulation of this model using an Euler scheme (via EulerSchemeFromProcessModel). The model is \( \mathrm{d}S(t) = r S(t) \mathrm{d} + \sigma(t) S(t) \mathrm{d}W(t) ; \quad S(t_{0}) = S_{0} \), where \( S(t_{0}) \) is the modelInitialValue, \( r \) is the modelRiskFreeRate, \( \sigma \) is the modelVolatility.
JShell:

				import net.finmath.montecarlo.*;
				import net.finmath.montecarlo.process.*;
				import net.finmath.montecarlo.assetderivativevaluation.*;
				import net.finmath.montecarlo.assetderivativevaluation.models.*;
				import net.finmath.stochastic.*;
				import net.finmath.time.*;
				import net.finmath.plots.*;
				
				double modelInitialValue = 100.0;
				double modelRiskFreeRate = 0.05;
				double modelVolatility = 0.20;
				
				// Create a model
				var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility);
				
				// Create a corresponding MC process from the model
				var td = new TimeDiscretizationFromArray(0.0, 300, 0.01);
				var brownianMotion = new BrownianMotionLazyInit(td, 1, 10000, 3231);
				var process = new EulerSchemeFromProcessModel(model, brownianMotion);
				
				// Create a function, plotting paths t -> S(t)
				DoubleToRandomVariableFunction paths = time -> process.getProcessValue(td.getTimeIndex(time), 0 /* assetIndex */);
				
				// Plot 100 of paths against the given time discretization.
				var plot = new PlotProcess2D(td, paths, 100);
				plot.setTitle("Black Scholes model paths").setXAxisLabel("time").setYAxisLabel("value");
				plot.show();
			

Experiment 3

We value a financial product on our simulation, that is we calculate the expectation \( E(f(S(T)) \) for, e.g. \( f(x) = \max(x - K) \). The function \( f \) represents the financial product, in the example below we use an EuropeanOption. The product provides a method getValue which implements \( E(f(S(T)) \) given a simulation providing S(T), in our example the object simulation. Note: the following requires that Experiment 2 has initialized the object simulation. We first create the product
JShell: (continued from experiment 2)

				import net.finmath.montecarlo.assetderivativevaluation.products.*;
				
				double maturity = 3.0;
				double strike = 106.0;
				
				var europeanOption = new EuropeanOption(maturity, strike);
			
Given that the objects process and europeanOption have been initialized, we can value the product against the simulation:
JShell: (continued)

				// Using the process (Euler scheme) and provide methods like getAssetValue and getNumeraire
				var simulation = new MonteCarloAssetModel(process);

				// Use the simulation to value the product				
				var valueOfEuropeanOption = europeanOption.getValue(0.0, simulation);
				var value = valueOfEuropeanOption.average().doubleValue();
			
The value reported it 18.115.... Request the standard error via
JShell: (continued)

				valueOfEuropeanOption.getStandardError();
			

The reported standard error is 0.27....

You can plot the products payoff function and the histogram of the simulated values of \( S(T) \) where \( T \) corresponds to the optionMaturity:

JShell: (continued)

				var underlying = simulation.getAssetValue(maturity, 0 /* assetIndex */);
				
				var plot = Plots.createPlotOfHistogramBehindValues(underlying, valueOfEuropeanOption, 100 /* bins */, 5.0 /* stddev */);
				plot.setTitle("European option value and distribution of underlying").setXAxisLabel("underlying").setYAxisLabel("value");
				plot.show();
			

Analytic Benchmark

We may compare the value obtained from the Monte-Carlo simulation with the analytic solution using Black-Scholes formula:

JShell: (continued)

				import net.finmath.functions.AnalyticFormulas;
				
				AnalyticFormulas.blackScholesOptionValue(modelInitialValue, modelRiskFreeRate, modelVolatility, maturity, strike);
			
The value reported is 17.984... .

Summary (Experiments 1-3)

We have created a simulation, calculated the value of a European option.

Where to continue

You may continue with