SimpleCappedFlooredFloatingRateBond.java

/*
 * (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
 *
 * Created on 07.11.2015
 */

package net.finmath.montecarlo.interestrate.products;

import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.interestrate.TermStructureMonteCarloSimulationModel;
import net.finmath.stochastic.RandomVariable;

/**
 * @author Christian Fries
 *
 * @version 1.0
 */
public class SimpleCappedFlooredFloatingRateBond extends AbstractTermStructureMonteCarloProduct {

	private final double[]	fixingDates;	// Vector of fixing dates
	private final double[]	paymentDates;	// Vector of payment dates (same length as fixing dates)
	private final double[]	spreads;		// Vector of spreads
	private final double[]	floors;			// Vector of floors
	private final double[]	caps;			// Vector of caps
	private final double	maturity;

	public SimpleCappedFlooredFloatingRateBond(final String currency, final double[] fixingDates, final double[] paymentDates, final double[] spreads, final double[] floors, final double[] caps, final double maturity) {
		super(currency);
		this.fixingDates = fixingDates;
		this.paymentDates = paymentDates;
		this.spreads = spreads;
		this.floors = floors;
		this.caps = caps;
		this.maturity = maturity;
	}

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

		// Accumulating values in the random variable
		RandomVariable value = model.getRandomVariableForConstant(0.0);

		for(int periodIndex=0; periodIndex<fixingDates.length; periodIndex++) {
			final double fixingDate = fixingDates[periodIndex];
			final double paymentDate = paymentDates[periodIndex];
			final double periodLength = paymentDate-fixingDate;

			// Get floating rate for coupon
			RandomVariable coupon = model.getForwardRate(fixingDate, fixingDate, paymentDate);

			// Apply spread, if any
			if(spreads != null) {
				coupon = coupon.sub(spreads[periodIndex]);
			}

			// Apply floor, if any
			if(floors != null) {
				coupon = coupon.floor(floors[periodIndex]);
			}

			// Apply cap, if any
			if(caps != null) {
				coupon = coupon.cap(caps[periodIndex]);
			}

			coupon = coupon.mult(periodLength);

			final RandomVariable numeraire = model.getNumeraire(paymentDate);
			final RandomVariable monteCarloProbabilities	= model.getMonteCarloWeights(paymentDate);

			value = value.add(coupon.div(numeraire).mult(monteCarloProbabilities));
		}

		// Add unit notional payment at maturity
		final RandomVariable notionalPayoff = model.getRandomVariableForConstant(1.0);
		final RandomVariable numeraire = model.getNumeraire(maturity);
		final RandomVariable monteCarloProbabilities	= model.getMonteCarloWeights(maturity);
		value = value.add(notionalPayoff.div(numeraire).mult(monteCarloProbabilities));

		final RandomVariable	numeraireAtEvalTime					= model.getNumeraire(evaluationTime);
		final RandomVariable	monteCarloProbabilitiesAtEvalTime	= model.getMonteCarloWeights(evaluationTime);
		value = value.mult(numeraireAtEvalTime).div(monteCarloProbabilitiesAtEvalTime);

		return value;
	}
}