/** * Copyright (C) 2015 - 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.IborIndexObservation; import com.opengamma.strata.collect.tuple.DoublesPair; 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.IborIndexRates; import com.opengamma.strata.pricer.rate.RateComputationFn; import com.opengamma.strata.pricer.rate.RatesProvider; import com.opengamma.strata.product.rate.IborInterpolatedRateComputation; /** * Rate computation implementation for rate based on the weighted average of the fixing * on a single date of two Ibor indices. * <p> * The rate computation queries the rates from the {@code RatesProvider} and interpolates them. * There is no convexity adjustment computed in this implementation. */ public class ForwardIborInterpolatedRateComputationFn implements RateComputationFn<IborInterpolatedRateComputation> { /** * Default instance. */ public static final ForwardIborInterpolatedRateComputationFn DEFAULT = new ForwardIborInterpolatedRateComputationFn(); /** * Creates an instance. */ public ForwardIborInterpolatedRateComputationFn() { } //------------------------------------------------------------------------- @Override public double rate( IborInterpolatedRateComputation computation, LocalDate startDate, LocalDate endDate, RatesProvider provider) { IborIndexObservation obs1 = computation.getShortObservation(); IborIndexObservation obs2 = computation.getLongObservation(); IborIndexRates rates1 = provider.iborIndexRates(obs1.getIndex()); IborIndexRates rates2 = provider.iborIndexRates(obs2.getIndex()); double rate1 = rates1.rate(obs1); double rate2 = rates2.rate(obs2); DoublesPair weights = weights(obs1, obs2, endDate); return ((rate1 * weights.getFirst()) + (rate2 * weights.getSecond())) / (weights.getFirst() + weights.getSecond()); } @Override public PointSensitivityBuilder rateSensitivity( IborInterpolatedRateComputation computation, LocalDate startDate, LocalDate endDate, RatesProvider provider) { // computes the dates related to the underlying deposits associated to the indices IborIndexObservation obs1 = computation.getShortObservation(); IborIndexObservation obs2 = computation.getLongObservation(); DoublesPair weights = weights(obs1, obs2, endDate); double totalWeight = weights.getFirst() + weights.getSecond(); IborIndexRates ratesIndex1 = provider.iborIndexRates(obs1.getIndex()); PointSensitivityBuilder sens1 = ratesIndex1.ratePointSensitivity(obs1) .multipliedBy(weights.getFirst() / totalWeight); IborIndexRates ratesIndex2 = provider.iborIndexRates(obs2.getIndex()); PointSensitivityBuilder sens2 = ratesIndex2.ratePointSensitivity(obs2) .multipliedBy(weights.getSecond() / totalWeight); return sens1.combinedWith(sens2); } @Override public double explainRate( IborInterpolatedRateComputation computation, LocalDate startDate, LocalDate endDate, RatesProvider provider, ExplainMapBuilder builder) { IborIndexObservation obs1 = computation.getShortObservation(); IborIndexObservation obs2 = computation.getLongObservation(); DoublesPair weights = weights(obs1, obs2, endDate); IborIndexRates rates1 = provider.iborIndexRates(obs1.getIndex()); IborIndexRates rates2 = provider.iborIndexRates(obs2.getIndex()); rates1.explainRate(obs1, builder, child -> child.put(ExplainKey.WEIGHT, weights.getFirst())); rates2.explainRate(obs2, builder, child -> child.put(ExplainKey.WEIGHT, weights.getSecond())); double rate = rate(computation, startDate, endDate, provider); builder.put(ExplainKey.COMBINED_RATE, rate); return rate; } // computes the weights related to the two indices private DoublesPair weights(IborIndexObservation obs1, IborIndexObservation obs2, LocalDate endDate) { // weights: linear interpolation on the number of days between the fixing date and the maturity dates of the // actual coupons on one side and the maturity dates of the underlying deposit on the other side. long fixingEpochDay = obs1.getFixingDate().toEpochDay(); double days1 = obs1.getMaturityDate().toEpochDay() - fixingEpochDay; double days2 = obs2.getMaturityDate().toEpochDay() - fixingEpochDay; double daysN = endDate.toEpochDay() - fixingEpochDay; double weight1 = (days2 - daysN) / (days2 - days1); double weight2 = (daysN - days1) / (days2 - days1); return DoublesPair.of(weight1, weight2); } }