NumerairePerformanceIndex.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.businessdaycalendar.BusinessdayCalendar;
import net.finmath.time.businessdaycalendar.BusinessdayCalendar.DateRollConvention;
import net.finmath.time.daycount.DayCountConvention;
/**
* A (floating) rate index representing the performance of the numeraire asset for a given period start offset (offset from fixing) and period length.
*
* 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.
*
* @author Christian Fries
* @version 1.1
*/
public class NumerairePerformanceIndex extends AbstractIndex {
private static final long serialVersionUID = 1L;
private final String paymentOffsetCode;
private final BusinessdayCalendar paymentBusinessdayCalendar;
private final BusinessdayCalendar.DateRollConvention paymentDateRollConvention;
private final DayCountConvention daycountConvention;
public NumerairePerformanceIndex(final String name, final String currency, final String paymentOffsetCode,
final BusinessdayCalendar paymentBusinessdayCalendar, final DateRollConvention paymentDateRollConvention,
final DayCountConvention daycountConvention) {
super(name, currency);
this.paymentOffsetCode = paymentOffsetCode;
this.paymentBusinessdayCalendar = paymentBusinessdayCalendar;
this.paymentDateRollConvention = paymentDateRollConvention;
this.daycountConvention = daycountConvention;
}
@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 LocalDateTime referenceDate = model.getReferenceDate();
final LocalDateTime fixingDate = FloatingpointDate.getDateFromFloatingPointDate(referenceDate, fixingTime);
final LocalDate paymentDate = paymentBusinessdayCalendar.getAdjustedDate(fixingDate.toLocalDate(), paymentOffsetCode, paymentDateRollConvention);
final double paymentTime = FloatingpointDate.getFloatingPointDateFromDate(referenceDate, LocalDateTime.of(paymentDate, fixingDate.toLocalTime()));
final double periodLength = daycountConvention.getDaycountFraction(fixingDate.toLocalDate(), paymentDate);
/*
* 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;
}
@Override
public Set<String> queryUnderlyings() {
final Set<String> underlyingNames = new HashSet<>();
underlyingNames.add(getName());
return underlyingNames;
}
@Override
public String toString() {
return "NumerairePerformanceIndex [paymentOffsetCode=" + paymentOffsetCode + ", paymentBusinessdayCalendar="
+ paymentBusinessdayCalendar + ", paymentDateRollConvention=" + paymentDateRollConvention
+ ", daycountConvention=" + daycountConvention + "]";
}
}