finMath.net

# Bermudan Option Valuation in a Monte-Carlo Simulation of Black-Scholes Model

Getting Started

Checkout finmath-experiments from git and run maven (mvn or mvnw) from its directory. This will start a JShell. See Getting Started for details.

# Experiment 1-3: Monte-Carlo Valuation of a Bermudan Option: Optimal Exercise and Foresight

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

## Experiment 1

The following will value a Bermudan option with two exercise dates $$T_{1}$$ and $$T_{2}$$, with the right to receive either $$S(T_{1})-K_{1}$$ in $$T_{1}$$ or $$S(T_{2})-K_{2}$$ in $$T_{2}$$ or nothing.

Since we assume a Black-Scholes model, the second option can be valued analytically using the Black-Scholes formula, and hence, the exercise criteria for the first exercise date is known analytically.

We calculate the numeraire relative Bermudan exercise value $$U(T)/N(T)$$ where $$T$$ is the optimal exercise time - a stochastic time being either $$T_{1}$$ or $$T_{2}$$. And $$U(T)[\omega]$$ is given by

• $$U(T_{1},\omega) = \max(S(T_{1},\omega)-K_{1},0)$$ if $$U(T_{1},\omega) > V_{2}(T_{1},\omega)$$
• $$U(T_{2},\omega) = \max(S(T_{2},\omega)-K_{2},0)$$ else,
where $$V_{2}(T_{1})$$ is the time $$T_{1}$$ value of the time $$T_{2}$$ option $$\max(S(T_{2},\omega)-K_{2},0)$$ (which - in this special example - can be calculated analytically).

Form this, the Bermudan value is given by the unconditional expectation $N(0) \mathrm{E}\Big( \frac{U(T)}{N(T)} \Big) \text{.}$

In addition, we value the super-optimal exercise using 'perfect foresight' where the super-optimal exercise criteria uses the future on-path value. This strategy is wrong. We consider it for illustration.

JShell:


import java.awt.Color;
import java.awt.Rectangle;
import java.util.List;

import net.finmath.functions.AnalyticFormulas;
import net.finmath.montecarlo.BrownianMotion;
import net.finmath.montecarlo.BrownianMotionFromMersenneRandomNumbers;
import net.finmath.montecarlo.assetderivativevaluation.MonteCarloAssetModel;
import net.finmath.montecarlo.assetderivativevaluation.models.BlackScholesModel;
import net.finmath.montecarlo.process.EulerSchemeFromProcessModel;
import net.finmath.montecarlo.process.MonteCarloProcess;
import net.finmath.plots.GraphStyle;
import net.finmath.plots.Plot;
import net.finmath.plots.Plot2D;
import net.finmath.plots.Plotable2D;
import net.finmath.plots.PlotablePoints2D;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.TimeDiscretizationFromArray;

double initialValue = 100.0;
double riskFreeRate = 0.05;
double volatility = 0.30;

double initialTime = 0.0;
double timeHorizon = 2.0;
double dt = 1.0;

int numberOfPaths = 5000;
int seed = 3141;

double maturity1 = 1.0;
double strike1 = 120.0;

double maturity2 = 2.0;
double strike2 = 140.0;

BlackScholesModel blackScholesModel = new BlackScholesModel(initialValue, riskFreeRate, volatility);
BrownianMotion bm = new BrownianMotionFromMersenneRandomNumbers(new TimeDiscretizationFromArray(initialTime, (int)Math.round(timeHorizon/dt), dt), 1, numberOfPaths, seed);
MonteCarloProcess process = new EulerSchemeFromProcessModel(blackScholesModel, bm);
MonteCarloAssetModel model = new MonteCarloAssetModel(process);

RandomVariable stockInT2 = model.getAssetValue(maturity2, 0);		// S(T2)
RandomVariable stockInT1 = model.getAssetValue(maturity1, 0);		// S(T1)

RandomVariable valueOption2InT2 = stockInT2.sub(strike2).floor(0.0);	// max(S(T2)-K,0)
RandomVariable valueOption1InT1 = stockInT1.sub(strike1).floor(0.0);	// max(S(T1)-K,0)
RandomVariable valueOption2InT1 = AnalyticFormulas.blackScholesOptionValue(stockInT1, riskFreeRate, volatility, maturity2-maturity1, strike2);

// Convert all time T-values to numeraire relative values by dividing by N(T)
RandomVariable valueRelativeOption2InT2 = valueOption2InT2.div(model.getNumeraire(maturity2));
RandomVariable valueRelativeOption1InT1 = valueOption1InT1.div(model.getNumeraire(maturity1));
RandomVariable valueRelativeOption2InT1 = valueOption2InT1.div(model.getNumeraire(maturity1));

