/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.credit.options;
import com.opengamma.analytics.financial.credit.isdastandardmodel.AnalyticCDSPricer;
import com.opengamma.analytics.financial.credit.isdastandardmodel.AnnuityForSpreadFunction;
import com.opengamma.analytics.financial.credit.isdastandardmodel.AnnuityForSpreadISDAFunction;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalytic;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurve;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantYieldCurve;
import com.opengamma.analytics.financial.credit.isdastandardmodel.PriceType;
import com.opengamma.analytics.financial.credit.isdastandardmodel.fastcalibration.SuperFastCreditCurveBuilder;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.util.ArgumentChecker;
/**
* Pricer for option to enter a forward starting CDS (aka default swaption)
*/
public class DefaultSwaption {
private final AnalyticCDSPricer _pricer = new AnalyticCDSPricer();
/**
* Price single-name CDS option
* @param forwardStartingCDS The underlying forward starting CDS
* @param yieldCurve The yield curve
* @param creditCurve The credit curve
* @param strike The fractional strike
* @param optionExpiry The option expiry
* @param vol The spread volatility
* @param isPayer True if payer swaption
* @param hasFrontEndProt True if no-knockout swaption
* @return The option price
*/
public double price(final CDSAnalytic forwardStartingCDS, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve, final double strike, final double optionExpiry,
final double vol, final boolean isPayer, final boolean hasFrontEndProt) {
ArgumentChecker.isTrue(forwardStartingCDS.getEffectiveProtectionStart() >= optionExpiry,
"Have not provided a forward CDS. The option expiry is {}, but the CDS(effective) protection start time is {}", optionExpiry, forwardStartingCDS.getEffectiveProtectionStart());
//front end protection is worth zero for an option to be the seller of protection
final double fep = isPayer && hasFrontEndProt ? forwardStartingCDS.getLGD() * yieldCurve.getDiscountFactor(optionExpiry) * (1 - creditCurve.getSurvivalProbability(optionExpiry)) : 0.0;
final double annuity = _pricer.annuity(forwardStartingCDS, yieldCurve, creditCurve, PriceType.CLEAN, 0);
final double protLeg = _pricer.protectionLeg(forwardStartingCDS, yieldCurve, creditCurve, 0);
final double fwdSpread = protLeg / annuity;
final double koVal = annuity * BlackFormulaRepository.price(fwdSpread, strike, optionExpiry, vol, isPayer);
return koVal + fep;
}
public double priceFlat(final CDSAnalytic cds, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve, final double strike, final double optionExpiry,
final double vol, final boolean isPayer, final boolean hasFrontEndProt, final double coupon) {
//note cds is the underlying CDS seen at the option expiry
ArgumentChecker.isTrue(cds.getCashSettleTime() >= optionExpiry, "Have provided a forward CDS. The option expiry is {}, but the CDS cash-settlement time is {}", optionExpiry,
cds.getCashSettleTime());
final ISDACompliantYieldCurve fwdYC = yieldCurve.withOffset(optionExpiry);
final ISDACompliantCreditCurve fwdCC = new ISDACompliantCreditCurve(creditCurve.withOffset(optionExpiry));
//this is the expected price at option expiry (+ 3 working days)
final double expPrice = _pricer.pv(cds, fwdYC, fwdCC, coupon);
final SuperFastCreditCurveBuilder ccBuidler = new SuperFastCreditCurveBuilder();
final ISDACompliantCreditCurve flatCC = ccBuidler.calibrateCreditCurve(cds, coupon, fwdYC, expPrice);
//these values are condition on no default by option expiry
final double annuity = _pricer.annuity(cds, fwdYC, flatCC, PriceType.CLEAN);
final double protLeg = _pricer.protectionLeg(cds, fwdYC, flatCC);
final double fwdSpread = protLeg / annuity;
//discount using 'real' credit curve
final double disAnnuity = yieldCurve.getDiscountFactor(cds.getCashSettleTime()) * creditCurve.getSurvivalProbability(optionExpiry) * annuity;
final double koVal = disAnnuity * BlackFormulaRepository.price(fwdSpread, strike, optionExpiry, vol, isPayer);
return koVal;
}
public double priceMod(final CDSAnalytic cds, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve, final double strike, final double optionExpiry, final double vol,
final boolean isPayer, final boolean hasFrontEndProt, final double coupon) {
final AnnuityForSpreadFunction annuityFunction = new AnnuityForSpreadISDAFunction(cds, yieldCurve.withOffset(optionExpiry));
//front end protection is worth zero for an option to be the seller of protection
final double fep = isPayer && hasFrontEndProt ? cds.getLGD() * yieldCurve.getDiscountFactor(optionExpiry) * (1 - creditCurve.getSurvivalProbability(optionExpiry)) : 0.0;
final double rpv01 = _pricer.annuity(cds, yieldCurve, creditCurve, PriceType.CLEAN, 0);
final double protLeg = _pricer.protectionLeg(cds, yieldCurve, creditCurve, 0);
final double fwdSpread = (protLeg + fep) / rpv01;
final double modK = coupon + (strike - coupon) * annuityFunction.evaluate(strike) / rpv01;
final double koVal = rpv01 * BlackFormulaRepository.price(fwdSpread, modK, optionExpiry, vol, isPayer);
return koVal;
}
/**
* Compute volatility implied by {@link #price}
* @param forwardStartingCDS The underlying forward starting CDS
* @param yieldCurve The yield curve
* @param creditCurve The credit curve
* @param strike The fractional strike
* @param optionExpiry The option expiry
* @param price The option price
* @param isPayer True of payer swaption
* @param hasFrontEndProt True if no-knockout swaption
* @return The implied volatility
*/
public double impliedVol(final CDSAnalytic forwardStartingCDS, final ISDACompliantYieldCurve yieldCurve, final ISDACompliantCreditCurve creditCurve, final double strike, final double optionExpiry,
final double price, final boolean isPayer, final boolean hasFrontEndProt) {
final double fep = isPayer && hasFrontEndProt ? forwardStartingCDS.getLGD() * yieldCurve.getDiscountFactor(optionExpiry) * (1 - creditCurve.getSurvivalProbability(optionExpiry)) : 0.0;
final double rpv01 = _pricer.annuity(forwardStartingCDS, yieldCurve, creditCurve, PriceType.CLEAN, 0);
final double protLeg = _pricer.protectionLeg(forwardStartingCDS, yieldCurve, creditCurve, 0);
final double fwdSpread = protLeg / rpv01;
final double fwdPrice = (price - fep) / rpv01;
return BlackFormulaRepository.impliedVolatility(fwdPrice, fwdSpread, strike, optionExpiry, isPayer);
}
}