SwaprateCovarianceAnalyticApproximation.java

/*
 * (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
 *
 * Created on 10.11.2007
 */
package net.finmath.montecarlo.interestrate.products;

import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.AbstractMonteCarloProduct;
import net.finmath.montecarlo.MonteCarloSimulationModel;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.montecarlo.interestrate.LIBORMarketModel;
import net.finmath.montecarlo.interestrate.LIBORModelMonteCarloSimulationModel;
import net.finmath.montecarlo.model.ProcessModel;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.TimeDiscretization;

/**
 * This class implements an analytic approximation of the integrated instantaneous covariance
 * of two swap rates under a LIBOR market model.
 *
 * @author Christian Fries
 * @version 1.0
 */
public class SwaprateCovarianceAnalyticApproximation extends AbstractMonteCarloProduct {

	private final double[]    swapTenor1;       // Vector of swap tenor (period start and end dates).
	private final double[]    swapTenor2;       // Vector of swap tenor (period start and end dates).

	/**
	 * Create the product implementing the analytic approximation of a swap rate covariance in a forward rate model.
	 *
	 * @param swapTenor1 The swap tenor of the first rate in doubles.
	 * @param swapTenor2 The swap tenor of the second rate in doubles.
	 */
	public SwaprateCovarianceAnalyticApproximation(final double[] swapTenor1, final double[] swapTenor2) {
		super();
		this.swapTenor1 = swapTenor1;
		this.swapTenor2 = swapTenor2;
	}

	@Override
	public RandomVariable getValue(final double evaluationTime, final MonteCarloSimulationModel model) throws CalculationException {
		if(!(model instanceof LIBORModelMonteCarloSimulationModel)) {
			throw new IllegalArgumentException("This product requires a simulation of type LIBORModelMonteCarloSimulationModel where the underlying model is of type LIBORMarketModel.");
		}

		final ProcessModel modelBase = ((LIBORModelMonteCarloSimulationModel)model).getModel();
		if(modelBase instanceof LIBORMarketModel) {
			return getValues(evaluationTime, model.getTimeDiscretization(), (LIBORMarketModel)modelBase);
		} else {
			throw new IllegalArgumentException("This product requires a simulation where the underlying model is of type LIBORMarketModel.");
		}
	}

	/**
	 * Calculates the approximated integrated instantaneous covariance of two swap rates,
	 * using the approximation d log(S(t))/d log(L(t)) = d log(S(0))/d log(L(0)).
	 *
	 * @param evaluationTime The evaluation time.
	 * @param timeDiscretization The time discretization used for integrating the covariance.
	 * @param model A model implementing the LIBORMarketModelFromCovarianceModel
	 * @return Returns the approximated integrated instantaneous covariance of two swap rates.
	 */
	public RandomVariable getValues(final double evaluationTime, final TimeDiscretization timeDiscretization, final LIBORMarketModel model) {

		final int swapStartIndex1  = model.getLiborPeriodIndex(swapTenor1[0]);
		final int swapEndIndex1    = model.getLiborPeriodIndex(swapTenor1[swapTenor1.length-1]);

		final int swapStartIndex2  = model.getLiborPeriodIndex(swapTenor2[0]);
		final int swapEndIndex2    = model.getLiborPeriodIndex(swapTenor2[swapTenor2.length-1]);

		final int optionMaturityIndex = model.getCovarianceModel().getTimeDiscretization().getTimeIndex(Math.min(swapTenor1[0], swapTenor2[0]));

		final double[]  swapCovarianceWeights1  = SwaptionSingleCurveAnalyticApproximation.getLogSwaprateDerivative(model.getLiborPeriodDiscretization(), model.getForwardRateCurve(), swapTenor1).get("values");
		final double[]  swapCovarianceWeights2  = SwaptionSingleCurveAnalyticApproximation.getLogSwaprateDerivative(model.getLiborPeriodDiscretization(), model.getForwardRateCurve(), swapTenor2).get("values");

		// Get the integrated libor covariance from the model
		final double[][]	integratedLIBORCovariance = model.getIntegratedLIBORCovariance(timeDiscretization)[optionMaturityIndex];

		// Calculate integrated swap rate covariance
		double integratedSwapRateCovariance = 0.0;

		for(int componentIndex1 = swapStartIndex1; componentIndex1 < swapEndIndex1; componentIndex1++) {
			// Sum the libor cross terms (use symmetry)
			for(int componentIndex2 = swapStartIndex2; componentIndex2 < swapEndIndex2; componentIndex2++) {
				integratedSwapRateCovariance += swapCovarianceWeights1[componentIndex1-swapStartIndex1] * swapCovarianceWeights2[componentIndex2-swapStartIndex2] * integratedLIBORCovariance[componentIndex1][componentIndex2];
			}
		}

		return new RandomVariableFromDoubleArray(evaluationTime, integratedSwapRateCovariance);
	}
}