/**
* 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.time.LocalDate;
import java.time.Period;
import com.opengamma.strata.basics.date.BusinessDayConvention;
import com.opengamma.strata.basics.date.BusinessDayConventions;
import com.opengamma.strata.basics.date.DayCount;
import com.opengamma.strata.basics.date.DayCounts;
import com.opengamma.strata.basics.date.HolidayCalendar;
import com.opengamma.strata.basics.date.HolidayCalendars;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.basics.schedule.StubConvention;
import com.opengamma.strata.collect.ArgChecker;
/**
*
*/
public class CdsAnalyticFactory {
private static final int DEFAULT_STEPIN = 1;
private static final int DEFAULT_CASH_SETTLE = 3;
private static final boolean DEFAULT_PAY_ACC = true;
private static final Period DEFAULT_COUPON_INT = Period.ofMonths(3);
private static final StubConvention DEFAULT_STUB_TYPE = StubConvention.SHORT_INITIAL;
private static final boolean PROT_START = true;
private static final double DEFAULT_RR = 0.4;
private static final HolidayCalendar DEFAULT_CALENDAR = HolidayCalendars.SAT_SUN;
private static final BusinessDayConvention FOLLOWING = BusinessDayConventions.FOLLOWING;
/** Curve daycount generally fixed to Act/365 in ISDA */
private static final DayCount ACT_365 = DayCounts.ACT_365F;
private static final DayCount ACT_360 = DayCounts.ACT_360;
private final int _stepIn;
private final int _cashSettle;
private final boolean _payAccOnDefault;
private final Period _couponInterval;
private final Tenor _couponIntervalTenor;
private final StubConvention _stubType;
private final boolean _protectStart;
private final double _recoveryRate;
private final BusinessDayConvention _businessdayAdjustmentConvention;
private final HolidayCalendar _calendar;
private final DayCount _accrualDayCount;
private final DayCount _curveDayCount;
/**
* Produce CDSs with the following default values:<P>
* Step-in: T+1<br>
* Cash-Settle: T+3 working days<br>
* Pay accrual on Default: true<br>
* CouponInterval: 3M<br>
* Stub type: front-short<br>
* Protection from start of day: true<br>
* Recovery rate: 40%<br>
* Business-day Adjustment: Following<br>
* HolidayCalendar: weekend only<br>
* Accrual day count: ACT/360<br>
* Curve day count: ACT/365 (fixed)<p>
* These defaults can be overridden using the with methods
*/
public CdsAnalyticFactory() {
_stepIn = DEFAULT_STEPIN;
_cashSettle = DEFAULT_CASH_SETTLE;
_payAccOnDefault = DEFAULT_PAY_ACC;
_couponInterval = DEFAULT_COUPON_INT;
_stubType = DEFAULT_STUB_TYPE;
_protectStart = PROT_START;
_recoveryRate = DEFAULT_RR;
_businessdayAdjustmentConvention = FOLLOWING;
_calendar = DEFAULT_CALENDAR;
_accrualDayCount = ACT_360;
_curveDayCount = ACT_365;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
/**
* Produce CDSs with the following default values and a supplied recovery rate:<P>
* Step-in: T+1<br>
* Cash-Settle: T+3 working days<br>
* Pay accrual on Default: true<br>
* CouponInterval: 3M<br>
* Stub type: front-short<br>
* Protection from start of day: true<br>
* Business-day Adjustment: Following<br>
* HolidayCalendar: weekend only<br>
* Accrual day count: ACT/360<br>
* Curve day count: ACT/365 (fixed)
* @param recoveryRate The recovery rate
*/
public CdsAnalyticFactory(double recoveryRate) {
_stepIn = DEFAULT_STEPIN;
_cashSettle = DEFAULT_CASH_SETTLE;
_payAccOnDefault = DEFAULT_PAY_ACC;
_couponInterval = DEFAULT_COUPON_INT;
_stubType = DEFAULT_STUB_TYPE;
_protectStart = PROT_START;
_recoveryRate = recoveryRate;
_businessdayAdjustmentConvention = FOLLOWING;
_calendar = DEFAULT_CALENDAR;
_accrualDayCount = ACT_360;
_curveDayCount = ACT_365;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
/**
* Produce CDSs with the following default values and a supplied coupon interval:<P>
* Step-in: T+1<br>
* Cash-Settle: T+3 working days<br>
* Pay accrual on Default: true<br>
* Stub type: front-short<br>
* Protection from start of day: true<br>
* Recovery rate: 40%<br>
* Business-day Adjustment: Following<br>
* HolidayCalendar: weekend only<br>
* Accrual day count: ACT/360<br>
* Curve day count: ACT/365 (fixed)
* @param couponInterval The coupon interval
*/
public CdsAnalyticFactory(Period couponInterval) {
ArgChecker.notNull(couponInterval, "couponInterval");
_stepIn = DEFAULT_STEPIN;
_cashSettle = DEFAULT_CASH_SETTLE;
_payAccOnDefault = DEFAULT_PAY_ACC;
_couponInterval = couponInterval;
_stubType = DEFAULT_STUB_TYPE;
_protectStart = PROT_START;
_recoveryRate = DEFAULT_RR;
_businessdayAdjustmentConvention = FOLLOWING;
_calendar = DEFAULT_CALENDAR;
_accrualDayCount = ACT_360;
_curveDayCount = ACT_365;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
/**
* Produce CDSs with the following default values and a supplied recovery rate and coupon interval:<P>
* Step-in: T+1<br>
* Cash-Settle: T+3 working days<br>
* Pay accrual on Default: true<br>
* Stub type: front-short<br>
* Protection from start of day: true<br>
* Business-day Adjustment: Following<br>
* HolidayCalendar: weekend only<br>
* Accrual day count: ACT/360<br>
* Curve day count: ACT/365 (fixed)
* @param recoveryRate The recovery rate
* @param couponInterval The coupon interval
*/
public CdsAnalyticFactory(double recoveryRate, Period couponInterval) {
ArgChecker.notNull(couponInterval, "couponInterval");
_stepIn = DEFAULT_STEPIN;
_cashSettle = DEFAULT_CASH_SETTLE;
_payAccOnDefault = DEFAULT_PAY_ACC;
_couponInterval = couponInterval;
_stubType = DEFAULT_STUB_TYPE;
_protectStart = PROT_START;
_recoveryRate = recoveryRate;
_businessdayAdjustmentConvention = FOLLOWING;
_calendar = DEFAULT_CALENDAR;
_accrualDayCount = ACT_360;
_curveDayCount = ACT_365;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
/**
* Copy constructor
* @param other The factory to copy
*/
public CdsAnalyticFactory(CdsAnalyticFactory other) {
ArgChecker.notNull(other, "other");
_stepIn = other._stepIn;
_cashSettle = other._cashSettle;
_payAccOnDefault = other._payAccOnDefault;
_couponInterval = other._couponInterval;
_stubType = other._stubType;
_protectStart = other._protectStart;
_recoveryRate = other._recoveryRate;
_businessdayAdjustmentConvention = other._businessdayAdjustmentConvention;
_calendar = other._calendar;
_accrualDayCount = other._accrualDayCount;
_curveDayCount = other._curveDayCount;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
protected CdsAnalyticFactory(
int stepIn,
int cashSettle,
boolean payAccOnDefault,
Period couponInterval,
StubConvention stubType,
boolean protectStart,
double recoveryRate,
BusinessDayConvention businessdayAdjustmentConvention,
HolidayCalendar calendar,
DayCount accrualDayCount,
DayCount curveDayCount) {
_stepIn = stepIn;
_cashSettle = cashSettle;
_payAccOnDefault = payAccOnDefault;
_couponInterval = couponInterval;
_stubType = stubType;
_protectStart = protectStart;
_recoveryRate = recoveryRate;
_businessdayAdjustmentConvention = businessdayAdjustmentConvention;
_calendar = calendar;
_accrualDayCount = accrualDayCount;
_curveDayCount = curveDayCount;
_couponIntervalTenor = Tenor.of(_couponInterval);
}
//************************************************************************************************************************
// with methods - use these to override defaults
//************************************************************************************************************************
/**
* The Step-in (Protection Effective Date or sometimes just Effective Date) is usually T+1.
* This is when protection (and risk) starts in terms of the model.
* @param stepIn Zero or more days (after trade day)
* @return A new factory with the step-in days set.
*/
public CdsAnalyticFactory withStepIn(int stepIn) {
ArgChecker.notNegative(stepIn, "stepIn");
return new CdsAnalyticFactory(
stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart,
_recoveryRate, _businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Valuation or Cash-settle Date. This is the date for which the present value (PV) of
* the CDS is calculated. It is usually three working dates after the trade date.
* @param cashSettle Zero or more days (after trade day)
* @return A new factory with the cash-settle days set.
*/
public CdsAnalyticFactory withCashSettle(int cashSettle) {
return new CdsAnalyticFactory(
_stepIn, cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Is the accrued premium paid in the event of a default (default value is true)
* @param payAcc Set to true to pay accrued on default
* @return A new factory with the payAccOnDefault set
*/
public CdsAnalyticFactory withPayAccOnDefault(boolean payAcc) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, payAcc, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Set the coupon interval (default is 3M)
* @param couponInterval The coupon interval
* @return a new factory with the coupon interval set
*/
public CdsAnalyticFactory with(Period couponInterval) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Sets the stub convention.
* @param stubType The stub type
* @return a new factory with the stub-type interval set
*/
public CdsAnalyticFactory with(StubConvention stubType) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* If protectStart = true, then protections starts at the beginning of the day, otherwise it is at the end.
* @param protectionStart Protected from start of day?
* @return A new factory with protectStart set
*/
public CdsAnalyticFactory withProtectionStart(boolean protectionStart) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, protectionStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Set the recovery rate (default is 40%)
* @param recovery The recovery rate
* @return a new factory with recovery rate set
*/
public CdsAnalyticFactory withRecoveryRate(double recovery) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, recovery,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Set how adjustments for non-business are days made. Default is following.
* @param busDay business-day adjustment convention
* @return A new factory with business-day adjustment convention set
*/
public CdsAnalyticFactory with(BusinessDayConvention busDay) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
busDay, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Set the calendar. Default is weekend-only
* @param calendar HolidayCalendar defining what is a non-business day
* @return A new factory with calendar set
*/
public CdsAnalyticFactory with(HolidayCalendar calendar) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, calendar, _accrualDayCount, _curveDayCount);
}
/**
* Set the day count used for accrual calculations (i.e. premium payments). Default is ACT/360
* @param accDCC Day count used for accrual
* @return A new factory with accDCC set
*/
public CdsAnalyticFactory withAccrualDCC(DayCount accDCC) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, accDCC, _curveDayCount);
}
/**
* Set the day count used on curve
* @param curveDCC Day count used on curve (NOTE ISDA uses ACT/365 (fixed) and it is not recommended to change this)
* @return A new factory with curveDCC set
*/
public CdsAnalyticFactory withCurveDCC(DayCount curveDCC) {
return new CdsAnalyticFactory(
_stepIn, _cashSettle, _payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, curveDCC);
}
//************************************************************************************************************************
// Make CdsAnalytic
//************************************************************************************************************************
/**
* Set up an on-the-run index represented as a single name CDS (i.e. by CdsAnalytic).
* The index roll dates (when new indices are issued) are 20 Mar & Sep,
* and the index is defined to have a maturity that is its nominal tenor plus 3M on issuance,
* so a 5Y index on the 6-Feb-2014 will have a maturity of 20-Dec-2018 (5Y3M on the issue date of 20-Sep-2013).
* The accrual start date will be the previous IMM date (before the trade date), business-day adjusted.
* <b>Note</b> it payment interval is changed from the
* default of 3M, this will produce a (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenor the nominal length of the index
* @return a CDS analytic description
*/
public CdsAnalytic makeCdx(LocalDate tradeDate, Period tenor) {
ArgChecker.notNull(tradeDate, "tradeDate");
ArgChecker.notNull(tenor, "tenor");
LocalDate effectiveDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
LocalDate roll = ImmDateLogic.getNextIndexRollDate(tradeDate);
LocalDate maturity = roll.plus(tenor).minusMonths(3);
return makeCds(tradeDate, effectiveDate, maturity);
}
/**
* Set up a strip of on-the-run indexes represented as a single name CDSs (i.e. by CdsAnalytic).
* The index roll dates (when new indices are issued) are 20 Mar & Sep,
* and the index is defined to have a maturity that is its nominal tenor plus 3M on issuance,
* so a 5Y index on the 6-Feb-2014 will have a maturity of
* 20-Dec-2018 (5Y3M on the issue date of 20-Sep-2013).
* The accrual start date will be the previous IMM date (before the trade date), business-day adjusted.
* <b>Note</b> it payment interval is changed from the
* default of 3M, this will produce a (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenors the nominal lengths of the indexes
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeCdx(LocalDate tradeDate, Period[] tenors) {
ArgChecker.notNull(tradeDate, "tradeDate");
ArgChecker.noNulls(tenors, "tenors");
LocalDate effectiveDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
LocalDate mid = ImmDateLogic.getNextIndexRollDate(tradeDate).minusMonths(3);
LocalDate[] maturities = ImmDateLogic.getIMMDateSet(mid, tenors);
return makeCds(tradeDate, effectiveDate, maturities);
}
//-------------------------------------------------------------------------
/**
* Make a CDS with a maturity date the given period on from the next IMM date after the trade-date.
* The accrual start date will be the previous IMM date (before the trade date), business-day adjusted.
* <b>Note</b> it payment interval is changed from the
* default of 3M, this will produce a (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenor the tenor (length) of the CDS
* @return a CDS analytic description
*/
public CdsAnalytic makeImmCds(LocalDate tradeDate, Period tenor) {
return makeImmCds(tradeDate, tenor, true);
}
/**
* Make a CDS with a maturity date the given period on from the next IMM date after the trade-date.
* The accrual start date will be the previous IMM date (before the trade date).
* <b>Note</b> it payment interval is changed from the
* default of 3M, this will produce a (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenor the tenor (length) of the CDS
* @param makeEffBusDay is the accrual start day business-day adjusted.
* @return a CDS analytic description
*/
public CdsAnalytic makeImmCds(LocalDate tradeDate, Period tenor, boolean makeEffBusDay) {
ArgChecker.notNull(tradeDate, "tradeDate");
ArgChecker.notNull(tenor, "tenor");
LocalDate effectiveDate = makeEffBusDay ?
_businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar) :
ImmDateLogic.getPrevIMMDate(tradeDate);
LocalDate nextIMM = ImmDateLogic.getNextIMMDate(tradeDate);
LocalDate maturity = nextIMM.plus(tenor);
return makeCds(tradeDate, effectiveDate, maturity);
}
/**
* Make a set of CDSs with a common trade date and maturities dates the given periods after the
* next IMM date (after the trade-date).
* The accrual start date will be the previous IMM date (before the trade date), business-day adjusted.
* <b>Note</b> it payment interval is changed from the default of 3M, this will produce a
* (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenors the tenors (lengths) of the CDSs
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeImmCds(LocalDate tradeDate, Period[] tenors) {
return makeImmCds(tradeDate, tenors, true);
}
/**
* Make a set of CDSs with a common trade date and maturities dates the given periods after
* the next IMM date (after the trade-date).
* The accrual start date will be the previous IMM date (before the trade date).
* <b>Note</b> it payment interval is changed from the default of 3M, this will produce a
* (possibly incorrect) non-standard first coupon.
*
* @param tradeDate the trade date
* @param tenors the tenors (lengths) of the CDSs
* @param makeEffBusDay is the accrual start day business-day adjusted.
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeImmCds(LocalDate tradeDate, Period[] tenors, boolean makeEffBusDay) {
LocalDate effectiveDate = makeEffBusDay ?
_businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar) :
ImmDateLogic.getPrevIMMDate(tradeDate);
return makeImmCds(tradeDate, effectiveDate, tenors);
}
/**
* Make a set of CDSs with a common trade date and maturities dates the given periods after
* the next IMM date (after the trade-date).
*
* @param tradeDate the trade date
* @param accStartDate this is when the CDS nominally starts in terms of premium payments.
* For a standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
* @param tenors the tenors (lengths) of the CDSs
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeImmCds(LocalDate tradeDate, LocalDate accStartDate, Period[] tenors) {
ArgChecker.notNull(tradeDate, "tradeDate");
ArgChecker.notNull(accStartDate, "effectiveDate");
ArgChecker.noNulls(tenors, "tenors");
LocalDate nextIMM = ImmDateLogic.getNextIMMDate(tradeDate);
LocalDate[] maturities = ImmDateLogic.getIMMDateSet(nextIMM, tenors);
return makeCds(tradeDate, accStartDate, maturities);
}
//-------------------------------------------------------------------------
/**
* Make a CDS by specifying key dates.
*
* @param tradeDate the trade date
* @param accStartDate this is when the CDS nominally starts in terms of premium payments.
* For a standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
* @param maturity the maturity. For a standard CDS this is an IMM date
* @return a CDS analytic description
*/
public CdsAnalytic makeCds(LocalDate tradeDate, LocalDate accStartDate, LocalDate maturity) {
LocalDate stepinDate = tradeDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(tradeDate, _cashSettle, _calendar);
return new CdsAnalytic(tradeDate, stepinDate, valueDate, accStartDate, maturity,
_payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate, _businessdayAdjustmentConvention,
_calendar, _accrualDayCount, _curveDayCount);
}
/**
* Make a CDS by specifying all dates.
*
* @param tradeDate the trade date
* @param stepinDate (aka Protection Effective sate or assignment date). Date when party assumes ownership.
* This is usually T+1. This is when protection (and risk) starts in terms of the model.
* Note, this is sometimes just called the Effective Date, however this can cause confusion
* with the legal effective date which is T-60 or T-90.
* @param cashSettlementDate The valuation date. The date that values are PVed to.
* Is is normally today + 3 business days. Aka cash-settle date.
* @param accStartDate this is when the CDS nominally starts in terms of premium payments.
* For a standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
* @param maturity (aka end date) This is when the contract expires and protection ends - any
* default after this date does not trigger a payment. (the protection ends at end of day)
* @return a CDS analytic description
*/
public CdsAnalytic makeCds(
LocalDate tradeDate,
LocalDate stepinDate,
LocalDate cashSettlementDate,
LocalDate accStartDate,
LocalDate maturity) {
return new CdsAnalytic(tradeDate, stepinDate, cashSettlementDate, accStartDate, maturity,
_payAccOnDefault, _couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
/**
* Make a set of CDS by specifying key dates.
*
* @param tradeDate the trade date
* @param accStartDate this is when the CDS nominally starts in terms of premium payments.
* For a standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
* @param maturities The maturities of the CDSs. For a standard CDS these are IMM dates
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeCds(LocalDate tradeDate, LocalDate accStartDate, LocalDate[] maturities) {
LocalDate stepinDate = tradeDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(tradeDate, _cashSettle, _calendar);
return makeCds(tradeDate, stepinDate, valueDate, accStartDate, maturities);
}
/**
* Make a set of CDS by specifying all dates.
*
* @param tradeDate the trade date
* @param stepinDate (aka Protection Effective sate or assignment date). Date when party assumes ownership.
* This is usually T+1. This is when protection (and risk) starts in terms of the model.
* Note, this is sometimes just called the Effective Date, however this can cause
* confusion with the legal effective date which is T-60 or T-90.
* @param valueDate the valuation date. The date that values are PVed to.
* Is is normally today + 3 business days. Aka cash-settle date.
* @param accStartDate this is when the CDS nominally starts in terms of premium payments. i.e. the number
* of days in the first period (and thus the amount of the first premium payment) is counted from this date.
* @param maturities The maturities of the CDSs. For a standard CDS these are IMM dates
* @return an array of CDS analytic descriptions
*/
public CdsAnalytic[] makeCds(
LocalDate tradeDate,
LocalDate stepinDate,
LocalDate valueDate,
LocalDate accStartDate,
LocalDate[] maturities) {
ArgChecker.noNulls(maturities, "maturities");
int n = maturities.length;
CdsAnalytic[] cds = new CdsAnalytic[n];
for (int i = 0; i < n; i++) {
cds[i] = new CdsAnalytic(tradeDate, stepinDate, valueDate, accStartDate, maturities[i], _payAccOnDefault,
_couponInterval, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, _calendar, _accrualDayCount, _curveDayCount);
}
return cds;
}
//************************************************************************************************************************
// Make forward starting CDS
//************************************************************************************************************************
/**
* A forward starting CDS starts on some date after today (the trade date).
* The stepin date and cash settlement date are taken from the forward start date
* (1 day and 3 working days by default).
*
* @param tradeDate the trade date (i.e. today)
* @param forwardStartDate the forward start date
* @param maturity the maturity of the CDS
* @return a CDS analytic description for a forward starting CDS
*/
public CdsAnalytic makeForwardStartingCds(LocalDate tradeDate, LocalDate forwardStartDate, LocalDate maturity) {
ArgChecker.isFalse(
forwardStartDate.isBefore(tradeDate),
"forwardStartDate of {} is before trade date of {}", forwardStartDate, tradeDate);
LocalDate stepinDate = forwardStartDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(forwardStartDate, _cashSettle, _calendar);
LocalDate accStartDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(forwardStartDate), _calendar);
return makeCds(tradeDate, stepinDate, valueDate, accStartDate, maturity);
}
/**
* A forward starting CDS starts on some date after today (the trade date).
* The accrual start must be specified (would normally use this for T+1 accrual atart).
* The stepin date and cash settlement date are taken from the forward start date
* (1 day and 3 working days by default).
*
* @param tradeDate the trade date (i.e. today)
* @param forwardStartDate the forward start date
* @param accStartDate the accrual start date
* @param maturity the maturity of the CDS
* @return a CDS analytic description for a forward starting CDS
*/
public CdsAnalytic makeForwardStartingCds(
LocalDate tradeDate,
LocalDate forwardStartDate,
LocalDate accStartDate,
LocalDate maturity) {
ArgChecker.isFalse(
forwardStartDate.isBefore(tradeDate),
"forwardStartDate of {} is before trade date of {}", forwardStartDate, tradeDate);
LocalDate stepinDate = forwardStartDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(forwardStartDate, _cashSettle, _calendar);
return makeCds(tradeDate, stepinDate, valueDate, accStartDate, maturity);
}
/** A forward starting CDS starts on some date after today (the trade date).
* The stepin date and cash settlement date are taken from the forward start date
* (1 day and 3 working days by default). The period is from the next IMM date after the
* forward-start-date, so for a trade-date of 13-Feb-2014, a forward-start-date
* of 25-Mar-2014 and a tenor of 1Y, the maturity will be 20-Jun-2015.
*
* @param tradeDate the trade date (i.e. today)
* @param forwardStartDate the forward start date
* @param tenor the tenor (length) of the CDS at the forwardStartDate
* @return a CDS analytic description for a forward starting CDS
*/
public CdsAnalytic makeForwardStartingImmCds(LocalDate tradeDate, LocalDate forwardStartDate, Period tenor) {
LocalDate nextIMM = ImmDateLogic.getNextIMMDate(forwardStartDate);
LocalDate maturity = nextIMM.plus(tenor);
return makeForwardStartingCds(tradeDate, forwardStartDate, maturity);
}
/**
* /** A forward starting index starts on some date after today (the trade date).
* The stepin date and cash settlement date are taken from the forward start date
* (1 day and 3 working days by default).
* The maturity (of the index) is taken from the forward-start-date.
* The index roll dates (when new indices are issued) are 20 Mar & Sep,
* and the index is defined to have a maturity that is its nominal tenor plus 3M on issuance,
* so a 5Y index on the 6-Feb-2014 will have a maturity of
* 20-Dec-2018 (5Y3M on the issue date of 20-Sep-2013). However for a trade-date of 6-Feb-2014, a forward-start-date
* of 25-Mar-2014 and a tenor of 5Y, the maturity will be 20-Jun-2019.
*
* @param tradeDate the trade date (i.e. today)
* @param forwardStartDate the forward start date
* @param tenor the tenor (nominal length) of the index at the forwardStartDate
* @return a CDS analytic description for a forward starting index
*/
public CdsAnalytic makeForwardStartingCdx(LocalDate tradeDate, LocalDate forwardStartDate, Period tenor) {
LocalDate roll = ImmDateLogic.getNextIndexRollDate(forwardStartDate);
LocalDate maturity = roll.plus(tenor).minusMonths(3);
return makeForwardStartingCds(tradeDate, forwardStartDate, maturity);
}
//************************************************************************************************************************
// Make MultiCdsAnalytic
//************************************************************************************************************************
/**
* Make a CDS represented as a MultiCdsAnalytic instance. Note, this is mainly for testing,
* since if you want only a single CDS should use a method that returns a {@link CdsAnalytic}.
*
* @param tradeDate the trade date
* @param maturityReferanceDate a reference date that maturities are measured from.
* For standard CDSSs, this is the next IMM date after
* the trade date, so the actually maturities will be some fixed periods after this.
* @param termMatIndex the maturities are fixed integer multiples of the payment interval, so 2Y tenor with a 3M
* payment interval, this would be 8
* @return a CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiCds(LocalDate tradeDate, LocalDate maturityReferanceDate, int termMatIndex) {
int[] maturityIndexes = new int[termMatIndex + 1];
for (int i = 0; i <= termMatIndex; i++) {
maturityIndexes[i] = i;
}
LocalDate accStartDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
return makeMultiCds(tradeDate, accStartDate, maturityReferanceDate, maturityIndexes);
}
/**
* Make a set of CDS represented as a MultiCdsAnalytic instance.
*
* @param tradeDate the trade date
* @param accStartDate This is when the CDS nominally starts in terms of the accrual calculation for premium payments.
* For a standard CDS this is the previous IMM date, and for a `legacy' CDS it is T+1
* @param maturityReferanceDate A reference date that maturities are measured from.
* For standard CDSSs, this is the next IMM date after the trade date, so the actually maturities
* will be some fixed periods after this.
* @param maturityIndexes the maturities are fixed integer multiples of the payment interval,
* so for 6M, 1Y and 2Y tenors with a 3M payment interval, would require 2, 4, and 8 as the indices
* @return Make a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiCds(
LocalDate tradeDate,
LocalDate accStartDate,
LocalDate maturityReferanceDate,
int[] maturityIndexes) {
LocalDate stepinDate = tradeDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(tradeDate, _cashSettle, _calendar);
return makeMultiCds(tradeDate, stepinDate, valueDate, accStartDate, maturityReferanceDate, maturityIndexes);
}
/**
* Make a set of CDS represented as a MultiCdsAnalytic instance.
*
* @param tradeDate the trade date
* @param stepinDate (aka Protection Effective sate or assignment date). Date when party assumes ownership.
* This is usually T+1. This is when protection (and risk) starts in terms of the model.
* Note, this is sometimes just called the Effective Date, however this can cause
* confusion with the legal effective date which is T-60 or T-90.
* @param cashSettlementDate the valuation date. The date that values are PVed to.
* Is is normally today + 3 business days. Aka cash-settle date.
* @param accStartDate this is when the CDS nominally starts in terms of premium payments. i.e. the number
* of days in the first period (and thus the amount of the first premium payment) is counted from this date.
* @param maturityReferanceDate a reference date that maturities are measured from.
* For standard CDSSs, this is the next IMM date after
* the trade date, so the actually maturities will be some fixed periods after this.
* @param maturityIndexes the maturities are fixed integer multiples of the payment interval,
* so for 6M, 1Y and 2Y tenors with a 3M payment interval, would require 2, 4, and 8 as the indices
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiCds(
LocalDate tradeDate,
LocalDate stepinDate,
LocalDate cashSettlementDate,
LocalDate accStartDate,
LocalDate maturityReferanceDate,
int[] maturityIndexes) {
return new MultiCdsAnalytic(
tradeDate, stepinDate, cashSettlementDate, accStartDate, maturityReferanceDate,
maturityIndexes, _payAccOnDefault, _couponIntervalTenor, _stubType, _protectStart,
_recoveryRate, _businessdayAdjustmentConvention, DEFAULT_CALENDAR, _accrualDayCount, _curveDayCount);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
*
* @param tradeDate the trade date
* @param tenors the tenors (length) of the CDS
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, Period[] tenors) {
LocalDate accStartDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
return makeMultiImmCds(tradeDate, accStartDate, tenors);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
*
* @param tradeDate the trade date
* @param accStartDate the accrual start date
* @param tenors the tenors (length) of the CDS
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, LocalDate accStartDate, Period[] tenors) {
ArgChecker.noNulls(tenors, "tenors");
int n = tenors.length;
int immNMonths = (int) DEFAULT_COUPON_INT.toTotalMonths();
int[] matIndices = new int[n];
for (int i = 0; i < n; i++) {
int months = (int) tenors[i].toTotalMonths();
if (months % immNMonths != 0) {
throw new IllegalArgumentException("tenors index " + i + " is not a multiple of " + DEFAULT_COUPON_INT.toString());
}
matIndices[i] = months / immNMonths;
}
return makeMultiImmCds(tradeDate, accStartDate, matIndices);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
* The first CDS with have a tenor of firstTenor, while the last CDS will have a tenor of lastTenor;
* the remaining CDS will consist of all the (multiple of 3 month) tenors between the first and
* last tenor, e.g. if firstTenor = 6M and lastTenor = 5Y, there will be a total
* of 22 CDS with tenors of 6M, 9M, 1Y,....4Y9M, 5Y.
*
* @param tradeDate the trade date
* @param firstTenor the first tenor
* @param lastTenor the last tenor
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, Period firstTenor, Period lastTenor) {
ArgChecker.notNull(firstTenor, "firstTenor");
ArgChecker.notNull(lastTenor, "lastTenor");
int immNMonths = (int) DEFAULT_COUPON_INT.toTotalMonths();
int m1 = (int) firstTenor.toTotalMonths();
int m2 = (int) lastTenor.toTotalMonths();
if (m1 % immNMonths != 0 || m2 % immNMonths != 0) {
throw new IllegalArgumentException("tenors is not a multiple of " + DEFAULT_COUPON_INT.toString());
}
int firstIndex = m1 / immNMonths;
int lastIndex = m2 / immNMonths;
return makeMultiImmCds(tradeDate, firstIndex, lastIndex);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
* The maturities of the CDS are measured from the next IMM date (after the trade date), and
* the first and last tenors are the firstIndex and lastIndex multiplied by the coupon interval
* (3 months), which the remaining tenors being everything in between.
*
* @param tradeDate the trade date
* @param firstIndex the First index
* @param lastIndex the last index
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, int firstIndex, int lastIndex) {
ArgChecker.isTrue(lastIndex > firstIndex, "Require lastIndex>firstIndex");
ArgChecker.isTrue(firstIndex >= 0, "Require positive indices");
int n = lastIndex - firstIndex + 1;
int[] matIndices = new int[n];
for (int i = 0; i < n; i++) {
matIndices[i] = i + firstIndex;
}
return makeMultiImmCds(tradeDate, matIndices);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
* The maturities of the CDS are measured from the next IMM date (after the trade date), and
* the tenors are the given matIndices multiplied by the coupon interval (3 months).
*
* @param tradeDate the trade date
* @param matIndices the CDS tenors are these multiplied by the coupon interval (3 months)
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, int[] matIndices) {
LocalDate accStartDate = _businessdayAdjustmentConvention.adjust(ImmDateLogic.getPrevIMMDate(tradeDate), _calendar);
return makeMultiImmCds(tradeDate, accStartDate, matIndices);
}
/**
* Make a set of standard CDS represented as a MultiCdsAnalytic instance.
* The maturities of the CDS are measured from the next IMM date (after the trade date), and
* the tenors are the given matIndices multiplied by the coupon interval (3 months).
*
* @param tradeDate the trade date
* @param accStartDate the accrual start date
* @param matIndices the CDS tenors are these multiplied by the coupon interval (3 months)
* @return a set of CDS represented as a MultiCdsAnalytic
*/
public MultiCdsAnalytic makeMultiImmCds(LocalDate tradeDate, LocalDate accStartDate, int[] matIndices) {
if (!_couponInterval.equals(DEFAULT_COUPON_INT)) {
throw new IllegalArgumentException(
"coupon interval must be 3M for this method. However it is set to " + _couponInterval.toString());
}
ArgChecker.notNull(tradeDate, "tradeDate");
ArgChecker.notEmpty(matIndices, "matIndicies");
LocalDate nextIMM = ImmDateLogic.getNextIMMDate(tradeDate);
LocalDate stepinDate = tradeDate.plusDays(_stepIn);
LocalDate valueDate = addWorkDays(tradeDate, _cashSettle, _calendar);
return new MultiCdsAnalytic(
tradeDate, stepinDate, valueDate, accStartDate, nextIMM, matIndices, _payAccOnDefault,
_couponIntervalTenor, _stubType, _protectStart, _recoveryRate,
_businessdayAdjustmentConvention, DEFAULT_CALENDAR, _accrualDayCount, _curveDayCount);
}
/**
* Add a certain number of working days (defined by the holidayCalendar) to a date.
*
* @param startDate the start date
* @param workingDaysToAdd working days to add
* @param calendar the calendar of holidays
* @return a working day
*/
private static LocalDate addWorkDays(LocalDate startDate, int workingDaysToAdd, HolidayCalendar calendar) {
ArgChecker.notNull(startDate, "startDate");
ArgChecker.notNull(calendar, "calendar");
int daysLeft = workingDaysToAdd;
LocalDate temp = startDate;
while (daysLeft > 0) {
temp = temp.plusDays(1);
if (calendar.isBusinessDay(temp)) {
daysLeft--;
}
}
return temp;
}
}