SwaptionATM.java

package net.finmath.montecarlo.interestrate.products;

import net.finmath.exception.CalculationException;
import net.finmath.marketdata.model.curves.DiscountCurve;
import net.finmath.marketdata.model.curves.ForwardCurve;
import net.finmath.marketdata.products.Swap;
import net.finmath.marketdata.products.SwapAnnuity;
import net.finmath.montecarlo.interestrate.TermStructureMonteCarloSimulationModel;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.RegularSchedule;
import net.finmath.time.TimeDiscretization;
import net.finmath.time.TimeDiscretizationFromArray;

/**
 * A lightweight ATM swaption product used for calibration.
 *
 * @author Stefan Sedlmair
 * @author Christian Fries
 * @version 1.0
 */
public class SwaptionATM extends AbstractTermStructureMonteCarloProduct implements net.finmath.modelling.products.Swaption {

	private final TimeDiscretization	tenor;
	private final ValueUnit						valueUnit;

	public SwaptionATM(final double[] swapTenor, final ValueUnit valueUnit) {
		super();
		tenor = new TimeDiscretizationFromArray(swapTenor);
		this.valueUnit = valueUnit;
	}

	@Override
	public RandomVariable getValue(final double evaluationTime, final TermStructureMonteCarloSimulationModel model) throws CalculationException {

		final ForwardCurve forwardCurve	 = model.getModel().getForwardRateCurve();
		final DiscountCurve discountCurve = model.getModel().getAnalyticModel() != null ? model.getModel().getAnalyticModel().getDiscountCurve(forwardCurve.getDiscountCurveName()) : null;

		final double optionMaturity = tenor.getTime(0);
		final double swapAnnuity = discountCurve != null ? SwapAnnuity.getSwapAnnuity(tenor, discountCurve) : SwapAnnuity.getSwapAnnuity(tenor, forwardCurve);

		// Swaption is per definition at the money in this class
		final double parSwapRate = Swap.getForwardSwapRate(new RegularSchedule(tenor), new RegularSchedule(tenor), forwardCurve, model.getModel().getAnalyticModel());

		// define an atm swaption
		final TermStructureMonteCarloProduct swaption = new Swaption(tenor.getTime(0), tenor, parSwapRate);

		// get swaption value
		final RandomVariable optionValue = swaption.getValue(evaluationTime, model);

		switch (valueUnit) {
		case VALUE:
			return optionValue;
		case VOLATILITYNORMAL:
			return getImpliedBachelierATMOptionVolatility(optionValue, optionMaturity, swapAnnuity);
		case INTEGRATEDVARIANCENORMAL:
		case INTEGRATEDNORMALVARIANCE:
			return getImpliedBachelierATMOptionVolatility(optionValue, optionMaturity, swapAnnuity).squared().mult(optionMaturity);
		default:
			throw new IllegalArgumentException("Unknown valueUnit: " + valueUnit.name());
		}
	}

	/**
	 * 	Calculates ATM Bachelier implied volatilities.
	 *
	 * @see net.finmath.functions.AnalyticFormulas#bachelierOptionImpliedVolatility(double, double, double, double, double)
	 *
	 * @param optionValue RandomVarable representing the value of the option
	 * @param optionMaturity Time to maturity.
	 * @param swapAnnuity The swap annuity as seen on valuation time.
	 * @return The Bachelier implied volatility.
	 */
	public RandomVariable getImpliedBachelierATMOptionVolatility(final RandomVariable optionValue, final double optionMaturity, final double swapAnnuity){
		return optionValue.average().mult(Math.sqrt(2.0 * Math.PI / optionMaturity) / swapAnnuity);
	}
}