/** * 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 static com.opengamma.financial.convention.businessday.BusinessDayDateUtils.addWorkDays; import static org.testng.AssertJUnit.assertEquals; import org.testng.annotations.Test; import org.threeten.bp.LocalDate; import org.threeten.bp.Month; import org.threeten.bp.Period; import com.opengamma.analytics.financial.credit.isdastandardmodel.AnalyticCDSPricer; 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.PriceType; import com.opengamma.analytics.financial.credit.isdastandardmodel.fastcalibration.CreditCurveCalibrator; import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository; import com.opengamma.util.test.TestGroup; /** * Test. */ @Test(groups = TestGroup.UNIT) public class DefaultSwaptionTest extends ISDABaseTest { private static AnalyticCDSPricer PRICER = new AnalyticCDSPricer(); private static ISDACompliantYieldCurve YIELD_CURVE; private static ISDACompliantCreditCurve CREDIT_CURVE; private static CDSAnalytic CDS; private static double T; static { final CDSAnalyticFactory factory = new CDSAnalyticFactory(); final LocalDate tradeDate = LocalDate.of(2013, Month.NOVEMBER, 28); final LocalDate spotDate = addWorkDays(tradeDate.minusDays(1), 3, DEFAULT_CALENDAR); final LocalDate expiry = LocalDate.of(2014, 3, 20); final String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "9M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "11Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; final String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; final double[] rates = new double[] {0.00445, 0.009488, 0.012337, 0.017762, 0.01935, 0.020838, 0.01652, 0.02018, 0.023033, 0.02525, 0.02696, 0.02825, 0.02931, 0.03017, 0.03092, 0.0316, 0.03231, 0.03367, 0.03419, 0.03411, 0.03412 }; YIELD_CURVE = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT360, D30360, Period.ofYears(1)); final Period[] tenors = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(3), Period.ofYears(5), Period.ofYears(7), Period.ofYears(10) }; final CDSAnalytic[] pillarCDS = factory.makeIMMCDS(tradeDate, tenors); final double[] spreads = new double[] {0.00886315689995649, 0.00886315689995649, 0.0133044689825873, 0.0171490070952563, 0.0183903639181293, 0.0194721890639724 }; final CreditCurveCalibrator calibrator = new CreditCurveCalibrator(pillarCDS, YIELD_CURVE); CREDIT_CURVE = calibrator.calibrate(spreads); CDS = factory.makeForwardStartingCDS(tradeDate, expiry, LocalDate.of(2019, 3, 20)); T = ACT365F.getDayCountFraction(tradeDate, expiry); } /** * Round trip test. Does not test that the default swaption is priced correctly, just that the implied vol formula is consistent with the pricing */ @Test public void impliedVolConsistencyTest() { final DefaultSwaption ds = new DefaultSwaption(); final double fwdSpread = PRICER.parSpread(CDS, YIELD_CURVE, CREDIT_CURVE); final boolean hasFEP = true; for (int j = 0; j < 20; j++) { final double vol = 0.1 + 0.7 * j / 20.; for (int i = 0; i < 20; i++) { final double k = fwdSpread * Math.exp(vol * Math.sqrt(T) * 6 * (i / 20. - 0.5)); final boolean isPayer = k > fwdSpread; final double price = ds.price(CDS, YIELD_CURVE, CREDIT_CURVE, k, T, vol, isPayer, hasFEP); final double iv = ds.impliedVol(CDS, YIELD_CURVE, CREDIT_CURVE, k, T, price, isPayer, hasFEP); // System.out.println(k + " " + price + "\t" + vol + "\t" + iv); assertEquals(isPayer + " " + i + " " + j, vol, iv, 1e-9); } } } /** * Logic taken from {@link SingleNameCDSOptionTest} */ @Test public void priceTest() { final DefaultSwaption ds = new DefaultSwaption(); final LocalDate tradeDate = LocalDate.of(2014, 2, 5); final LocalDate expiry = LocalDate.of(2014, 3, 20); final LocalDate maturity = LocalDate.of(2019, 6, 20); final double[] pillarParSpreads; final CDSAnalyticFactory factory = new CDSAnalyticFactory(); final Period[] pillarTenors = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(2), Period.ofYears(3), Period.ofYears(4), Period.ofYears(5), Period.ofYears(7), Period.ofYears(10) }; final CDSAnalytic[] pillarCDS = factory.makeIMMCDS(tradeDate, pillarTenors); final double[] strikes = new double[] {100, 140, 150, 160, 170, 180, 182.767, 190, 200, 210, 220, 230, 250, 300 }; final double[] spreads = new double[] {57.43, 74.97, 111.32, 139.32, 157.64, 173.66, 209.28, 228.35 }; final int n = spreads.length; pillarParSpreads = new double[n]; for (int i = 0; i < n; i++) { pillarParSpreads[i] = spreads[i] * ONE_BP; } final double tEAlt = ACT_ACT_ISDA.getDayCountFraction(tradeDate, expiry); final CDSAnalytic fwdCDS = factory.makeCDS(tradeDate, expiry.plusDays(1), expiry.plusDays(1), expiry.plusDays(1), maturity); final ISDACompliantCreditCurve cc = CREDIT_CURVE_BUILDER.calibrateCreditCurve(pillarCDS, pillarParSpreads, YIELD_CURVE); final double expFwdProt = PRICER.protectionLeg(fwdCDS, YIELD_CURVE, cc, 0.0); final double expFwdAnnuity = PRICER.annuity(fwdCDS, YIELD_CURVE, cc, PriceType.CLEAN, 0.0); final double fwdSpread = expFwdProt / expFwdAnnuity; final double vol = 0.33; final int m = strikes.length; for (int i = 0; i < m; i++) { final double pRef = expFwdAnnuity * BlackFormulaRepository.price(fwdSpread, strikes[i] * ONE_BP, tEAlt, vol, true); final double p = ds.price(fwdCDS, YIELD_CURVE, cc, strikes[i] * ONE_BP, tEAlt, vol, true, false); assertEquals(pRef, p, 1.e-12); } } }