com.opengamma.strata.pricer.cms.SabrExtrapolationReplicationCmsLegPricer Maven / Gradle / Ivy
/*
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.cms;
import java.util.stream.Collectors;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.market.explain.ExplainKey;
import com.opengamma.strata.market.explain.ExplainMap;
import com.opengamma.strata.market.explain.ExplainMapBuilder;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.swaption.SabrSwaptionVolatilities;
import com.opengamma.strata.product.cms.CmsLeg;
import com.opengamma.strata.product.cms.CmsPeriod;
import com.opengamma.strata.product.cms.ResolvedCmsLeg;
/**
* Pricer for CMS legs by swaption replication on a SABR formula with extrapolation.
*
* This function provides the ability to price {@link ResolvedCmsLeg}.
* One must apply {@code resolved()} in order to price {@link CmsLeg}.
*/
public class SabrExtrapolationReplicationCmsLegPricer {
/**
* The pricer for {@link CmsPeriod}.
*/
private final SabrExtrapolationReplicationCmsPeriodPricer cmsPeriodPricer;
/**
* Creates an instance.
*
* @param cmsPeriodPricer the pricer for {@link CmsPeriod}
*/
public SabrExtrapolationReplicationCmsLegPricer(SabrExtrapolationReplicationCmsPeriodPricer cmsPeriodPricer) {
this.cmsPeriodPricer = ArgChecker.notNull(cmsPeriodPricer, "cmsPeriodPricer");
}
//-------------------------------------------------------------------------
/**
* Calculates the present value of the CMS leg.
*
* The present value of the leg is the value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param cmsLeg the CMS leg
* @param ratesProvider the rates provider
* @param swaptionVolatilities the swaption volatilities
* @return the present value
*/
public CurrencyAmount presentValue(
ResolvedCmsLeg cmsLeg,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(ratesProvider, swaptionVolatilities);
return cmsLeg.getCmsPeriods().stream()
.map(cmsPeriod -> cmsPeriodPricer.presentValue(cmsPeriod, ratesProvider, swaptionVolatilities))
.reduce((c1, c2) -> c1.plus(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Explains the present value of a CMS leg.
*
* This returns explanatory information about the calculation.
*
* @param cmsLeg the CMS leg
* @param provider the rates provider
* @param volatilities the swaption volatilities
* @return the explanatory information
*/
public ExplainMap explainPresentValue(
ResolvedCmsLeg cmsLeg,
RatesProvider provider,
SabrSwaptionVolatilities volatilities) {
ExplainMapBuilder builder = ExplainMap.builder();
builder.put(ExplainKey.ENTRY_TYPE, "CmsLeg");
builder.put(ExplainKey.PAY_RECEIVE, cmsLeg.getPayReceive());
builder.put(ExplainKey.PAYMENT_CURRENCY, cmsLeg.getCurrency());
builder.put(ExplainKey.START_DATE, cmsLeg.getStartDate());
builder.put(ExplainKey.END_DATE, cmsLeg.getEndDate());
builder.put(ExplainKey.INDEX, cmsLeg.getIndex());
for (CmsPeriod period : cmsLeg.getCmsPeriods()) {
builder.addListEntry(
ExplainKey.PAYMENT_PERIODS, child -> cmsPeriodPricer.explainPresentValue(period, provider, volatilities, child));
}
builder.put(ExplainKey.PRESENT_VALUE, presentValue(cmsLeg, provider, volatilities));
return builder.build();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value curve sensitivity of the CMS leg.
*
* The present value sensitivity of the leg is the sensitivity of the present value to
* the underlying curves.
*
* @param cmsLeg the CMS leg
* @param ratesProvider the rates provider
* @param swaptionVolatilities the swaption volatilities
* @return the present value sensitivity
*/
public PointSensitivityBuilder presentValueSensitivityRates(
ResolvedCmsLeg cmsLeg,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(ratesProvider, swaptionVolatilities);
return cmsLeg.getCmsPeriods().stream()
.map(cmsPeriod -> cmsPeriodPricer.presentValueSensitivityRates(cmsPeriod, ratesProvider, swaptionVolatilities))
.reduce((p1, p2) -> p1.combinedWith(p2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value sensitivity to the SABR model parameters.
*
* The present value sensitivity of the leg is the sensitivity of the present value to
* the SABR model parameters, alpha, beta, rho and nu.
*
* @param cmsLeg the CMS leg
* @param ratesProvider the rates provider
* @param swaptionVolatilities the swaption volatilities
* @return the present value sensitivity
*/
public PointSensitivityBuilder presentValueSensitivityModelParamsSabr(
ResolvedCmsLeg cmsLeg,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(ratesProvider, swaptionVolatilities);
return cmsLeg.getCmsPeriods().stream()
.map(cmsPeriod -> cmsPeriodPricer.presentValueSensitivityModelParamsSabr(cmsPeriod, ratesProvider, swaptionVolatilities))
.reduce(PointSensitivityBuilder.none(), PointSensitivityBuilder::combinedWith)
.normalize();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value sensitivity to the strike value.
*
* The present value sensitivity of the leg is the sensitivity of the present value to the strike value.
* This is not relevant for CMS coupons and an exception is thrown in the underlying pricer.
*
* @param cmsLeg the CMS leg
* @param ratesProvider the rates provider
* @param swaptionVolatilities the swaption volatilities
* @return the present value sensitivity
*/
public double presentValueSensitivityStrike(
ResolvedCmsLeg cmsLeg,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(ratesProvider, swaptionVolatilities);
return cmsLeg.getCmsPeriods().stream()
.map(cmsPeriod -> cmsPeriodPricer.presentValueSensitivityStrike(cmsPeriod, ratesProvider, swaptionVolatilities))
.collect(Collectors.summingDouble(Double::doubleValue));
}
//-------------------------------------------------------------------------
/**
* Calculates the current cash of the leg.
*
* @param cmsLeg the CMS leg
* @param ratesProvider the rates provider
* @param swaptionVolatilities the swaption volatilities
* @return the current cash
*/
public CurrencyAmount currentCash(
ResolvedCmsLeg cmsLeg,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(ratesProvider, swaptionVolatilities);
return cmsLeg.getCmsPeriods().stream()
.filter(x -> x.getPaymentDate().equals(ratesProvider.getValuationDate()))
.map(x -> cmsPeriodPricer.presentValue(x, ratesProvider, swaptionVolatilities))
.reduce((c1, c2) -> c1.plus(c2))
.orElse(CurrencyAmount.zero(cmsLeg.getCurrency()));
}
//-------------------------------------------------------------------------
private void validate(RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) {
ArgChecker.isTrue(swaptionVolatilities.getValuationDate().equals(ratesProvider.getValuationDate()),
"volatility and rate data must be for the same date");
}
}