CevActiveBoundaryProvider.java

package net.finmath.finitedifference.assetderivativevaluation.boundaries;

import net.finmath.finitedifference.assetderivativevaluation.models.FiniteDifferenceEquityModel;
import net.finmath.finitedifference.solvers.TwoStateActiveBoundaryProvider;
import net.finmath.modelling.products.CallOrPut;

/**
 * Active-state outer boundary provider for the direct two-state knock-in solver
 * under a CEV-type equity model.
 *
 * <p>
 * The active state represents the post-activation value, i.e. the corresponding
 * vanilla European option after the barrier has been hit.
 * </p>
 *
 * <p>
 * This provider uses the same vanilla asymptotic structure as the existing 1D
 * CEV boundary treatment:
 * </p>
 * <ul>
 *   <li>Lower boundary:
 *     <ul>
 *       <li>call: 0</li>
 *       <li>put: K exp(-r(T-t))</li>
 *     </ul>
 *   </li>
 *   <li>Upper boundary:
 *     <ul>
 *       <li>call: S - K exp(-r(T-t))</li>
 *       <li>put: 0</li>
 *     </ul>
 *   </li>
 * </ul>
 */
public class CevActiveBoundaryProvider implements TwoStateActiveBoundaryProvider {

	/**
	 * The epsilon.
	 */
	private static final double EPSILON = 1E-10;

	/**
	 * The model.
	 */
	private final FiniteDifferenceEquityModel model;
	/**
	 * The strike.
	 */
	private final double strike;
	/**
	 * The maturity.
	 */
	private final double maturity;
	/**
	 * The call or put.
	 */
	private final CallOrPut callOrPut;

	/**
	 * Performs the operation.
	 *
	 * @param model The value.
	 * @param strike The value.
	 * @param maturity The value.
	 * @param callOrPut The value.
	 */
	public CevActiveBoundaryProvider(
			final FiniteDifferenceEquityModel model,
			final double strike,
			final double maturity,
			final CallOrPut callOrPut) {
		this.model = model;
		this.strike = strike;
		this.maturity = maturity;
		this.callOrPut = callOrPut;
	}

	@Override
	public double getLowerBoundaryValue(final double time, final double stateVariable) {
		final double t = Math.max(time, EPSILON);
		final double discountFactorRiskFree = model.getRiskFreeCurve().getDiscountFactor(t);
		final double riskFreeRate = -Math.log(discountFactorRiskFree) / t;

		if (callOrPut == CallOrPut.CALL) {
			return 0.0;
		} else {
			return strike * Math.exp(-riskFreeRate * (maturity - time));
		}
	}

	@Override
	public double getUpperBoundaryValue(final double time, final double stateVariable) {
		final double t = Math.max(time, EPSILON);
		final double discountFactorRiskFree = model.getRiskFreeCurve().getDiscountFactor(t);
		final double riskFreeRate = -Math.log(discountFactorRiskFree) / t;

		if (callOrPut == CallOrPut.CALL) {
			return stateVariable - strike * Math.exp(-riskFreeRate * (maturity - time));
		} else {
			return 0.0;
		}
	}
}