.choose(valueRelativeOption2InT2, valueRelativeOption1InT1);

RandomVariable bermudanPathwiseValueForesight = valueRelativeOption2InT2.sub(valueRelativeOption1InT1)
.choose(valueRelativeOption2InT2, valueRelativeOption1InT1);

var bermudanValueWithForsight = bermudanPathwiseValueForesight.mult(model.getNumeraire(0.0)).getAverage();


Run in JShell, this prints out the values


bermudanValueWithForsight ==> 11.904281948764233
bermudanValue ==> 9.209824685660006

That is, the value of the Bermudan option is ≈ 9.21. Performing super-optimal exercise with an non-admissible strategy results in a value of ≈ 11.9.

## Experiment 2

The following code has to be run after Experiment 1 in the same JShell, since it requires initialization of variables from there.

The following code will create a scatter plot illustrating the optimal exercise of a Bermudan option with two exercise dates $$T_{1}$$ and $$T_{2}$$, with the right to receive either $$S(T_{1})-K_{1}$$ in $$T_{1}$$ or $$S(T_{2})-K_{2}$$ in $$T_{2}$$ or nothing.

JShell:


import java.awt.Color;
import java.awt.Rectangle;
import java.util.List;

import net.finmath.plots.GraphStyle;
import net.finmath.plots.Plot;
import net.finmath.plots.Plot2D;
import net.finmath.plots.Plotable2D;
import net.finmath.plots.PlotablePoints2D;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.TimeDiscretizationFromArray;

/*
* Plot the stuff
*/
Plotable2D continuationValues = PlotablePoints2D.of("Continuation Value max(S(T\u2082)-K\u2082, 0)", stockInT1, valueRelativeOption2InT2, new GraphStyle(new Rectangle(-1,-1,2,2), null, Color.RED));
Plotable2D exerciseValues = PlotablePoints2D.of("Underlying 1 (S(T\u2081)-K\u2081)", stockInT1, valueRelativeOption1InT1, new GraphStyle(new Rectangle(-3,-3,5,5), null, Color.GREEN));
Plotable2D expectedContinuationValue = PlotablePoints2D.of("Black Scholes Value of Option on S(T\u2082)-K\u2082", stockInT1, valueRelativeOption2InT1, new GraphStyle(new Rectangle(-3,-3,5,5),null, Color.BLUE));
Plotable2D bermudanPathwiseValueAdmissiblePlot = PlotablePoints2D.of("Bermudan exercise value", stockInT1, bermudanPathwiseValueAdmissible, new GraphStyle(new Rectangle(-1,-1,2,2), null, new Color(0.0f, 0.66f, 0.0f)));
Plotable2D bermudanPathwiseValueForesightPlot = PlotablePoints2D.of("Exercise value with foresight", stockInT1, bermudanPathwiseValueForesight, new GraphStyle(new Rectangle(-1,-1,2,2), null, new Color(0.50f, 0.50f, 0.0f)));

Plot plotBermudanExercise = new Plot2D(
List.of(
continuationValues,
exerciseValues,
expectedContinuationValue)
)
.setYRange(-5, 150)
.setIsLegendVisible(true)
.setXAxisLabel("S(T\u2081)")
.setYAxisLabel("V\u2081(T\u2081), V\u2082(T\u2081), V\u2082(T\u2082)")
.setTitle("Time T\u2081 and T\u2082 values related to a Bermudan option with exercises in T\u2081 and T\u2082.");
plotBermudanExercise.show();

The code will bring up the following plot: The plot shows simulations points for different simulation paths (scenarios) ω of the following points

• light green: $$(S(T_{1},\omega), \max(S(T_{1},\omega)-K_{1},0))$$: the exercise value in $$T_{1}$$ as a function of $$S(T_{1},\omega)$$
• red: $$(S(T_{1},\omega), \max(S(T_{2},\omega)-K_{2},0))$$: the exercise value in $$T_{2}$$ as a 'function' of $$S(T_{1},\omega)$$
• blue: $$(S(T_{1},\omega), V_{2}(T_{1},\omega))$$: the conditional expectation of the $$T_{2}$$-exercise value, conditional to $$T_{1}$$ as a function of $$S(T_{1},\omega)$$, given by the Black-Scholes formula.
• dark green: $$(S(T_{1},\omega), U(T)[\omega])$$: the Bermudan optimal exercise value as a function of $$S(T_{1},\omega)$$, where the optimal exercise value $$U(T)[\omega]$$ is given by $$U(T_{1},\omega) = \max(S(T_{1},\omega)-K_{1},0)$$ if $$U(T_{1},\omega) > V_{2}(T_{1},\omega)$$ $$U(T_{2},\omega) = \max(S(T_{2},\omega)-K_{2},0)$$ else.

