BlackScholesModelMonteCarloFiniteDifference1D.java
/*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*
* Created on 09.02.2018
*/
package net.finmath.modelling.modelfactory;
import java.util.HashMap;
import java.util.Map;
import net.finmath.finitedifference.assetderivativevaluation.models.FDMBlackScholesModel;
import net.finmath.finitedifference.assetderivativevaluation.models.FiniteDifferenceEquityModel;
import net.finmath.finitedifference.assetderivativevaluation.products.EuropeanOption;
import net.finmath.finitedifference.grids.Grid;
import net.finmath.finitedifference.grids.SpaceTimeDiscretization;
import net.finmath.finitedifference.grids.UniformGrid;
import net.finmath.finitedifference.utilities.FiniteDifferenceValueInterpolator;
import net.finmath.modelling.DescribedModel;
import net.finmath.modelling.DescribedProduct;
import net.finmath.modelling.Model;
import net.finmath.modelling.ModelFactory;
import net.finmath.modelling.ProductDescriptor;
import net.finmath.modelling.SingleAssetProductDescriptor;
import net.finmath.modelling.descriptor.BlackScholesModelDescriptor;
import net.finmath.modelling.descriptor.SingleAssetEuropeanOptionProductDescriptor;
import net.finmath.modelling.products.CallOrPut;
import net.finmath.time.FloatingpointDate;
import net.finmath.time.TimeDiscretization;
import net.finmath.time.TimeDiscretizationFromArray;
/**
* @author Christian Fries
* @version 1.0
*/
public class BlackScholesModelMonteCarloFiniteDifference1D implements ModelFactory<BlackScholesModelDescriptor> {
private final double theta;
public BlackScholesModelMonteCarloFiniteDifference1D(final double theta) {
super();
this.theta = theta;
}
@Override
public DescribedModel<BlackScholesModelDescriptor> getModelFromDescriptor(
final BlackScholesModelDescriptor modelDescriptor) {
final double initialValue = modelDescriptor.getInitialValue();
// @TODO The model does not support a curve for the forward.
final double riskFreeRate =
-Math.log(modelDescriptor.getDiscountCurveForForwardRate().getDiscountFactor(1.0));
final double volatility = modelDescriptor.getVolatility();
final int numTimesteps = 100;
final int numSpacesteps = 200;
final int numStandardDeviations = 5;
/*
* The old implementation used theta in the old FDMBlackScholesModel
* constructor. Keep the same theta here.
*
* If theta already exists as a field of this class, remove this local
* declaration and use the field instead.
*/
final double theta = 0.5;
class BlackScholesFDModel extends FDMBlackScholesModel
implements DescribedModel<BlackScholesModelDescriptor> {
BlackScholesFDModel() {
super(
initialValue,
riskFreeRate,
volatility,
createSpaceTimeDiscretization(
initialValue,
riskFreeRate,
volatility,
1.0,
numTimesteps,
numSpacesteps,
numStandardDeviations,
theta
)
);
}
@Override
public BlackScholesModelDescriptor getDescriptor() {
return modelDescriptor;
}
@Override
public DescribedProduct<? extends ProductDescriptor> getProductFromDescriptor(
final ProductDescriptor productDescriptor) {
if(productDescriptor instanceof SingleAssetEuropeanOptionProductDescriptor) {
final SingleAssetEuropeanOptionProductDescriptor europeanOptionDescriptor =
(SingleAssetEuropeanOptionProductDescriptor) productDescriptor;
final double maturity = FloatingpointDate.getFloatingPointDateFromDate(
modelDescriptor.getReferenceDate(),
europeanOptionDescriptor.getMaturity()
);
final double strike = europeanOptionDescriptor.getStrike();
class FDCallOptionProduct extends EuropeanOption
implements DescribedProduct<SingleAssetProductDescriptor> {
FDCallOptionProduct() {
super(maturity, strike, CallOrPut.CALL);
}
@Override
public Object getValue(final double evaluationTime, final Model model) {
return getValues(evaluationTime, model).get("value");
}
@Override
public Map<String, Object> getValues(
final double evaluationTime,
final Model model) {
if(!(model instanceof FiniteDifferenceEquityModel)) {
throw new IllegalArgumentException(
"Model must be a FiniteDifferenceEquityModel.");
}
final SpaceTimeDiscretization valuationDiscretization =
createSpaceTimeDiscretization(
initialValue,
riskFreeRate,
volatility,
maturity,
numTimesteps,
numSpacesteps,
numStandardDeviations,
theta
);
final FDMBlackScholesModel valuationModel =
new FDMBlackScholesModel(
initialValue,
riskFreeRate,
volatility,
valuationDiscretization
);
final double[] optionValues =
super.getValue(evaluationTime, valuationModel);
final double value =
FiniteDifferenceValueInterpolator.interpolateValue(
optionValues,
valuationDiscretization,
initialValue
);
final Map<String, Object> results = new HashMap<>();
results.put("value", value);
return results;
}
@Override
public SingleAssetProductDescriptor getDescriptor() {
return europeanOptionDescriptor;
}
}
return new FDCallOptionProduct();
}
final String name = modelDescriptor.name();
throw new IllegalArgumentException("Unsupported product type " + name);
}
}
return new BlackScholesFDModel();
}
private static SpaceTimeDiscretization createSpaceTimeDiscretization(
final double initialValue,
final double riskFreeRate,
final double volatility,
final double maturity,
final int numTimesteps,
final int numSpacesteps,
final int numStandardDeviations,
final double theta) {
final double timeHorizon = Math.max(maturity, 1.0E-8);
final double forwardValue = initialValue * Math.exp(riskFreeRate * timeHorizon);
final double varianceStock =
initialValue
* initialValue
* Math.exp(2.0 * riskFreeRate * timeHorizon)
* (Math.exp(volatility * volatility * timeHorizon) - 1.0);
final double standardDeviationStock =
Math.sqrt(Math.max(varianceStock, 0.0));
final double minimumStockPrice =
Math.max(
forwardValue - numStandardDeviations * standardDeviationStock,
0.0
);
final double maximumStockPrice =
forwardValue + numStandardDeviations * standardDeviationStock;
final Grid spaceGrid =
new UniformGrid(numSpacesteps, minimumStockPrice, maximumStockPrice);
final TimeDiscretization timeDiscretization =
new TimeDiscretizationFromArray(
0.0,
numTimesteps,
timeHorizon / numTimesteps
);
return new SpaceTimeDiscretization(
spaceGrid,
timeDiscretization,
theta,
new double[] {initialValue}
);
}
}