/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.fixedincome;
import com.opengamma.analytics.financial.instrument.fra.ForwardRateAgreementDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter;
import com.opengamma.analytics.financial.interestrate.fra.derivative.ForwardRateAgreement;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.financial.security.irs.PayReceiveType;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.time.Tenor;
/**
* Generates a pay or receive cashflow for a FRA. These are
* reported as {@link SwapLegCashFlows} to be consistent with
* the IR cashflow result type for swaps.
* <p>
* This implementation reports a "fixed" and "float" cashflow
* for the FRA. Whilst these do not exist in reality (only a
* single, netted cashflow is paid), it is convenient from
* a reporting point of view for the flows to be consistent
* with those for swaps. (Similarly, swap cashflow payments
* are in reality netted, but split out as separate sets of
* cashflows).
*
* The "Pay" leg is taken to be the flow with a negative PV.
*/
public class FraCashFlowDetailsCalculator extends InstrumentDerivativeVisitorAdapter<ForwardRateAgreementDefinition, SwapLegCashFlows> {
private final MulticurveProviderDiscount _multicurve;
private final PayReceiveType _type;
/**
* @param multicurve the curve to use for discounting and forward rate computation
* @param type the type of cashflow to produce - pay or receive
*/
public FraCashFlowDetailsCalculator(MulticurveProviderDiscount multicurve, PayReceiveType type) {
_multicurve = multicurve;
_type = type;
}
@Override
public SwapLegCashFlows visitForwardRateAgreement(ForwardRateAgreement fra, ForwardRateAgreementDefinition fraDefinition) {
double settlementDf = _multicurve.getDiscountFactor(fra.getCurrency(), fra.getPaymentTime());
double forwardRate = _multicurve.getSimplyCompoundForwardRate(fra.getIndex(), fra.getFixingPeriodStartTime(), fra.getFixingPeriodEndTime(), fra.getFixingYearFraction());;
double paymentYearFraction = fraDefinition.getPaymentYearFraction();
double fixedRate = fraDefinition.getRate();
double fixedProjectedAmount = -fraDefinition.getNotional() * paymentYearFraction * fixedRate / (1 + paymentYearFraction * forwardRate);
double fixedPresentValue = settlementDf * fixedProjectedAmount;
if (PayReceiveType.PAY.equals(_type) == fixedPresentValue <= 0) {
FixedCashFlowDetails fixedCashFlow = fixedCashFlow(fraDefinition, settlementDf, fixedProjectedAmount, fixedPresentValue);
return FixedLegCashFlows.builder().cashFlowDetails(fixedCashFlow).build();
} else {
double projectedAmount = fraDefinition.getNotional() * paymentYearFraction * forwardRate / (1 + paymentYearFraction * forwardRate);
double presentValue = settlementDf * projectedAmount;
FloatingCashFlowDetails floatCashFlow = floatCashFlow(fraDefinition, fra, settlementDf, forwardRate, projectedAmount, presentValue);
return FloatingLegCashFlows.builder().cashFlowDetails(floatCashFlow).build();
}
}
private FloatingCashFlowDetails floatCashFlow(ForwardRateAgreementDefinition fraDefinition,
ForwardRateAgreement fra,
double settlementDf,
double forwardRate,
double projectedAmount,
double presentValue) {
FloatingCashFlowDetails.Builder builder = FloatingCashFlowDetails.builder();
builder.accrualEndDate(fraDefinition.getAccrualEndDate().toLocalDate());
builder.accrualFactor(fraDefinition.getFixingPeriodAccrualFactor());
builder.accrualStartDate(fraDefinition.getAccrualStartDate().toLocalDate());
builder.df(settlementDf);
builder.fixingEndDate(fraDefinition.getFixingPeriodEndDate().toLocalDate());
builder.fixingStartDate(fraDefinition.getFixingPeriodStartDate().toLocalDate());
builder.fixingYearFrac(fra.getFixingYearFraction());
builder.forwardRate(forwardRate);
builder.indexTenors(Tenor.of(fraDefinition.getIndex().getTenor()));
builder.notional(CurrencyAmount.of(fraDefinition.getCurrency(), fraDefinition.getNotional()));
builder.paymentDate(fraDefinition.getPaymentDate().toLocalDate());
builder.presentValue(CurrencyAmount.of(fraDefinition.getCurrency(), presentValue));
builder.projectedAmount(CurrencyAmount.of(fraDefinition.getCurrency(), projectedAmount));
return builder.build();
}
private FixedCashFlowDetails fixedCashFlow(ForwardRateAgreementDefinition fraDefinition,
double df,
double projectedAmount,
double presentValue) {
FixedCashFlowDetails.Builder builder = FixedCashFlowDetails.builder();
builder.accrualEndDate(fraDefinition.getAccrualEndDate().toLocalDate());
builder.accrualFactor(fraDefinition.getFixingPeriodAccrualFactor());
builder.accrualStartDate(fraDefinition.getAccrualStartDate().toLocalDate());
builder.df(df);
//note: notional is positive w.r.t. payer of floating rate);
builder.notional(CurrencyAmount.of(fraDefinition.getCurrency(), -fraDefinition.getNotional()));
builder.paymentDate(fraDefinition.getPaymentDate().toLocalDate());
builder.presentValue(CurrencyAmount.of(fraDefinition.getCurrency(), presentValue));
builder.projectedAmount(CurrencyAmount.of(fraDefinition.getCurrency(), projectedAmount));
builder.rate(fraDefinition.getRate());
FixedCashFlowDetails fixedCashFlow = builder.build();
return fixedCashFlow;
}
}