Checkout finmath-experiments from git and run maven (mvn
or mvnw
) from
its directory. This will start a JShell.
See Getting Started for details.
In the experiments on the Monte-Carlo simulation a simulation object and a product object has been created and the delta of option has been evaluated using finite difference. Repeat this:
Create the model and its simulation:
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.*;
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
var td = new TimeDiscretizationFromArray(0.0, 300, 0.01);
var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(td, 1, 10000, 3231);
var process = new EulerSchemeFromProcessModel(model, brownianMotion);
// Using the process (Euler scheme), create an MC simulation of a Black-Scholes model
var simulation = new MonteCarloAssetModel(process);
Create the product:
import net.finmath.montecarlo.assetderivativevaluation.products.*;
double maturity = 3.0;
double strike = 106.0;
var europeanOption = new EuropeanOption(maturity, strike);
We like to calculate a finite difference approximation of the partial derivative of the value \( V \) (being europeanOption.getValue(0.0, simulation)
) with respect to \( S_{0} \) (being the initialValue
of simulation
) that is \( \partial V/ \partial S_{0} \approx \frac{V(M(S_0+h))-V(M(S_0-h))}{2h} \) (where \( M(x) \) refers to the model with the initial value \( x \)).
The object simulation
has a method getCloneWithModifiedData(Map)
which allows to create a new simulation with modified data. As argument we pass a Map
of the parameters to modify, in our case
Map.of("initialValue", modelInitialValue+h))
double h = 1E-2;
var valueUpShift = europeanOption.getValue(simulation.getCloneWithModifiedData(Map.of("initialValue", modelInitialValue+h)));
var valueDownShift = europeanOption.getValue(simulation.getCloneWithModifiedData(Map.of("initialValue", modelInitialValue-h)));
var deltaNumerical = (valueUpShift - valueDownShift) / (2 * h);
model
(and hence to the simulation
): we “inject” a factory creating AD enabled random variables into the model. As a result, the value calculated has the additional method getGradient
.
The difference of the following experiment is line
RandomVariableFactory randomVariableFactory = new RandomVariableDifferentiableAADFactory();
creating a factory to create AAD enabled RandomVariables, and passing it to the model
var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility, randomVariableFactory);
Injecting the factory has the effect that
var valueOfEuropeanOption = (RandomVariableDifferentiable) europeanOption.getValue(0.0, simulation);
returns an object of type RandomVariableDifferentiableAAD
.
Remark: The code below requires that the object europeanOption
has been initialised. If you haven't done so you can and execute it before.
europeanOption
has been created in Experiment 3)
import net.finmath.montecarlo.*;
import net.finmath.montecarlo.assetderivativevaluation.*;
import net.finmath.montecarlo.assetderivativevaluation.models.*;
import net.finmath.montecarlo.automaticdifferentiation.*;
import net.finmath.montecarlo.automaticdifferentiation.backward.*;
import net.finmath.montecarlo.process.*;
import net.finmath.time.*;
double modelInitialValue = 100.0;
double modelRiskFreeRate = 0.05;
double modelVolatility = 0.20;
RandomVariableFactory randomVariableFactory = new RandomVariableDifferentiableAADFactory();
// Create a model
var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility, randomVariableFactory);
// Create a corresponding MC process
var td = new TimeDiscretizationFromArray(0.0, 300, 0.01);
var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(td, 1, 10000, 3231);
var process = new EulerSchemeFromProcessModel(model, brownianMotion);
// Using the process (Euler scheme), create an MC simulation of a Black-Scholes model
var simulation = new MonteCarloAssetModel(process);
var valueOfEuropeanOption = (RandomVariableDifferentiable) europeanOption.getValue(0.0, simulation);
var initialValue = (RandomVariableDifferentiable) model.getInitialValue(process)[0];
var deltaPathwise = valueOfEuropeanOption.getGradient().get(initialValue.getID());
var deltaValue = deltaPathwise.average().doubleValue();
0.6736406559419106
(compare this to the finite difference approximation 0.6736119988879352
.
The variable deltaPathwise
is the algorithmic differentiation of valueOfEuropeanOption
with respect to the variable initialValue
. It is a path-wise derivative \( \partial V(t_{n},\omega_{k}) / \partial S(t_{0},\omega_{k}) \) (note: the initial value is a deterministic random variable, i.e. \( S(t_{0}, \omega_{k}) \equiv S_{0} \quad \forall k \)). Hence deltaPathwise
is a random variable too - the path wise differentiation of the (discounted) payoff with respect to \( S_{0} \). We may plot this path-wise differentiation:
import net.finmath.plots.*;
var underlying = simulation.getAssetValue(maturity, 0 /* assetIndex */);
var plot = Plots.createHistogramBehindValues(underlying, deltaPathwise, 100 /* bins */, 5.0 /* stddev */);
plot.setTitle("European option path-wise delta and distribution of underlying");
plot.setXAxisLabel("underlying").setYAxisLabel("path-wise delta");
plot.show();
RandomVariableDifferentiableAADFactory
we use RandomVariableDifferentiableADFactory
, that is AD instead of AAD. The class RandomVariableDifferentiableADFactory
resides in the package
automaticdifferentiation.forward
in net.finmath.montecarlo
, while the
class RandomVariableDifferentiableADFactory
resides in
automaticdifferentiation.backward
in net.finmath.montecarlo
.
europeanOption
has been created)
import net.finmath.montecarlo.*;
import net.finmath.montecarlo.assetderivativevaluation.*;
import net.finmath.montecarlo.assetderivativevaluation.models.*;
import net.finmath.montecarlo.automaticdifferentiation.*;
import net.finmath.montecarlo.automaticdifferentiation.forward.*;
import net.finmath.montecarlo.process.*;
import net.finmath.time.*;
double modelInitialValue = 100.0;
double modelRiskFreeRate = 0.05;
double modelVolatility = 0.20;
RandomVariableFactory randomVariableFactory = new RandomVariableDifferentiableADFactory();
// Create a model
var model = new BlackScholesModel(modelInitialValue, modelRiskFreeRate, modelVolatility, randomVariableFactory);
// Create a corresponding MC process
var td = new TimeDiscretizationFromArray(0.0, 300, 0.01);
var brownianMotion = new BrownianMotionFromMersenneRandomNumbers(td, 1, 10000, 3231);
var process = new EulerSchemeFromProcessModel(model, brownianMotion);
// Using the process (Euler scheme), create an MC simulation of a Black-Scholes model
var simulation = new MonteCarloAssetModel(process);
var valueOfEuropeanOption = (RandomVariableDifferentiable) europeanOption.getValue(0.0, simulation);
var initialValue = (RandomVariableDifferentiable) model.getInitialValue(process)[0];
var deltaPathwise = valueOfEuropeanOption.getGradient().get(initialValue.getID());
var deltaValue = deltaPathwise.average().doubleValue();
0.6736406559419106
(identical to the AAD implementation).