com.opengamma.strata.pricer.impl.rate.ForwardOvernightAveragedRateComputationFn Maven / Gradle / Ivy
/*
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.impl.rate;
import java.time.LocalDate;
import com.opengamma.strata.basics.index.OvernightIndex;
import com.opengamma.strata.basics.index.OvernightIndexObservation;
import com.opengamma.strata.market.explain.ExplainKey;
import com.opengamma.strata.market.explain.ExplainMapBuilder;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.rate.OvernightIndexRates;
import com.opengamma.strata.pricer.rate.RateComputationFn;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.product.rate.OvernightAveragedRateComputation;
/**
* Rate computation implementation for a rate based on a single overnight index that is arithmetically averaged.
*
* The rate computation retrieves the rate at each fixing date in the period
* from the {@link RatesProvider} and average them.
*/
public class ForwardOvernightAveragedRateComputationFn
implements RateComputationFn {
/**
* Default implementation.
*/
public static final ForwardOvernightAveragedRateComputationFn DEFAULT = new ForwardOvernightAveragedRateComputationFn();
/**
* Creates an instance.
*/
public ForwardOvernightAveragedRateComputationFn() {
}
//-------------------------------------------------------------------------
@Override
public double rate(
OvernightAveragedRateComputation computation,
LocalDate startDate,
LocalDate endDate,
RatesProvider provider) {
OvernightIndex index = computation.getIndex();
OvernightIndexRates rates = provider.overnightIndexRates(index);
LocalDate lastNonCutoffFixing = computation.getEndDate();
int cutoffOffset = computation.getRateCutOffDays() > 1 ? computation.getRateCutOffDays() : 1;
double accumulatedInterest = 0.0d;
double accrualFactorTotal = 0.0d;
// Cut-off period. Starting from the end as the cutoff period is defined as a lag from the end.
// When the fixing period end-date is not a good business day in the index calendar,
// the last fixing end date will be after the fixing end-date.
double cutoffAccrualFactor = 0.0;
OvernightIndexObservation lastIndexObs = null;
// cutoffOffset >= 1, so loop always runs at least once
for (int i = 0; i < cutoffOffset; i++) {
lastNonCutoffFixing = computation.getFixingCalendar().previous(lastNonCutoffFixing);
lastIndexObs = computation.observeOn(lastNonCutoffFixing);
accrualFactorTotal += lastIndexObs.getYearFraction();
cutoffAccrualFactor += lastIndexObs.getYearFraction();
}
double forwardRateCutOff = rates.rate(lastIndexObs);
accumulatedInterest += cutoffAccrualFactor * forwardRateCutOff;
LocalDate currentFixingNonCutoff = computation.getStartDate();
while (currentFixingNonCutoff.isBefore(lastNonCutoffFixing)) {
// All dates involved in the period are computed. Potentially slow.
// The fixing periods are added as long as their start date is (strictly) before the no cutoff period end-date.
OvernightIndexObservation indexObs = computation.observeOn(currentFixingNonCutoff);
double forwardRate = rates.rate(indexObs);
accrualFactorTotal += indexObs.getYearFraction();
accumulatedInterest += indexObs.getYearFraction() * forwardRate;
currentFixingNonCutoff = computation.getFixingCalendar().next(currentFixingNonCutoff);
}
// final rate
return accumulatedInterest / accrualFactorTotal;
}
@Override
public PointSensitivityBuilder rateSensitivity(
OvernightAveragedRateComputation computation,
LocalDate startDate,
LocalDate endDate,
RatesProvider provider) {
OvernightIndex index = computation.getIndex();
OvernightIndexRates rates = provider.overnightIndexRates(index);
LocalDate lastNonCutoffFixing = computation.getEndDate();
int cutoffOffset = computation.getRateCutOffDays() > 1 ? computation.getRateCutOffDays() : 1;
double accrualFactorTotal = 0.0d;
// Cut-off period. Starting from the end as the cutoff period is defined as a lag from the end.
// When the fixing period end-date is not a good business day in the index calendar,
// the last fixing end date will be after the fixing end-date.
double cutoffAccrualFactor = 0.0;
OvernightIndexObservation lastIndexObs = null;
// cutoffOffset >= 1, so loop always runs at least once
for (int i = 0; i < cutoffOffset; i++) {
lastNonCutoffFixing = computation.getFixingCalendar().previous(lastNonCutoffFixing);
lastIndexObs = computation.observeOn(lastNonCutoffFixing);
accrualFactorTotal += lastIndexObs.getYearFraction();
cutoffAccrualFactor += lastIndexObs.getYearFraction();
}
PointSensitivityBuilder combinedPointSensitivityBuilder = rates.ratePointSensitivity(lastIndexObs)
.multipliedBy(cutoffAccrualFactor);
LocalDate currentFixingNonCutoff = computation.getStartDate();
while (currentFixingNonCutoff.isBefore(lastNonCutoffFixing)) {
// All dates involved in the period are computed. Potentially slow.
// The fixing periods are added as long as their start date is (strictly) before the no cutoff period end-date.
OvernightIndexObservation indexObs = computation.observeOn(currentFixingNonCutoff);
PointSensitivityBuilder forwardRateSensitivity = rates.ratePointSensitivity(indexObs)
.multipliedBy(indexObs.getYearFraction());
combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(forwardRateSensitivity);
accrualFactorTotal += indexObs.getYearFraction();
currentFixingNonCutoff = computation.getFixingCalendar().next(currentFixingNonCutoff);
}
return combinedPointSensitivityBuilder.multipliedBy(1.0 / accrualFactorTotal);
}
@Override
public double explainRate(
OvernightAveragedRateComputation computation,
LocalDate startDate,
LocalDate endDate,
RatesProvider provider,
ExplainMapBuilder builder) {
double rate = rate(computation, startDate, endDate, provider);
builder.put(ExplainKey.COMBINED_RATE, rate);
return rate;
}
}