ConstantMaturitySwaprate.java
/*
* Created on 15.09.2006
*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*/
package net.finmath.montecarlo.interestrate.products.indices;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.finmath.exception.CalculationException;
import net.finmath.montecarlo.interestrate.TermStructureMonteCarloSimulationModel;
import net.finmath.stochastic.RandomVariable;
/**
* An idealized (single curve) CMS index with given maturity and given period length.
*
* @author Christian Fries
* @version 1.0
*/
public class ConstantMaturitySwaprate extends AbstractIndex {
private static final long serialVersionUID = -5353191308059733179L;
private final double fixingOffset;
private final double[] periodLengths;
/**
* Create a CMS index with given fixing offset and given period lengths.
*
* @param name The name of the underlying index.
* @param currency The currency of the underlying index, if any.
* @param fixingOffset Fixing offset of this index.
* @param periodLengths Period length of underlying swap, used for the swap annuity calculation.
*/
public ConstantMaturitySwaprate(final String name, final String currency, final double fixingOffset, final double[] periodLengths) {
super(name, currency);
this.fixingOffset = fixingOffset;
this.periodLengths = periodLengths;
}
/**
* Create a CMS index with given fixing offset and given period lengths.
*
* @param fixingOffset Fixing offset of this index.
* @param periodLengths Period length of underlying swap, used for the swap annuity calculation.
*/
public ConstantMaturitySwaprate(final double fixingOffset, final double[] periodLengths) {
this(null, null, fixingOffset, periodLengths);
}
/**
* Create a CMS index with given period lengths.
*
* @param periodLengths Period length of underlying swap, used for the swap annuity calculation.
*/
public ConstantMaturitySwaprate(final double[] periodLengths) {
this(0.0, periodLengths);
}
/**
* Create a CMS index with given fixing offset and given maturity and given period length.
* Note that maturity must be a multiple of the period length.
*
* @param name The name of the underlying index.
* @param currency The currency of the underlying index, if any.
* @param fixingOffset Fixing offset of this index.
* @param maturity The maturity.
* @param periodLength Period length of underlying swap, used for the swap annuity calculation.
*/
public ConstantMaturitySwaprate(final String name, final String currency, final double fixingOffset, final double maturity, final double periodLength) {
super(name, currency);
this.fixingOffset = fixingOffset;
final int numberOfPeriods = (int) (maturity / periodLength + 0.5);
if(numberOfPeriods * periodLength != maturity) {
throw new IllegalArgumentException("matruity not divisible by periodLength");
}
periodLengths = new double[numberOfPeriods];
Arrays.fill(periodLengths,periodLength);
}
/**
* Create a CMS index with given fixing offset and given maturity and given period length.
* Note that maturity must be a multiple of the period length.
*
* @param fixingOffset Fixing offset of this index.
* @param maturity The maturity.
* @param periodLength Period length of underlying swap, used for the swap annuity calculation.
*/
public ConstantMaturitySwaprate(final double fixingOffset, final double maturity, final double periodLength) {
this(null, null, fixingOffset, maturity, periodLength);
}
/**
* Create a CMS index with given maturity and given period length. Note that maturity must be a multiple of the period length.
*
* @param maturity Maturity of the swap rate.
* @param periodLength Period length of the fixed size (determines the swap annuity used)
*/
public ConstantMaturitySwaprate(final double maturity, final double periodLength) {
this(0.0, maturity, periodLength);
}
@Override
public RandomVariable getValue(final double evaluationTime, final TermStructureMonteCarloSimulationModel model) throws CalculationException {
// Fetch curve
final RandomVariable[] forwardRates = new RandomVariable[periodLengths.length];
double periodStart = evaluationTime+fixingOffset;
for(int periodIndex = 0; periodIndex < periodLengths.length; periodIndex++) {
forwardRates[periodIndex] = model.getForwardRate(evaluationTime+fixingOffset, periodStart, periodStart+periodLengths[periodIndex]);
periodStart += periodLengths[periodIndex];
}
// Calculate float leg value (single curve/classical) and annuity.
RandomVariable forwardBondInverse = model.getRandomVariableForConstant(1.0);
RandomVariable forwardAnnuityInverse = model.getRandomVariableForConstant(periodLengths[periodLengths.length-1]);
for(int periodIndex = periodLengths.length-1; periodIndex>= 1; periodIndex--) {
final RandomVariable forwardBondOnePeriodInverse = (forwardRates[periodIndex]).mult(periodLengths[periodIndex]).add(1.0);
forwardBondInverse = forwardBondInverse.mult(forwardBondOnePeriodInverse);
forwardAnnuityInverse = forwardAnnuityInverse.addProduct(forwardBondInverse, periodLengths[periodIndex]);
}
final RandomVariable forwardBondOnePeriodInverse = (forwardRates[0]).mult(periodLengths[0]).add(1.0);
forwardBondInverse = forwardBondInverse.mult(forwardBondOnePeriodInverse);
final RandomVariable swaprate = forwardBondInverse.sub(1.0).div(forwardAnnuityInverse);
return swaprate;
}
@Override
public Set<String> queryUnderlyings() {
final Set<String> underlyingNames = new HashSet<>();
underlyingNames.add(getName());
return underlyingNames;
}
@Override
public String toString() {
return "ConstantMaturitySwaprate [fixingOffset=" + fixingOffset
+ ", periodLengths=" + Arrays.toString(periodLengths) + "]";
}
}