NumerairePerformanceOnScheduleIndex.java
/*
* Created on 01.01.2019
*
* (c) Copyright Christian P. Fries, Germany. Contact: email@christian-fries.de.
*/
package net.finmath.montecarlo.interestrate.products.indices;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import net.finmath.exception.CalculationException;
import net.finmath.marketdata.model.AnalyticModel;
import net.finmath.marketdata.model.curves.DiscountCurve;
import net.finmath.montecarlo.interestrate.TermStructureMonteCarloSimulationModel;
import net.finmath.stochastic.RandomVariable;
import net.finmath.time.FloatingpointDate;
import net.finmath.time.Period;
import net.finmath.time.Schedule;
/**
* A (floating) rate index representing the performance of the numeraire asset.
*
* The index is given give
* \( F = \frac{1}{dc(t-s)} ( N(t)/N(s) - 1 ) \).
* where \( s \) denotes the period start and \( t \) denotes the period end and dc is a given daycount convention.
*
* The index fetches fixing, payment and daycount conventions, etc. from a given schedule.
* The index fails to evaluate
*
* @author Christian Fries
* @version 1.1
*/
public class NumerairePerformanceOnScheduleIndex extends AbstractIndex {
private static final long serialVersionUID = 1L;
private final Schedule schedule;
public NumerairePerformanceOnScheduleIndex(final String name, final String currency, final Schedule schedule) {
super(name, currency);
this.schedule = schedule;
}
@Override
public RandomVariable getValue(final double evaluationTime, final TermStructureMonteCarloSimulationModel model) throws CalculationException {
/*
* The periodLength may be a given float or (more exact) derived from the rolling convetions.
*/
final double fixingTime = evaluationTime;
final Period period = getPeriod(FloatingpointDate.getDateFromFloatingPointDate(model.getReferenceDate(), fixingTime));
final LocalDate paymentDate = period.getPayment();
final double paymentTime = FloatingpointDate.getFloatingPointDateFromDate(model.getReferenceDate().toLocalDate(), paymentDate);
final double periodLength = schedule.getDaycountconvention().getDaycountFraction(period.getPeriodStart(), period.getPeriodEnd());
/*
* Fetch numeraire performance rate from model
*/
final RandomVariable numeraireAtStart = model.getNumeraire(fixingTime);
final RandomVariable numeraireAtEnd = model.getNumeraire(paymentTime);
RandomVariable numeraireRatio = numeraireAtEnd.div(numeraireAtStart);
if(getName() != null && !model.getModel().getDiscountCurve().getName().equals(getName())) {
// Perform a multiplicative adjustment on the forward bonds
final AnalyticModel analyticModel = model.getModel().getAnalyticModel();
final DiscountCurve indexDiscountCurve = analyticModel.getDiscountCurve(getName());
final DiscountCurve modelDisountCurve = model.getModel().getDiscountCurve();
final double forwardBondOnIndexCurve = indexDiscountCurve.getDiscountFactor(analyticModel, fixingTime)/indexDiscountCurve.getDiscountFactor(analyticModel, paymentTime);
final double forwardBondOnModelCurve = modelDisountCurve.getDiscountFactor(analyticModel, fixingTime)/modelDisountCurve.getDiscountFactor(analyticModel, paymentTime);
final double adjustment = forwardBondOnModelCurve/forwardBondOnIndexCurve;
numeraireRatio = numeraireRatio.mult(adjustment);
}
final RandomVariable forwardRate = numeraireRatio.sub(1.0).div(periodLength);
return forwardRate;
}
private Period getPeriod(final LocalDateTime localDateTime) {
for(final Period period : schedule.getPeriods()) {
if(period.getFixing().isEqual(localDateTime.toLocalDate())) {
return period;
}
}
return null;
}
@Override
public Set<String> queryUnderlyings() {
final Set<String> underlyingNames = new HashSet<>();
underlyingNames.add(getName());
return underlyingNames;
}
@Override
public String toString() {
return "NumerairePerformanceOnScheduleIndex [schedule=" + schedule + "]";
}
}