com.opengamma.strata.pricer.swaption.SabrSwaptionPhysicalProductPricer Maven / Gradle / Ivy
/*
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.swaption;
import static com.opengamma.strata.market.model.SabrParameterType.ALPHA;
import static com.opengamma.strata.market.model.SabrParameterType.BETA;
import static com.opengamma.strata.market.model.SabrParameterType.NU;
import static com.opengamma.strata.market.model.SabrParameterType.RHO;
import java.time.ZonedDateTime;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.value.ValueDerivatives;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.impl.option.BlackFormulaRepository;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.swap.DiscountingSwapProductPricer;
import com.opengamma.strata.product.swap.ResolvedSwap;
import com.opengamma.strata.product.swap.ResolvedSwapLeg;
import com.opengamma.strata.product.swap.Swap;
import com.opengamma.strata.product.swaption.ResolvedSwaption;
/**
* Pricer for swaption with physical settlement in SABR model on the swap rate.
*
* The swap underlying the swaption must have a fixed leg on which the forward rate is computed.
* The underlying swap must be single currency.
*
* The volatility parameters are not adjusted for the underlying swap convention.
* The volatilities from the provider are taken as such.
*
* The value of the swaption after expiry is 0. For a swaption which already expired, negative number is returned by
* the method, {@link SabrSwaptionVolatilities#relativeTime(ZonedDateTime)}.
*/
public class SabrSwaptionPhysicalProductPricer
extends VolatilitySwaptionPhysicalProductPricer {
/**
* Default implementation.
*/
public static final SabrSwaptionPhysicalProductPricer DEFAULT =
new SabrSwaptionPhysicalProductPricer(DiscountingSwapProductPricer.DEFAULT);
/**
* Creates an instance.
*
* @param swapPricer the pricer for {@link Swap}
*/
public SabrSwaptionPhysicalProductPricer(DiscountingSwapProductPricer swapPricer) {
super(swapPricer);
}
//-------------------------------------------------------------------------
/**
* Calculates the present value sensitivity of the swaption product to the rate curves.
*
* The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the
* curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential
* re-calibration of the model parameters to the raw market data.
*
* @param swaption the swaption product
* @param ratesProvider the rates provider
* @param swaptionVolatilities the volatilities
* @return the point sensitivity to the rate curves
*/
public PointSensitivityBuilder presentValueSensitivityRatesStickyModel(
ResolvedSwaption swaption,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(swaption, ratesProvider, swaptionVolatilities);
ZonedDateTime expiryDateTime = swaption.getExpiry();
double expiry = swaptionVolatilities.relativeTime(expiryDateTime);
ResolvedSwap underlying = swaption.getUnderlying();
ResolvedSwapLeg fixedLeg = fixedLeg(underlying);
if (expiry < 0d) { // Option has expired already
return PointSensitivityBuilder.none();
}
double forward = forwardRate(swaption, ratesProvider);
double pvbp = getSwapPricer().getLegPricer().pvbp(fixedLeg, ratesProvider);
double strike = getSwapPricer().getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp);
double tenor = swaptionVolatilities.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate());
double shift = swaptionVolatilities.shift(expiry, tenor);
ValueDerivatives volatilityAdj = swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward);
boolean isCall = fixedLeg.getPayReceive().isPay();
// Payer at strike is exercise when rate > strike, i.e. call on rate
// Backward sweep
PointSensitivityBuilder pvbpDr = getSwapPricer().getLegPricer().pvbpSensitivity(fixedLeg, ratesProvider);
PointSensitivityBuilder forwardDr = getSwapPricer().parRateSensitivity(underlying, ratesProvider);
double shiftedForward = forward + shift;
double shiftedStrike = strike + shift;
double price = BlackFormulaRepository.price(shiftedForward, shiftedStrike, expiry, volatilityAdj.getValue(), isCall);
double delta = BlackFormulaRepository.delta(shiftedForward, shiftedStrike, expiry, volatilityAdj.getValue(), isCall);
double vega = BlackFormulaRepository.vega(shiftedForward, shiftedStrike, expiry, volatilityAdj.getValue());
double sign = swaption.getLongShort().sign();
return pvbpDr.multipliedBy(price * sign * Math.signum(pvbp))
.combinedWith(forwardDr.multipliedBy((delta + vega * volatilityAdj.getDerivative(0)) * Math.abs(pvbp) * sign));
}
//-------------------------------------------------------------------------
/**
* Calculates the present value sensitivity to the SABR model parameters of the swaption product.
*
* The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu.
*
* @param swaption the swaption product
* @param ratesProvider the rates provider
* @param swaptionVolatilities the volatilities
* @return the point sensitivity to the SABR model parameters
*/
public PointSensitivityBuilder presentValueSensitivityModelParamsSabr(
ResolvedSwaption swaption,
RatesProvider ratesProvider,
SabrSwaptionVolatilities swaptionVolatilities) {
validate(swaption, ratesProvider, swaptionVolatilities);
double expiry = swaptionVolatilities.relativeTime(swaption.getExpiry());
ResolvedSwap underlying = swaption.getUnderlying();
ResolvedSwapLeg fixedLeg = fixedLeg(underlying);
double tenor = swaptionVolatilities.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate());
double shift = swaptionVolatilities.shift(expiry, tenor);
double pvbp = getSwapPricer().getLegPricer().pvbp(fixedLeg, ratesProvider);
double strike = getSwapPricer().getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp);
if (expiry < 0d) { // Option has expired already
return PointSensitivityBuilder.none();
}
double forward = forwardRate(swaption, ratesProvider);
double volatility = swaptionVolatilities.volatility(expiry, tenor, strike, forward);
DoubleArray derivative =
swaptionVolatilities.volatilityAdjoint(expiry, tenor, strike, forward).getDerivatives();
// Backward sweep
double vega = Math.abs(pvbp) * BlackFormulaRepository.vega(forward + shift, strike + shift, expiry, volatility) *
swaption.getLongShort().sign();
// sensitivities
Currency ccy = fixedLeg.getCurrency();
SwaptionVolatilitiesName name = swaptionVolatilities.getName();
return PointSensitivityBuilder.of(
SwaptionSabrSensitivity.of(name, expiry, tenor, ALPHA, ccy, vega * derivative.get(2)),
SwaptionSabrSensitivity.of(name, expiry, tenor, BETA, ccy, vega * derivative.get(3)),
SwaptionSabrSensitivity.of(name, expiry, tenor, RHO, ccy, vega * derivative.get(4)),
SwaptionSabrSensitivity.of(name, expiry, tenor, NU, ccy, vega * derivative.get(5)));
}
}