FDMBlackScholesModel.java
package net.finmath.finitedifference.assetderivativevaluation.models;
import java.time.LocalDate;
import net.finmath.finitedifference.assetderivativevaluation.boundaries.FDBoundaryFactory;
import net.finmath.finitedifference.assetderivativevaluation.boundaries.FiniteDifferenceBoundary;
import net.finmath.finitedifference.assetderivativevaluation.products.FiniteDifferenceEquityProduct;
import net.finmath.finitedifference.boundaries.BoundaryCondition;
import net.finmath.finitedifference.grids.SpaceTimeDiscretization;
import net.finmath.marketdata.model.curves.CurveInterpolation.ExtrapolationMethod;
import net.finmath.marketdata.model.curves.CurveInterpolation.InterpolationEntity;
import net.finmath.marketdata.model.curves.CurveInterpolation.InterpolationMethod;
import net.finmath.marketdata.model.curves.DiscountCurve;
import net.finmath.marketdata.model.curves.DiscountCurveInterpolation;
import net.finmath.marketdata.model.volatilities.ConstantLocalVolatility;
import net.finmath.marketdata.model.volatilities.LocalVolatility;
/**
* Finite difference model for option pricing under the Black-Scholes framework
* for European and American options.
*
* <p>
* The model supports both the classical constant-volatility Black-Scholes case
* and the local-volatility case. Constant volatility is represented internally
* as a {@link ConstantLocalVolatility}.
* </p>
*
* @author Alessandro Gnoatto (this version)
* @author Christian Fries, Ralph Rudd, Jorg Kienitz (original version)
*/
public class FDMBlackScholesModel implements FiniteDifferenceEquityModel {
/**
* The initial value.
*/
private final double initialValue;
/**
* The risk free curve.
*/
private final DiscountCurve riskFreeCurve;
/**
* The volatility.
*/
private final LocalVolatility volatility;
/**
* The dividend yield curve.
*/
private final DiscountCurve dividendYieldCurve;
/**
* The space time discretization.
*/
private final SpaceTimeDiscretization spaceTimeDiscretization;
/**
* Minimum time used to avoid division by zero.
*/
private static final double MINIMUM_TIME = 1.0E-6;
/**
* Constructs a Black-Scholes finite difference model for option pricing.
*
* @param initialValue Initial spot price.
* @param riskFreeCurve Risk-free discount curve.
* @param dividendYieldCurve Dividend yield discount curve.
* @param volatility Constant volatility of the underlying asset.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final DiscountCurve riskFreeCurve,
final DiscountCurve dividendYieldCurve,
final double volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this(
initialValue,
riskFreeCurve,
dividendYieldCurve,
new ConstantLocalVolatility(volatility),
spaceTimeDiscretization
);
}
/**
* Constructs a local-volatility finite difference model for option pricing.
*
* @param initialValue Initial spot price.
* @param riskFreeCurve Risk-free discount curve.
* @param dividendYieldCurve Dividend yield discount curve.
* @param volatility Local volatility function.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final DiscountCurve riskFreeCurve,
final DiscountCurve dividendYieldCurve,
final LocalVolatility volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this.initialValue = initialValue;
this.riskFreeCurve = riskFreeCurve;
this.dividendYieldCurve = dividendYieldCurve;
this.volatility = volatility;
this.spaceTimeDiscretization = spaceTimeDiscretization;
}
/**
* Constructs a Black-Scholes finite difference model for option pricing
* without
* dividend yield.
*
* @param initialValue Initial spot price.
* @param riskFreeCurve Risk-free discount curve.
* @param volatility Constant volatility of the underlying asset.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final DiscountCurve riskFreeCurve,
final double volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this(
initialValue,
riskFreeCurve,
new ConstantLocalVolatility(volatility),
spaceTimeDiscretization
);
}
/**
* Constructs a local-volatility finite difference model for option pricing
* without dividend yield.
*
* @param initialValue Initial spot price.
* @param riskFreeCurve Risk-free discount curve.
* @param volatility Local volatility function.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final DiscountCurve riskFreeCurve,
final LocalVolatility volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this.initialValue = initialValue;
this.riskFreeCurve = riskFreeCurve;
final double[] times = new double[] {0.0, 1.0};
final double[] givenAnnualizedZeroRates = new double[] {0.0, 0.0};
final InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR;
final InterpolationEntity interpolationEntity = InterpolationEntity.LOG_OF_VALUE_PER_TIME;
final ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.CONSTANT;
final DiscountCurve dividendYieldCurve =
DiscountCurveInterpolation.createDiscountCurveFromAnnualizedZeroRates(
"dividendCurve",
LocalDate.of(2010, 8, 1),
times,
givenAnnualizedZeroRates,
interpolationMethod,
extrapolationMethod,
interpolationEntity);
this.dividendYieldCurve = dividendYieldCurve;
this.volatility = volatility;
this.spaceTimeDiscretization = spaceTimeDiscretization;
}
/**
* Constructs a Black-Scholes finite difference model for option pricing.
*
* @param initialValue Initial spot price.
* @param riskFreeRate Constant risk-free rate.
* @param dividendYieldRate Constant dividend yield rate.
* @param volatility Constant volatility of the underlying asset.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final double riskFreeRate,
final double dividendYieldRate,
final double volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this(
initialValue,
riskFreeRate,
dividendYieldRate,
new ConstantLocalVolatility(volatility),
spaceTimeDiscretization
);
}
/**
* Constructs a local-volatility finite difference model for option pricing.
*
* @param initialValue Initial spot price.
* @param riskFreeRate Constant risk-free rate.
* @param dividendYieldRate Constant dividend yield rate.
* @param volatility Local volatility function.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final double riskFreeRate,
final double dividendYieldRate,
final LocalVolatility volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this.initialValue = initialValue;
final double[] times = new double[] {0.0, 1.0};
final double[] givenAnnualizedZeroRates = new double[] {riskFreeRate, riskFreeRate};
final InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR;
final InterpolationEntity interpolationEntity = InterpolationEntity.VALUE;
final ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.CONSTANT;
final DiscountCurve riskFreeCurve =
DiscountCurveInterpolation.createDiscountCurveFromAnnualizedZeroRates(
"dividendCurve",
null,
times,
givenAnnualizedZeroRates,
interpolationMethod,
extrapolationMethod,
interpolationEntity);
this.riskFreeCurve = riskFreeCurve;
final double[] times1 = new double[] {0.0, 1.0};
final double[] givenAnnualizedZeroRates1 = new double[] {dividendYieldRate, dividendYieldRate};
final InterpolationMethod interpolationMethod1 = InterpolationMethod.LINEAR;
final InterpolationEntity interpolationEntity1 = InterpolationEntity.VALUE;
final ExtrapolationMethod extrapolationMethod1 = ExtrapolationMethod.CONSTANT;
final DiscountCurve dividendYieldCurve =
DiscountCurveInterpolation.createDiscountCurveFromAnnualizedZeroRates(
"dividendCurve",
null,
times1,
givenAnnualizedZeroRates1,
interpolationMethod1,
extrapolationMethod1,
interpolationEntity1);
this.dividendYieldCurve = dividendYieldCurve;
this.volatility = volatility;
this.spaceTimeDiscretization = spaceTimeDiscretization;
}
/**
* Constructs a Black-Scholes finite difference model for option pricing
* without
* dividend yield.
*
* @param initialValue Initial spot price.
* @param riskFreeRate Constant risk-free rate.
* @param volatility Constant volatility of the underlying asset.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final double riskFreeRate,
final double volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this(
initialValue,
riskFreeRate,
new ConstantLocalVolatility(volatility),
spaceTimeDiscretization
);
}
/**
* Constructs a local-volatility finite difference model for option pricing
* without dividend yield.
*
* @param initialValue Initial spot price.
* @param riskFreeRate Constant risk-free rate.
* @param volatility Local volatility function.
* @param spaceTimeDiscretization Grid object defining the spatial
* discretization.
*/
public FDMBlackScholesModel(
final double initialValue,
final double riskFreeRate,
final LocalVolatility volatility,
final SpaceTimeDiscretization spaceTimeDiscretization) {
this.initialValue = initialValue;
final double[] times = new double[] {0.0, 1.0};
final double[] givenAnnualizedZeroRates = new double[] {riskFreeRate, riskFreeRate};
final InterpolationMethod interpolationMethod = InterpolationMethod.LINEAR;
final InterpolationEntity interpolationEntity = InterpolationEntity.VALUE;
final ExtrapolationMethod extrapolationMethod = ExtrapolationMethod.CONSTANT;
final DiscountCurve riskFreeCurve =
DiscountCurveInterpolation.createDiscountCurveFromAnnualizedZeroRates(
"dividendCurve",
LocalDate.of(2010, 8, 1),
times,
givenAnnualizedZeroRates,
interpolationMethod,
extrapolationMethod,
interpolationEntity);
this.riskFreeCurve = riskFreeCurve;
final double[] times1 = new double[] {0.0, 1.0};
final double[] givenAnnualizedZeroRates1 = new double[] {0.0, 0.0};
final InterpolationMethod interpolationMethod1 = InterpolationMethod.LINEAR;
final InterpolationEntity interpolationEntity1 = InterpolationEntity.VALUE;
final ExtrapolationMethod extrapolationMethod1 = ExtrapolationMethod.CONSTANT;
final DiscountCurve dividendYieldCurve =
DiscountCurveInterpolation.createDiscountCurveFromAnnualizedZeroRates(
"dividendCurve",
LocalDate.of(2010, 8, 1),
times1,
givenAnnualizedZeroRates1,
interpolationMethod1,
extrapolationMethod1,
interpolationEntity1);
this.dividendYieldCurve = dividendYieldCurve;
this.volatility = volatility;
this.spaceTimeDiscretization = spaceTimeDiscretization;
}
@Override
public DiscountCurve getRiskFreeCurve() {
return riskFreeCurve;
}
/**
* Returns the initial value, i.e. the spot value, of the underlying.
*
* @return The initial value.
*/
@Override
public double[] getInitialValue() {
return new double[] {initialValue};
}
@Override
public double[] getDrift(final double time, final double... stateVariables) {
final double effectiveTime = time == 0.0 ? MINIMUM_TIME : time;
final double[] result = new double[1];
final double rF = getRiskFreeCurve().getDiscountFactor(effectiveTime);
final double riskFreeRate = -Math.log(rF) / effectiveTime;
final double dY = getDividendYieldCurve().getDiscountFactor(effectiveTime);
final double dividendYieldRate = -Math.log(dY) / effectiveTime;
result[0] = (riskFreeRate - dividendYieldRate) * stateVariables[0];
return result;
}
@Override
public double[][] getFactorLoading(final double time, final double... stateVariables) {
final double[][] result = new double[1][1];
final double assetValue = stateVariables[0];
result[0][0] = volatility.getValue(time, assetValue) * assetValue;
return result;
}
/**
* Returns the volatility function.
*
* @return The local volatility function.
*/
public LocalVolatility getVolatility() {
return volatility;
}
/**
* Returns the constant volatility if the model has been constructed with a
* constant volatility.
*
* @return The constant volatility.
*/
public double getConstantVolatility() {
if (volatility instanceof ConstantLocalVolatility) {
return ((ConstantLocalVolatility) volatility).getVolatility();
}
throw new IllegalStateException("The model is not using a constant volatility.");
}
@Override
public DiscountCurve getDividendYieldCurve() {
return dividendYieldCurve;
}
@Override
public SpaceTimeDiscretization getSpaceTimeDiscretization() {
return spaceTimeDiscretization;
}
@Override
public BoundaryCondition[] getBoundaryConditionsAtLowerBoundary(
final FiniteDifferenceEquityProduct product,
final double time,
final double... riskFactors) {
final FiniteDifferenceBoundary boundary =
FDBoundaryFactory.createBoundary(this, product);
return boundary.getBoundaryConditionsAtLowerBoundary(product, time, riskFactors);
}
@Override
public BoundaryCondition[] getBoundaryConditionsAtUpperBoundary(
final FiniteDifferenceEquityProduct product,
final double time,
final double... riskFactors) {
final FiniteDifferenceBoundary boundary =
FDBoundaryFactory.createBoundary(this, product);
return boundary.getBoundaryConditionsAtUpperBoundary(product, time, riskFactors);
}
@Override
public FiniteDifferenceEquityModel getCloneWithModifiedSpaceTimeDiscretization(
final SpaceTimeDiscretization newSpaceTimeDiscretization) {
return new FDMBlackScholesModel(
initialValue,
riskFreeCurve,
dividendYieldCurve,
volatility,
newSpaceTimeDiscretization
);
}
}