/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.impl.credit.isda;
import java.util.Arrays;
import com.opengamma.strata.collect.ArgChecker;
/**
* Standard CDS have a standard premium (100 or 500bps in North America) and are quoted as either
* as Points Up-Front (PUF) or quoted spread - these method allow conversion via a single constant hazard rate.
* <p>
* A credit curve can be built that is consistent with market quotes;
* this can then be used to imply equivalent par spreads, and vice-versa.
*/
public class MarketQuoteConverter {
private final IsdaCompliantCreditCurveBuilder _builder;
private final AnalyticCdsPricer _pricer;
public MarketQuoteConverter() {
_builder = new FastCreditCurveBuilder();
_pricer = new AnalyticCdsPricer();
}
public MarketQuoteConverter(AccrualOnDefaultFormulae formula) {
_builder = new FastCreditCurveBuilder(formula);
_pricer = new AnalyticCdsPricer(formula);
}
//**************************************************************************************************************
// Various ways of quoting the price for a given credit curve
//**************************************************************************************************************
/**
* The clean price as a fraction of notional (it is often expressed as a percentage of notional).
*
* @param fractionalPUF the points up-front (as a fraction)
* @return the clean price (as a fraction)
*/
public double cleanPrice(double fractionalPUF) {
return 1 - fractionalPUF;
}
/**
* The clean price as a fraction of notional (it is often expressed as a percentage of notional).
* <p>
* This requires that a credit curve is bootstrapped first.
*
* @param cds the CDS to be traded
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @param coupon the fractional quoted spread (coupon) of the CDS
* @return the clean price (as a fraction)
*/
public double cleanPrice(
CdsAnalytic cds,
IsdaCompliantYieldCurve yieldCurve,
IsdaCompliantCreditCurve creditCurve,
double coupon) {
double puf = pointsUpFront(cds, coupon, yieldCurve, creditCurve);
return 1 - puf;
}
/**
* The principal - this is the clean present value.
*
* @param notional the notional of the trade
* @param cds the CDS to be traded
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @param coupon the fractional quoted spread (coupon) of the CDS
* @return the principle
*/
public double principal(
double notional,
CdsAnalytic cds,
IsdaCompliantYieldCurve yieldCurve,
IsdaCompliantCreditCurve creditCurve,
double coupon) {
return notional * _pricer.pv(cds, yieldCurve, creditCurve, coupon, CdsPriceType.CLEAN);
}
/**
* Get the points up-front - this requires that a credit curve is bootstrapped first.
*
* @param cds the CDS to be traded
* @param premium the standard premium of the CDS <b>expressed as a fraction</b>
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @return points up-front - these are usually quoted as a percentage of the notional.
* Here we return a fraction of notional, so 0.01 is 1(%) points up-front
*/
public double pointsUpFront(
CdsAnalytic cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
IsdaCompliantCreditCurve creditCurve) {
return _pricer.pv(cds, yieldCurve, creditCurve, premium, CdsPriceType.CLEAN);
}
/**
* Get the points up-front for a collection of CDSs - this requires that a credit curve
* is bootstrapped first.
* <p>
* This will give a slightly different answer to using a single (flat) credit curve for each
* CDS (the latter is the market standard).
*
* @param cds the collection of CDSs
* @param premium the single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @return points up-front (as fractions)
*/
public double[] pointsUpFront(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
IsdaCompliantCreditCurve creditCurve) {
ArgChecker.noNulls(cds, "cds");
int n = cds.length;
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = pointsUpFront(cds[i], premium, yieldCurve, creditCurve);
}
return res;
}
/**
* Get the points up-front for a collection of CDSs.
* <p>
* This requires that a credit curve is bootstrapped first. This will give a slightly
* different answer to using a single (flat) credit curve for each CDS
* (the latter is the market standard).
*
* @param cds the collection of CDSs
* @param premiums the premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @return points-upfront (as fractions)
*/
public double[] pointsUpFront(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
IsdaCompliantCreditCurve creditCurve) {
ArgChecker.noNulls(cds, "cds");
ArgChecker.notEmpty(premiums, "premiums");
int n = cds.length;
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = pointsUpFront(cds[i], premiums[i], yieldCurve, creditCurve);
}
return res;
}
/**
* The par spreads for a collection of CDSs where a single, non-flat, credit/hazard curve is known.
*
* @param cds the collection of CDSs
* @param yieldCurve the yield/discount curve
* @param creditCurve the credit/hazard curve
* @return par spreads
*/
public double[] parSpreads(CdsAnalytic[] cds, IsdaCompliantYieldCurve yieldCurve, IsdaCompliantCreditCurve creditCurve) {
ArgChecker.noNulls(cds, "cds");
ArgChecker.notNull(yieldCurve, "yieldCurve");
ArgChecker.notNull(creditCurve, "creditCurve");
int n = cds.length;
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = _pricer.parSpread(cds[i], yieldCurve, creditCurve);
}
return res;
}
//**************************************************************************************************************
// Single Converters. These convert between a single quote as PUF or quoted spread by building a
// constant hazard rate curve.
//**************************************************************************************************************
/**
* Convert from a CDS quoted spread to points up-front (PUF).
* @param cds The CDS to be traded
* @param qSpread The quoted spread
* @param yieldCurve the yield/discount curve
* @return the PUF
*/
public PointsUpFront convert(CdsAnalytic cds, CdsQuotedSpread qSpread, IsdaCompliantYieldCurve yieldCurve) {
ArgChecker.notNull(qSpread, "qSpread");
double puf = quotedSpreadToPUF(cds, qSpread.getCoupon(), yieldCurve, qSpread.getQuotedSpread());
return new PointsUpFront(qSpread.getCoupon(), puf);
}
/**
* Convert from a CDS quoted spread to points up-front (PUF). <b>Note:</b> Quoted spread is not the same as par spread
* (although they are numerically similar) - it is simply an alternative quoting convention from PUF where the CDS is priced
* off a flat credit/hazard curve.
* @param cds The CDS to be traded
* @param premium The standard premium of the CDS <b>expressed as a fraction</b>
* @param yieldCurve the yield/discount curve
* @param quotedSpread The quoted spread (<b>as a fraction</b>).
* @return points up-front - these are usually quoted as a percentage of the notional - here we return a fraction of notional,
* so 0.01 is 1(%) points up-front
*/
public double quotedSpreadToPUF(CdsAnalytic cds, double premium, IsdaCompliantYieldCurve yieldCurve, double quotedSpread) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notNull(yieldCurve, "yieldCurve");
IsdaCompliantCreditCurve creditCurve = _builder.calibrateCreditCurve(cds, quotedSpread, yieldCurve);
return pointsUpFront(cds, premium, yieldCurve, creditCurve);
}
/**
* Convert from a CDS points up-front (PUF) to a quoted spread.
* @param cds The CDS to be traded
* @param puf point-up-front (this contains the premium)
* @param yieldCurve the yield/discount curve
* @return the par spread
*/
public CdsQuotedSpread convert(CdsAnalytic cds, PointsUpFront puf, IsdaCompliantYieldCurve yieldCurve) {
ArgChecker.notNull(puf, "puf");
double qs = pufToQuotedSpread(cds, puf.getCoupon(), yieldCurve, puf.getPointsUpFront());
return new CdsQuotedSpread(puf.getCoupon(), qs);
}
/**
* Convert from a CDS quote as points up-front (PUF) and a standard premium, to a <i>quoted</i> spread.
* This is simply an alternative quoting convention from PUF where the CDS is priced off a flat credit/hazard curve.
* @param cds The CDS to be traded
* @param premium The standard premium of the CDS <b>expressed as a fraction</b>
* @param yieldCurve the yield/discount curve
* @param pointsUpfront points up-front
* @return the par spread <b>expressed as a fraction</b>
*/
public double pufToQuotedSpread(CdsAnalytic cds, double premium, IsdaCompliantYieldCurve yieldCurve, double pointsUpfront) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notNull(yieldCurve, "yieldCurve");
IsdaCompliantCreditCurve creditCurve = _builder.calibrateCreditCurve(cds, premium, yieldCurve, pointsUpfront);
return _pricer.parSpread(cds, yieldCurve, creditCurve);
}
//**************************************************************************************************************
// multiple Converters. These convert between N quotes as PUF or quoted spread by building N independent
// constant hazard rate curves.
//**************************************************************************************************************
public PointsUpFront[] convert(CdsAnalytic[] cds, CdsQuotedSpread[] qSpreads, IsdaCompliantYieldCurve yieldCurve) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notNull(qSpreads, "qSpreads");
int n = cds.length;
ArgChecker.isTrue(n == qSpreads.length, "numbe of CDSs does not match qSpreads");
PointsUpFront[] res = new PointsUpFront[n];
for (int i = 0; i < n; i++) {
res[i] = convert(cds[i], qSpreads[i], yieldCurve);
}
return res;
}
/**
* Convert from a set of CDSs quoted spreads to points up-front (PUF). <b>Note:</b> Quoted spread is not the same as par spread
* (although they are numerically similar) - it is simply an alternative quoting convention from PUF where each CDS is priced
* off a <b>separate</b> flat credit/hazard curve - i.e. the CDSs are completely decoupled from each other.
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve yieldCurve the yield/discount curve
* @param quotedSpreads The quoted spreads (<b>as a fractions</b>).
* @return points up-front (expressed as fractions)
*/
public double[] quotedSpreadsToPUF(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] quotedSpreads) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notEmpty(quotedSpreads, "parSpreads");
int n = cds.length;
ArgChecker.isTrue(n == quotedSpreads.length, "parSpreads wrong length");
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = quotedSpreadToPUF(cds[i], premium, yieldCurve, quotedSpreads[i]);
}
return res;
}
/**
* Convert from a set of CDSs quoted spreads to points up-front (PUF). <b>Note:</b> Quoted spread is not the same as par spread
* (although they are numerically similar) - it is simply an alternative quoting convention from PUF where each CDS is priced
* off a <b>separate</b> flat credit/hazard curve - i.e. the CDSs are completely decoupled from each other.
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve yieldCurve the yield/discount curve
* @param quotedSpreads The quoted spreads (<b>as a fractions</b>).
* @return points up-front (expressed as fractions)
*/
public double[] quotedSpreadsToPUF(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] quotedSpreads) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notEmpty(premiums, "premiums");
ArgChecker.notEmpty(quotedSpreads, "parSpreads");
int n = cds.length;
ArgChecker.isTrue(n == premiums.length, "premiums wrong length");
ArgChecker.isTrue(n == quotedSpreads.length, "parSpreads wrong length");
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = quotedSpreadToPUF(cds[i], premiums[i], yieldCurve, quotedSpreads[i]);
}
return res;
}
public CdsQuotedSpread[] convert(CdsAnalytic[] cds, PointsUpFront[] puf, IsdaCompliantYieldCurve yieldCurve) {
ArgChecker.notNull(cds, "cds");
ArgChecker.notNull(puf, "puf");
int n = cds.length;
ArgChecker.isTrue(n == puf.length, "numbe of CDSs does not match puf");
CdsQuotedSpread[] res = new CdsQuotedSpread[n];
for (int i = 0; i < n; i++) {
res[i] = convert(cds[i], puf[i], yieldCurve);
}
return res;
}
/**
* Get the equivalent <i>quoted</i> spreads for a collection of CDSs. This is simply a quoting convention -each CDS is priced
* off a <b>separate</b> flat credit/hazard curve - i.e. the CDSs are completely decoupled from each other.
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param pointsUpfront The points up-front (expressed as fractions)
* @see MarketQuoteConverter#pufToQuotedSpread
* @return collection of CDSs
*/
public double[] pufToQuotedSpreads(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] pointsUpfront) {
ArgChecker.noNulls(cds, "cds");
ArgChecker.notNull(yieldCurve, "yieldCurve");
ArgChecker.notEmpty(pointsUpfront, "pointsUpfront");
int n = cds.length;
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = pufToQuotedSpread(cds[i], premium, yieldCurve, pointsUpfront[i]);
}
return res;
}
/**
* Get the equivalent <i>quoted</i> spreads for a collection of CDSs. This is simply a quoting convention -each CDS is priced
* off a <b>separate</b> flat credit/hazard curve - i.e. the CDSs are completely decoupled from each other.
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param pointsUpfront The points up-front (expressed as fractions)
* @see MarketQuoteConverter#pufToQuotedSpread
* @return equivalent par spreads
*/
public double[] pufToQuotedSpreads(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] pointsUpfront) {
ArgChecker.noNulls(cds, "cds");
ArgChecker.notNull(yieldCurve, "yieldCurve");
ArgChecker.notEmpty(premiums, "premiums");
ArgChecker.notEmpty(pointsUpfront, "pointsUpfront");
int n = cds.length;
double[] res = new double[n];
for (int i = 0; i < n; i++) {
res[i] = pufToQuotedSpread(cds[i], premiums[i], yieldCurve, pointsUpfront[i]);
}
return res;
}
//**************************************************************************************************************
// Full Curve Converters. These convert between par spread quotes and PUF by constructing a single
// credit curve consistent with the quotes.
//**************************************************************************************************************
/**
* Convert from a set of CDSs quoted as a par spreads (the old way of quoting) to points up-front (PUF).
* Each CDS is priced off a <b>single non-flat</b> credit/hazard curve. <br>
* If the CDS are quoted as <b>quoted</b> spreads one must use quotedSpreadsToPUF instead
* {@link #pointsUpFront}
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve yieldCurve the yield/discount curve
* @param parSpreads The par-spreads (<b>as a fractions</b>).
* @return points up-front (expressed as fractions)
*/
public double[] parSpreadsToPUF(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] parSpreads) {
IsdaCompliantCreditCurve creditCurve = _builder.calibrateCreditCurve(cds, parSpreads, yieldCurve);
return pointsUpFront(cds, premium, yieldCurve, creditCurve);
}
/**
* Convert from a set of CDSs quoted as a par spreads (the old way of quoting) to points up-front (PUF).
* Each CDS is priced off a <b>single non-flat</b> credit/hazard curve. <br>
* If the CDS are quoted as <b>quoted</b> spreads one must use quotedSpreadsToPUF instead
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve yieldCurve the yield/discount curve
* @param parSpreads The par-spreads (<b>as a fractions</b>).
* @see MarketQuoteConverter#pointsUpFront
* @return points up-front (expressed as fractions)
*/
public double[] parSpreadsToPUF(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] parSpreads) {
IsdaCompliantCreditCurve creditCurve = _builder.calibrateCreditCurve(cds, parSpreads, yieldCurve);
return pointsUpFront(cds, premiums, yieldCurve, creditCurve);
}
/**
* The equivalent par spreads for a collection of CDSs where a single, non-flat, credit/hazard curve is bootstrapped to
* reprice all the given CDSs.
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param pointsUpfront The points up-front (expressed as fractions)
* @see MarketQuoteConverter#pufToParSpreads
* @return equivalent par spreads
*/
public double[] pufToParSpreads(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] pointsUpfront) {
ArgChecker.noNulls(cds, "cds");
int n = cds.length;
double[] premiums = new double[n];
Arrays.fill(premiums, premium);
return pufToParSpreads(cds, premiums, yieldCurve, pointsUpfront);
}
/**
* The equivalent par spreads for a collection of CDSs where a single, non-flat, credit/hazard curve is bootstrapped to
* reprice all the given CDSs.
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param pointsUpfront The points up-front (expressed as fractions)
* @see MarketQuoteConverter#parSpreads
* @return equivalent par spreads
*/
public double[] pufToParSpreads(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] pointsUpfront) {
IsdaCompliantCreditCurve creditCurve = _builder.calibrateCreditCurve(cds, premiums, yieldCurve, pointsUpfront);
return parSpreads(cds, yieldCurve, creditCurve);
}
/**
* Convert from par spreads to quoted spreads
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param parSpreads par spreads
* @return quoted spreads
*/
public double[] parSpreadsToQuotedSpreads(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] parSpreads) {
double[] puf = parSpreadsToPUF(cds, premium, yieldCurve, parSpreads);
return pufToQuotedSpreads(cds, premium, yieldCurve, puf);
}
/**
* Convert from par spreads to quoted spreads
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param parSpreads par spreads
* @return quoted spreads
*/
public double[] parSpreadsToQuotedSpreads(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] parSpreads) {
double[] puf = parSpreadsToPUF(cds, premiums, yieldCurve, parSpreads);
return pufToQuotedSpreads(cds, premiums, yieldCurve, puf);
}
/**
* Convert from quoted spreads to par spreads
* @param cds collection of CDSs
* @param premium The single common premium of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param quotedSpreads The quoted spreads
* @return par spreads
*/
public double[] quotedSpreadToParSpreads(
CdsAnalytic[] cds,
double premium,
IsdaCompliantYieldCurve yieldCurve,
double[] quotedSpreads) {
double[] puf = quotedSpreadsToPUF(cds, premium, yieldCurve, quotedSpreads);
return pufToParSpreads(cds, premium, yieldCurve, puf);
}
/**
* Convert from quoted spreads to par spreads
* @param cds collection of CDSs
* @param premiums The premiums of the CDSs expressed as fractions (these are usually 0.01 or 0.05)
* @param yieldCurve the yield/discount curve
* @param quotedSpreads The quoted spreads
* @return par spreads
*/
public double[] quotedSpreadToParSpreads(
CdsAnalytic[] cds,
double[] premiums,
IsdaCompliantYieldCurve yieldCurve,
double[] quotedSpreads) {
double[] puf = quotedSpreadsToPUF(cds, premiums, yieldCurve, quotedSpreads);
return pufToParSpreads(cds, premiums, yieldCurve, puf);
}
}