BarrierOptionBlackScholesModelBoundary.java
package net.finmath.finitedifference.assetderivativevaluation.boundaries;
import net.finmath.finitedifference.assetderivativevaluation.models.FDMBlackScholesModel;
import net.finmath.finitedifference.assetderivativevaluation.products.BarrierOption;
import net.finmath.finitedifference.assetderivativevaluation.products.FiniteDifferenceEquityProduct;
import net.finmath.finitedifference.boundaries.BoundaryCondition;
import net.finmath.finitedifference.boundaries.StandardBoundaryCondition;
import net.finmath.modelling.products.BarrierType;
import net.finmath.modelling.products.CallOrPut;
/**
* Boundary conditions for {@link BarrierOption} under the {@link
* FDMBlackScholesModel}.
*
* <p>
* This class supports the explicit boundary-condition API returning
* {@link BoundaryCondition} objects.
* </p>
*
* <p>
* Conventions:
* </p>
* <ul>
* <li>For knock-out options, the rebate is paid at hit, so the barrier-side
* boundary is pinned to the rebate.</li>
* <li>For knock-in options, the outer boundaries use the corresponding
* vanilla Black-Scholes asymptotics.</li>
* <li>The barrier is assumed to coincide with one spatial boundary of the grid
* for direct knock-out pricing:
* down barriers at the lower boundary, up barriers at the upper boundary.</li>
* </ul>
*
* <p>
* In the direct two-state knock-in solver, the activated regime should use
* these
* vanilla asymptotic boundaries, while the inactive regime is coupled to the
* activated regime on the hit set.
* </p>
*
* @author Alessandro Gnoatto
*/
public class BarrierOptionBlackScholesModelBoundary implements FiniteDifferenceBoundary {
/**
* The epsilon.
*/
private static final double EPSILON = 1E-6;
/**
* The model.
*/
private final FDMBlackScholesModel model;
/**
* Performs the operation.
*
* @param model The value.
*/
public BarrierOptionBlackScholesModelBoundary(final FDMBlackScholesModel model) {
this.model = model;
}
@Override
public BoundaryCondition[] getBoundaryConditionsAtLowerBoundary(
final FiniteDifferenceEquityProduct product,
double time,
final double... stateVariables) {
final BarrierOption option = (BarrierOption) product;
final BarrierType barrierType = option.getBarrierType();
final CallOrPut sign = option.getCallOrPut();
/*
* For a down-and-out option, the lower boundary is the barrier-side
* boundary,
* so the value is pinned to the rebate (paid at hit).
*
* For all other cases, including down-in, use vanilla asymptotics.
*/
if (barrierType == BarrierType.DOWN_OUT) {
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(option.getRebate())
};
}
if (sign == CallOrPut.CALL) {
/*
* Vanilla call asymptotic at S -> 0.
*/
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(0.0)
};
} else {
/*
* Vanilla put asymptotic at S -> 0:
* V(t,S) ~ K exp(-r(T-t)).
*/
time = Math.max(time, EPSILON);
final double discountFactorRiskFree =
model.getRiskFreeCurve().getDiscountFactor(time);
final double riskFreeRate =
-Math.log(discountFactorRiskFree) / time;
final double strike = option.getStrike();
final double maturity = option.getMaturity();
final double value =
strike * Math.exp(-riskFreeRate * (maturity - time));
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(value)
};
}
}
@Override
public BoundaryCondition[] getBoundaryConditionsAtUpperBoundary(
final FiniteDifferenceEquityProduct product,
double time,
final double... stateVariables) {
final BarrierOption option = (BarrierOption) product;
final BarrierType barrierType = option.getBarrierType();
final CallOrPut sign = option.getCallOrPut();
/*
* For an up-and-out option, the upper boundary is the barrier-side
* boundary,
* so the value is pinned to the rebate (paid at hit).
*
* For all other cases, including up-in, use vanilla asymptotics.
*/
if (barrierType == BarrierType.UP_OUT) {
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(option.getRebate())
};
}
if (sign == CallOrPut.CALL) {
/*
* Vanilla call asymptotic at large S:
* V(t,S) ~ S exp(-q(T-t)) - K exp(-r(T-t)).
*/
time = Math.max(time, EPSILON);
final double discountFactorRiskFree =
model.getRiskFreeCurve().getDiscountFactor(time);
final double riskFreeRate =
-Math.log(discountFactorRiskFree) / time;
final double discountFactorDividend =
model.getDividendYieldCurve().getDiscountFactor(time);
final double dividendYieldRate =
-Math.log(discountFactorDividend) / time;
final double strike = option.getStrike();
final double maturity = option.getMaturity();
final double stateVariable = stateVariables[0];
final double dividendAdjustedStockPrice =
stateVariable * Math.exp(-dividendYieldRate * (maturity - time));
final double value =
dividendAdjustedStockPrice
- strike * Math.exp(-riskFreeRate * (maturity - time));
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(value)
};
} else {
/*
* Vanilla put asymptotic at large S.
*/
return new BoundaryCondition[] {
StandardBoundaryCondition.dirichlet(0.0)
};
}
}
}