/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.fixedincome;
import java.util.List;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.Lists;
import com.google.common.primitives.Doubles;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition;
import com.opengamma.analytics.financial.instrument.payment.PaymentDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapDefinition;
import com.opengamma.analytics.financial.interestrate.AnnuityAccrualDatesVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityFixedRatesVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityFixingDatesVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityFixingYearFractionsVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityGearingsVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityNotionalsVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityPaymentAmountsVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityPaymentDatesVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuityPaymentTimesVisitor;
import com.opengamma.analytics.financial.interestrate.AnnuitySpreadsVisitor;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment;
import com.opengamma.analytics.financial.interestrate.swap.derivative.Swap;
import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon;
import com.opengamma.analytics.financial.interestrate.swap.provider.AnnuityDiscountFactorsVisitor;
import com.opengamma.analytics.financial.interestrate.swap.provider.AnnuityForwardRatesVisitor;
import com.opengamma.analytics.financial.interestrate.swap.provider.AnnuityProjectedPaymentsVisitor;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.financial.security.irs.PayReceiveType;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.tuple.Pair;
/**
* Calculator to expose the cash flows of the swap legs.
*/
public final class CashFlowDetailsCalculator extends InstrumentDerivativeVisitorAdapter<CashFlowDetailsProvider, SwapLegCashFlows> {
@Override
public SwapLegCashFlows visitFixedCouponSwap(SwapFixedCoupon<?> derivative, CashFlowDetailsProvider provider) {
return getCashFlows(derivative, provider);
}
@Override
public SwapLegCashFlows visitSwap(Swap<?, ?> derivative, CashFlowDetailsProvider provider) {
return getCashFlows(derivative, provider);
}
private SwapLegCashFlows getCashFlows(Swap<?, ?> swapDerivative, CashFlowDetailsProvider provider) {
AnnuityDefinition<? extends PaymentDefinition> legDefinition;
SwapDefinition swapDefinition = provider.getDefinition();
Annuity<? extends Payment> legDerivative;
boolean full = provider.isFull();
// if full cash flows are required override valuation data to epoch
ZonedDateTime valuationTime = full ? ZonedDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC) : provider.getZonedDateTime();
MulticurveProviderInterface bundle = provider.getMulticurveProviderInterface();
boolean isDerivativeFirstLegPay = swapDerivative.getFirstLeg().getNthPayment(0).getReferenceAmount() < 0;
boolean isDefinitionFirstLegPay = swapDefinition.getFirstLeg().getNthPayment(0).getReferenceAmount() < 0;
if (provider.getType() == PayReceiveType.PAY) {
legDefinition = isDefinitionFirstLegPay ? swapDefinition.getFirstLeg() : swapDefinition.getSecondLeg();
legDerivative = isDerivativeFirstLegPay ? swapDerivative.getFirstLeg() : swapDerivative.getSecondLeg();
} else {
legDefinition = isDefinitionFirstLegPay ? swapDefinition.getSecondLeg() : swapDefinition.getFirstLeg();
legDerivative = isDerivativeFirstLegPay ? swapDerivative.getSecondLeg() : swapDerivative.getFirstLeg();
}
//data from derivative - only future cash flows
List<Double> paymentTimes = Doubles.asList(legDerivative.accept(AnnuityPaymentTimesVisitor.getInstance()));
List<Double> discountFactors = Doubles.asList(legDerivative.accept(AnnuityDiscountFactorsVisitor.getInstance(), bundle));
List<Double> fixedRates = Lists.newArrayList(legDerivative.accept(AnnuityFixedRatesVisitor.getInstance()));
List<CurrencyAmount> paymentAmounts = Lists.newArrayList(legDerivative.accept(AnnuityPaymentAmountsVisitor.getInstance()));
//data from definition - can include past cash flows
List<CurrencyAmount> notionals = Lists.newArrayList(legDefinition.accept(AnnuityNotionalsVisitor.getInstance(), valuationTime));
Pair<LocalDate[], LocalDate[]> accrualDates = legDefinition.accept(AnnuityAccrualDatesVisitor.getInstance(), valuationTime);
List<LocalDate> startAccrualDates = Lists.newArrayList(accrualDates.getFirst());
List<LocalDate> endAccrualDates = Lists.newArrayList(accrualDates.getSecond());
List<LocalDate> paymentDates = Lists.newArrayList(legDefinition.accept(AnnuityPaymentDatesVisitor.getInstance(), valuationTime));
if (provider.isFixed()) {
return new FixedLegCashFlows(
startAccrualDates,
endAccrualDates,
discountFactors,
paymentTimes,
paymentDates,
paymentAmounts,
notionals,
fixedRates,
full);
}
//data from derivative - only future cash flows
List<Double> forwardRates = Lists.newArrayList(legDerivative.accept(AnnuityForwardRatesVisitor.getInstance(), bundle));
List<CurrencyAmount> projectedAmounts = Lists.newArrayList(legDerivative.accept(AnnuityProjectedPaymentsVisitor.getInstance(), bundle));
//data from definition - can include past cash flows
List<Double> fixingYearFractions = Lists.newArrayList(legDefinition.accept(AnnuityFixingYearFractionsVisitor.getInstance(), valuationTime));
List<Double> spreads = Doubles.asList(legDefinition.accept(AnnuitySpreadsVisitor.getInstance(), valuationTime));
List<Double> gearings = Doubles.asList(legDefinition.accept(AnnuityGearingsVisitor.getInstance(), valuationTime));
Pair<LocalDate[], LocalDate[]> fixingDates = legDefinition.accept(AnnuityFixingDatesVisitor.getInstance(), valuationTime);
List<LocalDate> fixingStartDates = Lists.newArrayList(fixingDates.getFirst());
List<LocalDate> fixingEndDates = Lists.newArrayList(fixingDates.getSecond());
return new FloatingLegCashFlows(
startAccrualDates,
endAccrualDates,
fixingStartDates,
fixingEndDates,
fixingYearFractions,
forwardRates,
fixedRates,
paymentDates,
paymentTimes,
discountFactors,
projectedAmounts,
notionals,
spreads,
gearings,
full);
}
}