SwapAnnuity.java

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

import net.finmath.marketdata2.model.AnalyticModel;
import net.finmath.marketdata2.model.AnalyticModelFromCurvesAndVols;
import net.finmath.marketdata2.model.curves.Curve;
import net.finmath.marketdata2.model.curves.DiscountCurveFromForwardCurve;
import net.finmath.marketdata2.model.curves.DiscountCurveInterface;
import net.finmath.marketdata2.model.curves.ForwardCurveInterface;
import net.finmath.montecarlo.RandomVariableFromDoubleArray;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.RegularSchedule;
import net.finmath.time.Schedule;
import net.finmath.time.TimeDiscretization;

/**
 * Implements the valuation of a swap annuity using curves (discount curve).
 * Support for day counting is limited to the capabilities of
 * <code>TimeDiscretization</code>.
 *
 * @author Christian Fries
 * @version 1.0
 */
public class SwapAnnuity extends AbstractAnalyticProduct implements AnalyticProduct {

	private final Schedule	schedule;
	private final String			discountCurveName;

	/**
	 * Creates a swap annuity for a given schedule and discount curve.
	 *
	 * @param schedule TenorFromArray of the swap annuity.
	 * @param discountCurveName Name of the discount curve for the swap annuity.
	 */
	public SwapAnnuity(final Schedule schedule, final String discountCurveName) {
		super();
		this.schedule = schedule;
		this.discountCurveName = discountCurveName;
	}

	@Override
	public RandomVariable getValue(final double evaluationTime, final AnalyticModel model) {
		final DiscountCurveInterface discountCurve = (DiscountCurveInterface) model.getCurve(discountCurveName);

		return getSwapAnnuity(evaluationTime, schedule, discountCurve, model);
	}

	/**
	 * Function to calculate an (idealized) swap annuity for a given schedule and discount curve.
	 *
	 * @param tenor The schedule discretization, i.e., the period start and end dates. End dates are considered payment dates and start of the next period.
	 * @param discountCurve The discount curve.
	 * @return The swap annuity.
	 */
	public static RandomVariable getSwapAnnuity(final TimeDiscretization tenor, final DiscountCurveInterface discountCurve) {
		return getSwapAnnuity(new RegularSchedule(tenor), discountCurve);
	}

	/**
	 * Function to calculate an (idealized) single curve swap annuity for a given schedule and forward curve.
	 * The discount curve used to calculate the annuity is calculated from the forward curve using classical
	 * single curve interpretations of forwards and a default period length. The may be a crude approximation.
	 *
	 * @param tenor The schedule discretization, i.e., the period start and end dates. End dates are considered payment dates and start of the next period.
	 * @param forwardCurve The forward curve.
	 * @return The swap annuity.
	 */
	public static RandomVariable getSwapAnnuity(final TimeDiscretization tenor, final ForwardCurveInterface forwardCurve) {
		return getSwapAnnuity(new RegularSchedule(tenor), forwardCurve);
	}

	/**
	 * Function to calculate an (idealized) swap annuity for a given schedule and discount curve.
	 *
	 * Note: This method will consider evaluationTime being 0, see {@link net.finmath.marketdata2.products.SwapAnnuity#getSwapAnnuity(double, Schedule, DiscountCurveInterface, AnalyticModel)}.
	 *
	 * @param schedule The schedule discretization, i.e., the period start and end dates. End dates are considered payment dates and start of the next period.
	 * @param discountCurve The discount curve.
	 * @return The swap annuity.
	 */
	public static RandomVariable getSwapAnnuity(final Schedule schedule, final DiscountCurveInterface discountCurve) {
		final double evaluationTime = 0.0;	// Consider only payment time > 0
		return getSwapAnnuity(evaluationTime, schedule, discountCurve, null);
	}

	/**
	 * Function to calculate an (idealized) single curve swap annuity for a given schedule and forward curve.
	 * The discount curve used to calculate the annuity is calculated from the forward curve using classical
	 * single curve interpretations of forwards and a default period length. The may be a crude approximation.
	 *
	 * Note: This method will consider evaluationTime being 0, see {@link net.finmath.marketdata2.products.SwapAnnuity#getSwapAnnuity(double, Schedule, DiscountCurveInterface, AnalyticModel)}.
	 *
	 * @param schedule The schedule discretization, i.e., the period start and end dates. End dates are considered payment dates and start of the next period.
	 * @param forwardCurve The forward curve.
	 * @return The swap annuity.
	 */
	public static RandomVariable getSwapAnnuity(final Schedule schedule, final ForwardCurveInterface forwardCurve) {
		final DiscountCurveInterface discountCurve = new DiscountCurveFromForwardCurve(forwardCurve.getName());
		final double evaluationTime = 0.0;	// Consider only payment time > 0
		return getSwapAnnuity(evaluationTime, schedule, discountCurve, new AnalyticModelFromCurvesAndVols( new Curve[] {forwardCurve, discountCurve} ));
	}

	/**
	 * Function to calculate an (idealized) swap annuity for a given schedule and discount curve.
	 *
	 * Note that, the value returned is divided by the discount factor at evaluation.
	 * This matters, if the discount factor at evaluationTime is not equal to 1.0.
	 *
	 * @param evaluationTime The evaluation time as double. Cash flows prior and including this time are not considered.
	 * @param schedule The schedule discretization, i.e., the period start and end dates. End dates are considered payment dates and start of the next period.
	 * @param discountCurve The discount curve.
	 * @param model The model, needed only in case the discount curve evaluation depends on an additional curve.
	 * @return The swap annuity.
	 */
	public static RandomVariable getSwapAnnuity(final double evaluationTime, final Schedule schedule, final DiscountCurveInterface discountCurve, final AnalyticModel model) {
		RandomVariable value = new RandomVariableFromDoubleArray(0.0);
		for(int periodIndex=0; periodIndex<schedule.getNumberOfPeriods(); periodIndex++) {
			final double paymentDate		= schedule.getPayment(periodIndex);
			if(paymentDate <= evaluationTime) {
				continue;
			}

			final double periodLength		= schedule.getPeriodLength(periodIndex);
			final RandomVariable discountFactor	= discountCurve.getDiscountFactor(model, paymentDate);
			value = discountFactor.mult(periodLength).add(value);
		}
		return value.div(discountCurve.getDiscountFactor(model, evaluationTime));
	}

	@Override
	public String toString() {
		return "SwapAnnuity [schedule=" + schedule + ", discountCurveName="
				+ discountCurveName + "]";
	}
}