/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.credit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import org.threeten.bp.LocalDate;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.credit.isdastandardmodel.AccrualOnDefaultFormulae;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalytic;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalyticFactory;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSQuoteConvention;
import com.opengamma.analytics.financial.credit.isdastandardmodel.FastCreditCurveBuilder;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurve;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurveBuilder;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurveBuilder.ArbitrageHandling;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantYieldCurve;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.region.RegionSource;
import com.opengamma.financial.analytics.conversion.CalendarUtils;
import com.opengamma.financial.analytics.isda.credit.CdsQuote;
import com.opengamma.financial.analytics.isda.credit.CreditCurveData;
import com.opengamma.financial.analytics.isda.credit.CreditCurveDataKey;
import com.opengamma.financial.convention.IsdaCreditCurveConvention;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.id.ExternalId;
import com.opengamma.sesame.Environment;
import com.opengamma.sesame.credit.curve.CreditCurveDataProviderFn;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.result.Result;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.ObjectsPair;
import com.opengamma.util.tuple.Pair;
/**
* Builds ISDA compliant credit curves using standard cds contracts to define the curve instruments.
*/
public class StandardIsdaCompliantCreditCurveFn implements IsdaCompliantCreditCurveFn {
private static final ISDACompliantCreditCurveBuilder CREDIT_CURVE_BUILDER =
new FastCreditCurveBuilder(AccrualOnDefaultFormulae.OrignalISDA, ArbitrageHandling.Fail);
private final IsdaCompliantYieldCurveFn _yieldCurveFn;
private final CreditCurveDataProviderFn _curveDataProviderFn;
private final HolidaySource _holidaySource;
private final RegionSource _regionSource;
/**
* Constructor for function.
* @param yieldCurveFn function for sourcing yield curves
* @param curveDataProviderFn function for sourcing credit curve data
* @param holidaySource holiday source for sourcing calendars
* @param regionSource region source for sourcing calendars
*/
public StandardIsdaCompliantCreditCurveFn(IsdaCompliantYieldCurveFn yieldCurveFn,
CreditCurveDataProviderFn curveDataProviderFn,
HolidaySource holidaySource,
RegionSource regionSource) {
_yieldCurveFn = ArgumentChecker.notNull(yieldCurveFn, "yieldCurveFn");
_curveDataProviderFn = ArgumentChecker.notNull(curveDataProviderFn, "curveDataProviderFn");
_holidaySource = ArgumentChecker.notNull(holidaySource, "holidaySource");
_regionSource = ArgumentChecker.notNull(regionSource, "regionSource");
}
@Override
public Result<IsdaCreditCurve> buildIsdaCompliantCreditCurve(Environment env,
CreditCurveDataKey creditCurveKey) {
Result<IsdaYieldCurve> yieldCurveResult =
_yieldCurveFn.buildIsdaCompliantCurve(env, creditCurveKey.getCurrency());
Result<CreditCurveData> creditCurveDataResult =
_curveDataProviderFn.retrieveCreditCurveData(env, creditCurveKey);
if (Result.anyFailures(creditCurveDataResult, yieldCurveResult)) {
return Result.failure(creditCurveDataResult, yieldCurveResult);
}
IsdaYieldCurve yieldCurve = yieldCurveResult.getValue();
Pair<ISDACompliantCreditCurve, List<CDSAnalytic>> curveData =
buildWithResolvedData(env,
yieldCurve.getCalibratedCurve(),
creditCurveDataResult.getValue(),
creditCurveKey);
return Result.success(IsdaCreditCurve.builder()
.calibratedCurve(curveData.getFirst())
.curveData(creditCurveDataResult.getValue())
.yieldCurve(yieldCurve)
.calibratedCds(curveData.getSecond())
.build());
}
private Pair<ISDACompliantCreditCurve, List<CDSAnalytic>> buildWithResolvedData(Environment env,
ISDACompliantYieldCurve yieldCurve,
CreditCurveData creditCurveData,
CreditCurveDataKey creditCurveKey) {
IsdaCreditCurveConvention convention = creditCurveData.getCurveConventionLink().resolve();
SortedMap<Tenor, CdsQuote> spreadData = creditCurveData.getCdsQuotes();
List<CDSAnalytic> calibrationCdsList = new ArrayList<>(spreadData.size());
List<CDSQuoteConvention> quoteList = new ArrayList<>(spreadData.size());
ExternalId regionId = convention.getRegionId();
Calendar calendar = getRegionCalendar(regionId);
CDSAnalyticFactory cdsFactory = new CDSAnalyticFactory()
.with(convention.getBusinessDayConvention())
.with(calendar)
.with(convention.getCouponInterval())
.with(convention.getStubType())
.withAccrualDCC(convention.getAccrualDayCount())
.withCashSettle(convention.getCashSettle())
.withCurveDCC(convention.getCurveDayCount())
.withPayAccOnDefault(convention.isPayAccOnDefault())
.withProtectionStart(convention.isProtectFromStartOfDay())
.withRecoveryRate(creditCurveData.getRecoveryRate())
.withStepIn(convention.getStepIn());
LocalDate valuationDate = env.getValuationDate();
for (Map.Entry<Tenor, CdsQuote> spreadEntry : spreadData.entrySet()) {
CDSAnalytic cdsAnalytic;
switch (creditCurveKey.getCdsType()) {
case INDEX:
cdsAnalytic = cdsFactory.makeCDX(valuationDate, spreadEntry.getKey().getPeriod());
break;
case SINGLE_NAME:
cdsAnalytic = cdsFactory.makeIMMCDS(valuationDate, spreadEntry.getKey().getPeriod());
break;
default:
throw new OpenGammaRuntimeException("Credit curve key with CDS type " + creditCurveKey.getCdsType() + " is " +
"invalid. Change to INDEX or SINGLE_NAME.");
}
CDSQuoteConvention quoteConvention = spreadEntry.getValue().toQuoteConvention();
calibrationCdsList.add(cdsAnalytic);
quoteList.add(quoteConvention);
}
ISDACompliantCreditCurve curve = CREDIT_CURVE_BUILDER.calibrateCreditCurve(
calibrationCdsList.toArray(new CDSAnalytic[calibrationCdsList.size()]),
quoteList.toArray(new CDSQuoteConvention[quoteList.size()]),
yieldCurve);
return ObjectsPair.of(curve, calibrationCdsList);
}
private Calendar getRegionCalendar(ExternalId regionId) {
if (regionId == null) {
return new MondayToFridayCalendar("weekday calendar");
} else {
return CalendarUtils.getCalendar(_regionSource, _holidaySource, regionId);
}
}
}