/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.credit.options;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_20140213_PRICES;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_20140213_RECOVERY_RATES;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_21_COUPON;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_21_NAMES;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_21_RECOVERY_RATE;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.INDEX_TENORS;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.getCDX_NA_HY_20140213_CreditCurves;
import static com.opengamma.analytics.financial.credit.options.YieldCurveProvider.ISDA_USD_20140213;
import static com.opengamma.analytics.financial.credit.options.YieldCurveProvider.ISDA_USD_20140213_RATES;
import static com.opengamma.analytics.financial.credit.options.YieldCurveProvider.makeUSDBuilder;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Period;
import com.opengamma.analytics.financial.credit.index.CDSIndexCalculator;
import com.opengamma.analytics.financial.credit.index.IntrinsicIndexDataBundle;
import com.opengamma.analytics.financial.credit.index.PortfolioSwapAdjustment;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalytic;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalyticFactory;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDABaseTest;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurve;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantYieldCurve;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantYieldCurveBuild;
import com.opengamma.analytics.financial.credit.isdastandardmodel.PointsUpFront;
import com.opengamma.analytics.financial.credit.isdastandardmodel.PriceType;
import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.differentiation.FiniteDifferenceType;
/**
*
*/
public class CDXNAHYTest extends ISDABaseTest {
private static final double NOTIONAL = 1e8;
private static final LocalDate TRADE_DATE = LocalDate.of(2014, 2, 13);
private static final LocalDate EXPIRY = LocalDate.of(2014, 3, 19);
private static final LocalDate EXERCISE_SETTLE = LocalDate.of(2014, 3, 24);
private static final LocalDate MATURITY = LocalDate.of(2018, 12, 20);
private static final double PRICE = 107.62 * ONE_PC;
private static final double INDEX_COUPON = CDX_NA_HY_21_COUPON;
private static final double INDEX_RECOVERY = CDX_NA_HY_21_RECOVERY_RATE;
// private static final double EXP_FWD_ANNUITY = 4.83644025;
private static final double BBG_ATM_FWD = 107.1444434 * ONE_PC;
private static final Period TENOR = Period.ofYears(5);
private static final ISDACompliantCreditCurve[] CREDIT_CURVES = getCDX_NA_HY_20140213_CreditCurves();
private static final double[] RECOVERY_RATES = CDX_NA_HY_20140213_RECOVERY_RATES;
private static IntrinsicIndexDataBundle INTRINSIC_DATA = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES);
private static ISDACompliantYieldCurve YIELD_CURVE = ISDA_USD_20140213;
private static double[] PRICES = CDX_NA_HY_20140213_PRICES;
private static int INDEX_SIZE = RECOVERY_RATES.length;
private static final PointsUpFront[] PILLAR_PUF;
private static final CDSAnalyticFactory FACTORY = new CDSAnalyticFactory(INDEX_RECOVERY);
private static final CDSAnalytic FWD_START_CDX = FACTORY.makeForwardStartingCDS(TRADE_DATE, EXPIRY, MATURITY);
private static final CDSAnalytic FWD_CDX = FACTORY.makeCDX(EXPIRY, TENOR);
private static final CDSAnalytic[] PILLAR_CDX = FACTORY.makeCDX(TRADE_DATE, INDEX_TENORS);
private static final double[] STRIKES = new double[] {103, 104, 105, 106, 107.1444434, 108, 109, 110, 111 };
private static final double[] CALLPRICE = new double[] {1050.57, 7281.74, 38630.22, 154451.94, 529900.91, 1053705.97, 1894442.5, 2859098.57, 3855162.16 };
private static final double[] PUTPRICE = new double[] {4144889.03, 3151266.17, 2182760.61, 1298728.3, 529900.91, 198274.25, 39156.75, 3958.78, 168.34 };
private static final PortfolioSwapAdjustment PSA = new PortfolioSwapAdjustment();
private static final CDSIndexCalculator INDEX_CAL = new CDSIndexCalculator();
private static final boolean PRINT = false;
static {
final int n = PRICES.length;
PILLAR_PUF = new PointsUpFront[n];
for (int i = 0; i < n; i++) {
PILLAR_PUF[i] = new PointsUpFront(INDEX_COUPON, 1 - PRICES[i]);
}
if (PRINT) {
System.out.println("CDXNAHYTest - set PRINT to false before push");
}
}
/**
* This computes the (default adjusted) forward spread and index value using a pseudo index credit curve and adjusted intrinsic curves
*/
@Test
public void forwardValueTest() {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final double tES = ACT365F.getDayCountFraction(TRADE_DATE, EXERCISE_SETTLE);
final double expFwdPrice1 = -7149840.399010934 / NOTIONAL;
final double expFwdPrice2 = -7121885.71427097 / NOTIONAL;
final double expFwdPrice3 = -7150407.604015437 / NOTIONAL;
final double expFwdSpread1 = 333.22161805754155 * ONE_BP;
final double expFwdSpread2 = 333.5071399772611 * ONE_BP;
final double expFwdSpread3 = 333.06693990756 * ONE_BP;
//build (pseudo) index credit curve from PUF
final ISDACompliantCreditCurve cc = CREDIT_CURVE_BUILDER.calibrateCreditCurve(PILLAR_CDX, PILLAR_PUF, YIELD_CURVE);
final double q = cc.getSurvivalProbability(tE);
final double df = YIELD_CURVE.getDiscountFactor(tES);
final double fwdProt = PRICER.protectionLeg(FWD_START_CDX, YIELD_CURVE, cc, 0) + df * (1 - INDEX_RECOVERY) * (1 - q);
final double fwdAnn = PRICER.annuity(FWD_START_CDX, YIELD_CURVE, cc, PriceType.CLEAN, 0);
final double fwdSpread = fwdProt / fwdAnn;
final double fwdSpread2 = INDEX_CAL.defaultAdjustedForwardSpread(FWD_START_CDX, tE, YIELD_CURVE, cc);
assertEquals(fwdSpread, fwdSpread2, 1e-15);
final double fwdIndexVal = ((fwdProt - INDEX_COUPON * fwdAnn) / df);
final double fwdIndexVal2 = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, cc);
assertEquals(fwdIndexVal, fwdIndexVal2, 1e-15);
if (PRINT) {
System.out.println("df: " + df);
System.out.println("Fwd Spread: " + fwdSpread * TEN_THOUSAND);
System.out.println("Fwd Index val: " + NOTIONAL * fwdIndexVal);
}
final double fwdSpreadUnAdj = INDEX_CAL.defaultAdjustedForwardSpread(FWD_START_CDX, tE, YIELD_CURVE, INTRINSIC_DATA);
final double fwdIndexValUnAdj = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, INTRINSIC_DATA);
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double fwdSpreadAdj = INDEX_CAL.defaultAdjustedForwardSpread(FWD_START_CDX, tE, YIELD_CURVE, adjCurves);
final double fwdIndexValAdj = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
if (PRINT) {//intrinsic
System.out.println("Intrinsic fwd spread before and after adjustment:\t" + fwdSpreadUnAdj * TEN_THOUSAND + "\t" + fwdSpreadAdj * TEN_THOUSAND);
System.out.println("Intrinsic fwd value before and after adjustment:\t" + fwdIndexValUnAdj * NOTIONAL + "\t" + fwdIndexValAdj * NOTIONAL);
}
assertEquals("Regression test for index curve ATM Fwd", expFwdPrice1, fwdIndexVal2, 1e-15);
assertEquals("Regression test for intrinic ATM Fwd", expFwdPrice2, fwdIndexValUnAdj, 1e-15);
assertEquals("Regression test for adjusted intrinic ATM Fwd", expFwdPrice3, fwdIndexValAdj, 1e-15);
assertEquals("Regression test for index curve ATM Fwd spread", expFwdSpread1, fwdSpread2, 1e-15);
assertEquals("Regression test for intrinic ATM Fwd spread", expFwdSpread2, fwdSpreadUnAdj, 1e-15);
assertEquals("Regression test for adjusted intrinic ATM Fwd spread", expFwdSpread3, fwdSpreadAdj, 1e-15);
}
@Test
void forwardValueWithAccrualTest() {
final LocalDate expiry = LocalDate.of(2014, 3, 18);
final CDSAnalytic fwdStartCDS = FACTORY.makeForwardStartingCDS(TRADE_DATE, expiry, MATURITY);
// assertEquals(89, fwdStartCDS.getAccuredDays());
final ISDACompliantCreditCurve cc = CREDIT_CURVE_BUILDER.calibrateCreditCurve(PILLAR_CDX, PILLAR_PUF, YIELD_CURVE);
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, expiry);
final double fwdIndexVal = INDEX_CAL.defaultAdjustedForwardIndexValue(fwdStartCDS, tE, YIELD_CURVE, INDEX_COUPON, cc);
final double defSet = INDEX_CAL.expectedDefaultSettlementValue(tE, cc, fwdStartCDS.getLGD());
final double fwdIndexVal2 = defSet + PRICER.pv(fwdStartCDS, YIELD_CURVE, cc, INDEX_COUPON);
if (PRINT) {
System.out.println(fwdIndexVal * NOTIONAL);
System.out.println(fwdIndexVal2 * NOTIONAL);
}
assertEquals(fwdIndexVal, fwdIndexVal2, NOTIONAL * 1e-15);
}
@Test
void optionPriceTest() {
final double expFwdVal = -0.07149840399010934;
final double[] expPayer = new double[] {1166.48464873934, 7845.0135391454, 40556.7856883846, 158851.690745577, 536239.999079741, 1058884.2933964, 1896630.82108264, 2859437.33558545,
3855042.43135933 };
final double[] expRec = new double[] {4144837.70571472, 3151702.55128495, 2184600.64011402, 1303081.86185103, 536239.999079741, 203487.097861513, 41419.9422275726, 4412.77341021166,
204.185863913313 };
final double[] expVol = new double[] {0.296998752854268, 0.296883528058332, 0.296757503699748, 0.296619609888718, 0.296447951763999, 0.296292852663868, 0.296096569049928, 0.295877172385047,
0.295628805272022 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final double tES = ACT365F.getDayCountFraction(TRADE_DATE, EXERCISE_SETTLE);
final IndexOptionPricer oPricer = new IndexOptionPricer(FWD_CDX, tE, YIELD_CURVE, INDEX_COUPON);
//build credit curve assuming par spreads
final ISDACompliantCreditCurve cc = CREDIT_CURVE_BUILDER.calibrateCreditCurve(PILLAR_CDX, PILLAR_PUF, YIELD_CURVE);
final double fwdIndexVal = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, cc);
assertEquals(expFwdVal, fwdIndexVal, 1e-15);
final double vol = 0.3;
if (PRINT) {
final double df = YIELD_CURVE.getDiscountFactor(tES);
final double x0 = oPricer.calibrateX0(fwdIndexVal, vol);
System.out.println("df: " + df);
System.out.println("Default-adj fwd index value: " + fwdIndexVal);
System.out.println("X0: " + x0 * TEN_THOUSAND);
}
final int n = STRIKES.length;
for (int i = 0; i < n; i++) {
final double g = 1 - STRIKES[i] * ONE_PC;
final double payer1 = oPricer.getOptionPriceForPriceQuotedIndex(1 - BBG_ATM_FWD, vol, g, true);
final double recevier1 = oPricer.getOptionPriceForPriceQuotedIndex(1 - BBG_ATM_FWD, vol, g, false);
final double payer2 = oPricer.getOptionPriceForPriceQuotedIndex(fwdIndexVal, vol, g, true);
final double recevier2 = oPricer.getOptionPriceForPriceQuotedIndex(fwdIndexVal, vol, g, false);
double vol1 = 0;
double vol2 = 0;
if (1 - BBG_ATM_FWD < g) {
vol1 = oPricer.impliedVol(1 - BBG_ATM_FWD, g, CALLPRICE[i] / NOTIONAL, true);
vol2 = oPricer.impliedVol(fwdIndexVal, g, CALLPRICE[i] / NOTIONAL, true);
} else {
vol1 = oPricer.impliedVol(1 - BBG_ATM_FWD, g, PUTPRICE[i] / NOTIONAL, false);
vol2 = oPricer.impliedVol(fwdIndexVal, g, PUTPRICE[i] / NOTIONAL, false);
}
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + payer1 * NOTIONAL + "\t" + recevier1 * NOTIONAL + "\t" + payer2 * NOTIONAL + "\t" + recevier2 * NOTIONAL + "\t" + vol1 + "\t" + vol2);
}
assertEquals("Regression test for payer option", expPayer[i] / NOTIONAL, payer1, 1e-12);
assertEquals("Regression test for reciver option", expRec[i] / NOTIONAL, recevier1, 1e-12);
assertEquals("Regression test for implied vol", expVol[i], vol1, 1e-12);
}
}
@Test
public void cs01FlatTest() {
final double[] expCS01 = new double[] {138.946475346697, 781.47013737074, 3269.03852433866, 9939.58490066654, 23642.6842859673, 34507.4999277713, 42497.1607278321, 45100.0176303277,
45494.3878513171 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final CS01OptionCalculator cs01Cal = new CS01OptionCalculator();
final double vol = 0.3;
final CDSAnalytic cds = PILLAR_CDX[1]; //5Y cds
final PointsUpFront puf = PILLAR_PUF[1]; //the 5Y quote
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double cs01Payer = NOTIONAL * ONE_BP * cs01Cal.indexCurveApprox(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, true, ONE_BP);
final double cs01Rec = NOTIONAL * ONE_BP * cs01Cal.indexCurveApprox(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + cs01Payer + "\t" + cs01Rec);
}
assertEquals(expCS01[i], cs01Payer, NOTIONAL * 1e-15);
}
}
@Test
public void cs01Test() {
final double[] expCS01 = new double[] {139.045084643814, 781.921221873803, 3270.49124500207, 9942.71206365506, 23646.9093111734, 34510.8082974714, 42498.5229611971, 45100.2751552152,
45494.4025851437 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final CS01OptionCalculator cs01Cal = new CS01OptionCalculator();
final double vol = 0.3;
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double cs01Payer = NOTIONAL * ONE_BP * cs01Cal.indexCurveApprox(FWD_CDX, tE, PILLAR_CDX, PILLAR_PUF, INDEX_COUPON, YIELD_CURVE, strike, vol, true, ONE_BP);
final double cs01Rec = NOTIONAL * ONE_BP * cs01Cal.indexCurveApprox(FWD_CDX, tE, PILLAR_CDX, PILLAR_PUF, INDEX_COUPON, YIELD_CURVE, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + cs01Payer + "\t" + cs01Rec);
}
assertEquals(expCS01[i], cs01Payer, NOTIONAL * 1e-15);
}
}
@Test
public void cs01FullTest() {
final double[] expCS01 = new double[] {138.863619033975, 781.087728296301, 3267.78959129945, 9936.82959737445, 23638.7271990648, 34504.0347198934, 42495.0858808288, 45098.7764730417,
45493.3340286387 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final CS01OptionCalculator cs01Cal = new CS01OptionCalculator();
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double cs01Payer = NOTIONAL * ONE_BP * cs01Cal.fullCal(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, ONE_BP);
final double cs01Rec = NOTIONAL * ONE_BP * cs01Cal.fullCal(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + cs01Payer + "\t" + cs01Rec);
}
assertEquals(expCS01[i], cs01Payer, NOTIONAL * 1e-15);
}
}
@Test
public void deltaTest() {
final double[] expDelta = new double[] {0.00289580626005673, 0.0164481880047495, 0.0694879134935995, 0.213319724045625, 0.512531360909954, 0.752647383327198, 0.931288304651875, 0.990256794878088,
0.999316059617505 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double eps = 1e-6;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double deltaPayer = greekCal.delta(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, eps, FiniteDifferenceType.CENTRAL);
final double deltaRec = greekCal.delta(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, false, eps, FiniteDifferenceType.CENTRAL);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + deltaPayer + "\t" + deltaRec);
}
//TODO [PLAT-5993] The accuracy has been turned down because different platforms produce different results. However this is a very high tolerance for this type of test.
assertEquals(expDelta[i], deltaPayer, 1e-10);
}
}
@Test
public void deltaPrintTest() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double eps = 1e-6;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < 100; i++) {
final double strikePrice = 102. + 10 * i / 99.;
final IndexOptionStrike strike = new ExerciseAmount(1 - strikePrice * ONE_PC);
final double deltaPayer = greekCal.delta(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, eps, FiniteDifferenceType.CENTRAL);
System.out.println(strikePrice + "\t" + deltaPayer);
}
}
}
@Test
public void deltaByCS01Test() {
final double[] expDelta = new double[] {0.00305222696988043, 0.0171664968361922, 0.0718107280135607, 0.218342127985126, 0.519357100911974, 0.7580237043069, 0.933531993475759, 0.99070875896559,
0.999371860506079 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double vol = 0.3;
final CDSAnalytic cds = PILLAR_CDX[1]; //5Y cds
final PointsUpFront puf = PILLAR_PUF[1]; //the 5Y quote
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double deltaPayer = greekCal.deltaByCS01(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, true, ONE_BP);
final double deltaRec = greekCal.deltaByCS01(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + deltaPayer + "\t" + deltaRec);
}
assertEquals(expDelta[i], deltaPayer, 1e-12);
}
}
@Test(enabled = false)
public void gammaTest() {
final double[] expGamma = new double[] {0.65886335151805, 3.04714161346829, 9.92606062448497, 21.6242635776853, 29.6437457913967, 23.4868756388006, 9.82867259802233, 1.91733434684593,
0.149075196631542 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double eps = 1e-6;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double gammaPayer = greekCal.gamma(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, eps);
final double gammaRec = greekCal.gamma(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, false, eps);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + gammaPayer + "\t" + gammaRec);
}
//TODO [PLAT-5993] The accuracy has been turned down because different platforms produce different results. However this is a very high tolerance for this type of test.
assertEquals(expGamma[i], gammaPayer, 1e-3 * expGamma[i]);
}
}
@Test
public void gammaByCS01Test() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double vol = 0.3;
final CDSAnalytic cds = PILLAR_CDX[1]; //5Y cds
final PointsUpFront puf = PILLAR_PUF[1]; //the 5Y quote
for (final double element : STRIKES) {
final IndexOptionStrike strike = new ExerciseAmount(1 - element * ONE_PC);
final double gammaPayer = greekCal.gammaByCS01(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, true);
final double gammaRec = greekCal.gammaByCS01(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, false);
System.out.println(element + "\t" + gammaPayer + "\t" + gammaRec);
}
}
}
@Test
public void gammaPrintTest() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double eps = 1e-4;
final CDSAnalytic cds = PILLAR_CDX[1]; //5Y cds
final PointsUpFront puf = PILLAR_PUF[1]; //the 5Y quote
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < 100; i++) {
// final double strikePrice = 110. + 1 * i / 99.;
final double strikePrice = 102. + 10 * i / 99.;
final IndexOptionStrike strike = new ExerciseAmount(1 - strikePrice * ONE_PC);
final double gammaPayer = greekCal.gamma(FWD_CDX, tE, cdx, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, eps);
final double gammaPayerCS01 = greekCal.gammaByCS01(FWD_CDX, tE, cds, puf, INDEX_COUPON, YIELD_CURVE, strike, vol, true, ONE_BP, 10 * ONE_BP);
System.out.println(strikePrice + "\t" + gammaPayer + "\t" + gammaPayerCS01);
}
}
}
@Test
public void vegaTest() {
final double[] expVega = new double[] {396.574716989006, 1834.09584242344, 5974.56411533317, 13015.7901309657, 17842.7602031284, 14136.901958007, 5915.92153748407, 1154.027149417,
89.7029953619661 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double vol = 0.3;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double vega1PC = NOTIONAL * ONE_PC * greekCal.vega(atmFwd, FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, strike, vol, true, ONE_PC, FiniteDifferenceType.FORWARD);
final double vegaFD = NOTIONAL * ONE_HUNDRED * ONE_BP * greekCal.vega(atmFwd, FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, strike, vol, false, ONE_BP, FiniteDifferenceType.CENTRAL);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + vega1PC + "\t" + vegaFD);
}
assertEquals(expVega[i], vegaFD, 1e-15 * NOTIONAL);
}
}
public void vegaPrintTest() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double vol = 0.3;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
for (int i = 0; i < 100; i++) {
final double strikePrice = 102. + 10 * i / 99.;
final IndexOptionStrike strike = new ExerciseAmount(1 - strikePrice * ONE_PC);
final double vegaFD = NOTIONAL * ONE_HUNDRED * ONE_BP * greekCal.vega(atmFwd, FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, strike, vol, false, ONE_BP, FiniteDifferenceType.CENTRAL);
System.out.println(strikePrice + "\t" + vegaFD);
}
}
}
@Test
public void thetaTest() {
final double[] expTheta = new double[] {-166.324597258476, -787.075048874065, -2610.1855614945, -5754.7887100487, -7928.53905375824, -6259.3422579046, -2580.19372964511, -480.551350985972,
-20.0888668935861 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double vol = 0.3;
final double oneDay = 1 / 365.;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double thetaPayer = NOTIONAL * oneDay * greekCal.thetaWithDefault(atmFwd, FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, strike, vol, true, oneDay);
final double thetaRec = NOTIONAL * oneDay * greekCal.thetaWithDefault(atmFwd, FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, strike, vol, false, oneDay);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + thetaPayer + "\t" + thetaRec);
}
assertEquals(expTheta[i], thetaPayer, 1e-15 * NOTIONAL);
}
}
@Test
public void thetaWithoutDefaultTest() {
final double[] expTheta = new double[] {-171.779302723284, -819.593563605345, -2752.95177577143, -6205.34070023028, -9030.51153313318, -7885.03115126178, -4590.44271716863, -2613.77608014867,
-2171.22546743581 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double oneDay = 1 / 365.;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
//System.out.println("ATM FWD\t" + atmFwd);
final double vol = 0.3;
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double thetaPayer = NOTIONAL * oneDay * greekCal.thetaWithoutDefault(FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, true, oneDay);
final double thetaRec = NOTIONAL * oneDay * greekCal.thetaWithoutDefault(FWD_CDX, tE, INDEX_COUPON, YIELD_CURVE, adjCurves, strike, vol, false, oneDay);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + thetaPayer + "\t" + thetaRec);
}
assertEquals(expTheta[i], thetaPayer, 1e-15 * NOTIONAL);
}
}
@Test
public void irDV01Test() {
final double[] expIR01 = new double[] {1.53050161177664, 12.0242139330876, 65.5557026436111, 247.553870009976, 716.909943688972, 1166.39438932867, 1553.4092320784, 1696.56799845659,
1713.3387819529 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double[] rates = ISDA_USD_20140213_RATES;
final ISDACompliantYieldCurveBuild ycBuilder = makeUSDBuilder(TRADE_DATE);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
final double indexPUF = PILLAR_PUF[1].getPointsUpFront();
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double ir01Payer = NOTIONAL * ONE_BP * greekCal.irDV01(FWD_CDX, tE, cdx, INDEX_COUPON, indexPUF, ycBuilder, rates, strike, vol, true, ONE_BP);
final double ir01Rec = NOTIONAL * ONE_BP * greekCal.irDV01(FWD_CDX, tE, cdx, INDEX_COUPON, indexPUF, ycBuilder, rates, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + ir01Payer + "\t" + ir01Rec);
}
assertEquals(expIR01[i], ir01Payer, 1e-15 * NOTIONAL);
}
}
@Test
public void irDV01FullTest() {
final double[] expIR01 = new double[] {1.52646334094705, 12.0006324213253, 65.4562450567238, 247.258505507242, 716.252880789743, 1165.50127736789, 1552.39497727707, 1695.54046945928,
1712.31479267827 };
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final double[] rates = ISDA_USD_20140213_RATES;
final ISDACompliantYieldCurveBuild ycBuilder = makeUSDBuilder(TRADE_DATE);
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double vol = 0.3;
final CDSAnalytic cdx = PILLAR_CDX[1]; //5Y
for (int i = 0; i < STRIKES.length; i++) {
final IndexOptionStrike strike = new ExerciseAmount(1 - STRIKES[i] * ONE_PC);
final double ir01Payer = NOTIONAL * ONE_BP * greekCal.irDV01(FWD_CDX, tE, cdx, INDEX_COUPON, ycBuilder, rates, adjCurves, strike, vol, true, ONE_BP);
final double ir01Rec = NOTIONAL * ONE_BP * greekCal.irDV01(FWD_CDX, tE, cdx, INDEX_COUPON, ycBuilder, rates, adjCurves, strike, vol, false, ONE_BP);
if (PRINT) {
System.out.println(STRIKES[i] + "\t" + ir01Payer + "\t" + ir01Rec);
}
assertEquals(expIR01[i], ir01Payer, 1e-15 * NOTIONAL);
}
}
@Test
public void defaultSenseTest() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final FiniteDifferenceGreekCalculator greekCal = new FiniteDifferenceGreekCalculator();
final String[] names = CDX_NA_HY_21_NAMES;
final double vol = 0.3;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(indexPUF, PILLAR_CDX, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA);
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, adjCurves);
final String[] exampleNames = new String[] {"The AES Corp", "BOMBARDIER INC.", "J C Penney Co Inc", "TX Competitive Elec Hldgs Co LLC" };
final int nNames = exampleNames.length;
final double[] atmFwdWithDefaults = new double[nNames];
final List<String> listNames = Arrays.asList(names);
int index = 0;
System.out.print("Strike price");
for (final String name : exampleNames) {
System.out.print("\t" + name);
final int pos = listNames.indexOf(name);
if (pos < 0) {
throw new MathException("cannot find " + name);
}
final IntrinsicIndexDataBundle withDefault = adjCurves.withDefault(pos);
atmFwdWithDefaults[index++] = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, withDefault);
}
System.out.print("\n");
final IndexOptionPricer pricer = new IndexOptionPricer(FWD_CDX, tE, YIELD_CURVE, INDEX_COUPON);
for (int i = 0; i < 100; i++) {
final double strikePrice = 102. + 10 * i / 99.;
System.out.print(strikePrice);
final IndexOptionStrike strike = new ExerciseAmount(1 - strikePrice * ONE_PC);
final double payer = pricer.getOptionPremium(atmFwd, vol, strike, true);
for (int jj = 0; jj < nNames; jj++) {
final double payerWithDefault = pricer.getOptionPremium(atmFwdWithDefaults[jj], vol, strike, true);
final double diffPayer = payerWithDefault - payer;
System.out.print("\t" + diffPayer);
}
System.out.print("\n");
}
}
}
@Test
public void defaultSense2Test() {
if (PRINT) {
final double tE = ACT365F.getDayCountFraction(TRADE_DATE, EXPIRY);
final double vol = 0.3;
final int n = PILLAR_PUF.length;
final double[] indexPUF = new double[n];
for (int i = 0; i < n; i++) {
indexPUF[i] = PILLAR_PUF[i].getPointsUpFront();
}
final ISDACompliantCreditCurve indexCurve = CREDIT_CURVE_BUILDER.calibrateCreditCurve(PILLAR_CDX, PILLAR_PUF, YIELD_CURVE);
final double defSettle = (1 - INDEX_RECOVERY) / INDEX_SIZE;
final double atmFwd = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, YIELD_CURVE, INDEX_COUPON, indexCurve);
final double atmFwdWithDefault = INDEX_CAL.defaultAdjustedForwardIndexValue(FWD_START_CDX, tE, INDEX_SIZE, YIELD_CURVE, INDEX_COUPON, indexCurve, defSettle, 1);
final IndexOptionPricer pricer = new IndexOptionPricer(FWD_CDX, tE, YIELD_CURVE, INDEX_COUPON);
for (int i = 0; i < 100; i++) {
final double strikePrice = 102. + 10 * i / 99.;
System.out.print(strikePrice);
final IndexOptionStrike strike = new ExerciseAmount(1 - strikePrice * ONE_PC);
final double payer = pricer.getOptionPremium(atmFwd, vol, strike, true);
final double payerWithDefault = pricer.getOptionPremium(atmFwdWithDefault, vol, strike, true);
final double diffPayer = payerWithDefault - payer;
System.out.print("\t" + diffPayer);
System.out.print("\n");
}
}
}
}