/** * 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.ArrayList; import java.util.List; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; 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.swap.DiscountingSwapLegPricer; import com.opengamma.strata.pricer.swaption.SabrSwaptionVolatilities; import com.opengamma.strata.product.cms.CmsLeg; import com.opengamma.strata.product.cms.ResolvedCms; import com.opengamma.strata.product.swap.SwapLeg; /** * Pricer for CMS products by swaption replication on a SABR formula with extrapolation. * <p> * This function provides the ability to price {@link ResolvedCms}. */ public class SabrExtrapolationReplicationCmsProductPricer { /** * The pricer for {@link CmsLeg}. */ private final SabrExtrapolationReplicationCmsLegPricer cmsLegPricer; /** * The pricer for {@link SwapLeg}. */ private final DiscountingSwapLegPricer payLegPricer; /** * Creates an instance using the default pay leg pricer. * * @param cmsLegPricer the pricer for {@link CmsLeg} */ public SabrExtrapolationReplicationCmsProductPricer( SabrExtrapolationReplicationCmsLegPricer cmsLegPricer) { this(cmsLegPricer, DiscountingSwapLegPricer.DEFAULT); } /** * Creates an instance. * * @param cmsLegPricer the pricer for {@link CmsLeg} * @param payLegPricer the pricer for {@link SwapLeg} */ public SabrExtrapolationReplicationCmsProductPricer( SabrExtrapolationReplicationCmsLegPricer cmsLegPricer, DiscountingSwapLegPricer payLegPricer) { this.cmsLegPricer = ArgChecker.notNull(cmsLegPricer, "cmsLegPricer"); this.payLegPricer = ArgChecker.notNull(payLegPricer, "payLegPricer"); } //------------------------------------------------------------------------- /** * Calculates the present value of the CMS product. * <p> * The present value of the product is the value on the valuation date. * <p> * CMS leg and pay leg are typically in the same currency. Thus the present value is expressed as a * single currency amount in most cases. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the present value */ public MultiCurrencyAmount presentValue( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { CurrencyAmount pvCmsLeg = cmsLegPricer.presentValue(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); if (!cms.getPayLeg().isPresent()) { return MultiCurrencyAmount.of(pvCmsLeg); } CurrencyAmount pvPayLeg = payLegPricer.presentValue(cms.getPayLeg().get(), ratesProvider); return MultiCurrencyAmount.of(pvCmsLeg).plus(pvPayLeg); } //------------------------------------------------------------------------- /** * Explains the present value of the CMS product. * <p> * This returns explanatory information about the calculation. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the explain PV map */ public ExplainMap explainPresentValue( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { ExplainMapBuilder builder = ExplainMap.builder(); builder.put(ExplainKey.ENTRY_TYPE, "CmsSwap"); List<ExplainMap> legsExplain = new ArrayList<>(); legsExplain.add(cmsLegPricer.explainPresentValue(cms.getCmsLeg(), ratesProvider, swaptionVolatilities)); if (cms.getPayLeg().isPresent()) { legsExplain.add(payLegPricer.explainPresentValue(cms.getPayLeg().get(), ratesProvider)); } builder.put(ExplainKey.LEGS, legsExplain); return builder.build(); } //------------------------------------------------------------------------- /** * Calculates the present value curve sensitivity of the CMS product. * <p> * The present value sensitivity of the product is the sensitivity of the present value to the underlying curves. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the present value sensitivity */ public PointSensitivityBuilder presentValueSensitivityRates( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { PointSensitivityBuilder pvSensiCmsLeg = cmsLegPricer.presentValueSensitivityRates(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); if (!cms.getPayLeg().isPresent()) { return pvSensiCmsLeg; } PointSensitivityBuilder pvSensiPayLeg = payLegPricer.presentValueSensitivity(cms.getPayLeg().get(), ratesProvider); return pvSensiCmsLeg.combinedWith(pvSensiPayLeg); } /** * Calculates the present value sensitivity to the SABR model parameters. * <p> * The present value sensitivity of the product is the sensitivity of the present value * to the SABR model parameters, alpha, beta, rho and nu. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the present value sensitivity */ public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { return cmsLegPricer.presentValueSensitivityModelParamsSabr(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); } /** * Calculates the present value sensitivity to the strike value. * <p> * The present value sensitivity of the product 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 cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the present value sensitivity */ public double presentValueSensitivityStrike( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { return cmsLegPricer.presentValueSensitivityStrike(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); } //------------------------------------------------------------------------- /** * Calculates the currency exposure of the product. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the currency exposure */ public MultiCurrencyAmount currencyExposure( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { CurrencyAmount ceCmsLeg = cmsLegPricer.presentValue(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); if (!cms.getPayLeg().isPresent()) { return MultiCurrencyAmount.of(ceCmsLeg); } MultiCurrencyAmount cePayLeg = payLegPricer.currencyExposure(cms.getPayLeg().get(), ratesProvider); return cePayLeg.plus(ceCmsLeg); } /** * Calculates the current cash of the product. * * @param cms the CMS product * @param ratesProvider the rates provider * @param swaptionVolatilities the swaption volatilities * @return the current cash */ public MultiCurrencyAmount currentCash( ResolvedCms cms, RatesProvider ratesProvider, SabrSwaptionVolatilities swaptionVolatilities) { CurrencyAmount ccCmsLeg = cmsLegPricer.currentCash(cms.getCmsLeg(), ratesProvider, swaptionVolatilities); if (!cms.getPayLeg().isPresent()) { return MultiCurrencyAmount.of(ccCmsLeg); } CurrencyAmount ccPayLeg = payLegPricer.currentCash(cms.getPayLeg().get(), ratesProvider); return MultiCurrencyAmount.of(ccPayLeg).plus(ccCmsLeg); } }