## Experiment 3

The following code creates a similar plot as in the previous Experiment 2, but uses 'perfect foresight' for the exercise decision, by 'looking into the future'. This strategy is wrong. We plot it for illustration.

The code just differs in a single line, that we plot bermudanPathwiseValueForesightPlot instead of bermudanPathwiseValueAdmissiblePlot.

The code has to be run after Experiment 1 or 2 in the same JShell, since it requires initialization of variables from there.

JShell:


import java.awt.Color;
import java.awt.Rectangle;
import java.util.List;

import net.finmath.plots.GraphStyle;
import net.finmath.plots.Plot;
import net.finmath.plots.Plot2D;
import net.finmath.plots.Plotable2D;
import net.finmath.plots.PlotablePoints2D;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.TimeDiscretizationFromArray;

/*
* Plot the stuff
*/
Plotable2D continuationValues = PlotablePoints2D.of("Continuation Value max(S(T\u2082)-K\u2082, 0)", stockInT1, valueRelativeOption2InT2, new GraphStyle(new Rectangle(-1,-1,2,2), null, Color.RED));
Plotable2D exerciseValues = PlotablePoints2D.of("Underlying 1 (S(T\u2081)-K\u2081)", stockInT1, valueRelativeOption1InT1, new GraphStyle(new Rectangle(-3,-3,5,5), null, Color.GREEN));
Plotable2D expectedContinuationValue = PlotablePoints2D.of("Black Scholes Value of Option on S(T\u2082)-K\u2082", stockInT1, valueRelativeOption2InT1, new GraphStyle(new Rectangle(-3,-3,5,5),null, Color.BLUE));
Plotable2D bermudanPathwiseValueAdmissiblePlot = PlotablePoints2D.of("Bermudan exercise value", stockInT1, bermudanPathwiseValueAdmissible, new GraphStyle(new Rectangle(-1,-1,2,2), null, new Color(0.0f, 0.66f, 0.0f)));
Plotable2D bermudanPathwiseValueForesightPlot = PlotablePoints2D.of("Exercise value with foresight", stockInT1, bermudanPathwiseValueForesight, new GraphStyle(new Rectangle(-1,-1,2,2), null, new Color(0.50f, 0.50f, 0.0f)));

Plot plotBermudanExerciseWithForesight = new Plot2D(
List.of(
bermudanPathwiseValueForesightPlot,
continuationValues,
exerciseValues,
expectedContinuationValue)
)
.setYRange(-5, 150)
.setIsLegendVisible(true)
.setXAxisLabel("S(T\u2081)")
.setYAxisLabel("V\u2081(T\u2081), V\u2082(T\u2081), V\u2082(T\u2082)")
.setTitle("Time T\u2081 and T\u2082 values related to a Bermudan option with exercises in T\u2081 and T\u2082.");
plotBermudanExerciseWithForesight.show();
plotBermudanExerciseWithForesight.saveAsSVG(new File("BermudanExerciseForesight.svg"),900,600);

The code will bring up the following plot: The plot shows simulations points for different simulation paths (scenarios) ω of the following points

• light green: $$(S(T_{1},\omega), \max(S(T_{1},\omega)-K_{1},0))$$: the exercise value in $$T_{1}$$ as a function of $$S(T_{1},\omega)$$
• red: $$(S(T_{1},\omega), \max(S(T_{2},\omega)-K_{2},0))$$: the exercise value in $$T_{2}$$ as a 'function' of $$S(T_{1},\omega)$$
• blue: $$(S(T_{1},\omega), V_{2}(T_{1},\omega))$$: the conditional expectation of the $$T_{2}$$-exercise value, conditional to $$T_{1}$$ as a function of $$S(T_{1},\omega)$$, given by the Black-Scholes formula.
• brown: $$(S(T_{1},\omega), \max(\max(S(T_{1},\omega)-K_{1},0), \max(S(T_{2},\omega)-K_{2},0)))$$: the Bermudan super-optimal exercise value by maximizing on every path, which is not an admissible strategy, since the decision is not $$\mathcal{F}_{T_{1}}$$-measurable.

## Summary (Experiments 1-3)

We have created a valuation of a Bermudan option in a Black-Scholes model and illustrated the effect of using a wrong exercise strategy using perfect foresight.

In this example, the admissible exercise strategy was known analytically, since the Bermuan had only two exercise dates and the model allowed for an analytic valuation of the European option.

## Where to continue

You may continue with