/** * Bootstrapper the credit curve from a single CDS, by making it have zero clean price. * Obviously the resulting credit (hazard) curve will be flat. * * @param tradeDate The 'current' date * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka assignment date or effective date. * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3 business days. Aka cash-settle date. * @param startDate The protection start date. If protectStart = true, then protections starts at the beginning of the day, otherwise it * is at the end. * @param endDate The maturity (or end of protection) of the CDS * @param fractionalParSpread - the (fractional) coupon that makes the CDS worth par (i.e. zero clean price) * @param payAccOnDefault Is the accrued premium paid in the event of a default * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months). * @param stubType the stub convention * @param protectStart Does protection start at the beginning of the day * @param yieldCurve Curve from which payments are discounted * @param recoveryRate the recovery rate * @return The credit curve */ public PiecewiseconstantHazardRate calibrateCreditCurve( DateTime tradeDate, DateTime stepinDate, DateTime valueDate, DateTime startDate, DateTime endDate, double fractionalParSpread, Boolean payAccOnDefault, int tenor, StubConvention stubType, Boolean protectStart, YieldTermStructure yieldCurve, double recoveryRate) { return(calibrateCreditCurve( tradeDate, stepinDate, valueDate, startDate, new DateTime[] { endDate }, new double[] { fractionalParSpread }, payAccOnDefault, tenor, stubType, protectStart, yieldCurve, recoveryRate)); }
/** * Bootstrapper the credit curve, by making each market CDS in turn have zero clean price. * * @param tradeDate The 'current' date * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka assignment date or effective date. * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3 business days. Aka cash-settle date. * @param startDate The protection start date. If protectStart = true, then protections starts at the beginning of the day, otherwise it * is at the end. * @param endDates The maturities (or end of protection) of each of the CDSs - must be ascending * @param fractionalParSpreads - the (fractional) coupon that makes each CDS worth par (i.e. zero clean price) * @param payAccOnDefault Is the accrued premium paid in the event of a default * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months). * @param stubType the stub convention * @param protectStart Does protection start at the beginning of the day * @param yieldCurve Curve from which payments are discounted * @param recoveryRate the recovery rate * @return The credit curve */ public PiecewiseconstantHazardRate calibrateCreditCurve( DateTime tradeDate, DateTime stepinDate, DateTime valueDate, DateTime startDate, DateTime[] endDates, double[] fractionalParSpreads, Boolean payAccOnDefault, int tenor, StubConvention stubType, Boolean protectStart, YieldTermStructure yieldCurve, double recoveryRate) { int n = endDates.Length; CDS[] cds = new CDS[n]; for (int i = 0; i < n; i++) { cds[i] = new CDS(0.01, 100000, endDates[i], CdsAnalyticFactory.getNextIMMDate(stepinDate), tradeDate, CdsAnalyticFactory.getPrevIMMDate(stepinDate), "Quarterly", recoveryRate, 3, 3); } return(calibrateCreditCurve(cds, fractionalParSpreads, yieldCurve)); }
//------------------------------------------------------------------------- // accrual schedule private static PeriodicSchedule parseAccrualSchedule(CsvRow row, string leg) { PeriodicSchedule.Builder builder = PeriodicSchedule.builder(); // basics builder.startDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, START_DATE_FIELD))); builder.endDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, END_DATE_FIELD))); builder.frequency(Frequency.parse(getValue(row, leg, FREQUENCY_FIELD))); // adjustments BusinessDayAdjustment dateAdj = parseBusinessDayAdjustment(row, leg, DATE_ADJ_CNV_FIELD, DATE_ADJ_CAL_FIELD).orElse(BusinessDayAdjustment.NONE); Optional <BusinessDayAdjustment> startDateAdj = parseBusinessDayAdjustment(row, leg, START_DATE_CNV_FIELD, START_DATE_CAL_FIELD); Optional <BusinessDayAdjustment> endDateAdj = parseBusinessDayAdjustment(row, leg, END_DATE_CNV_FIELD, END_DATE_CAL_FIELD); builder.businessDayAdjustment(dateAdj); if (startDateAdj.Present && !startDateAdj.get().Equals(dateAdj)) { builder.startDateBusinessDayAdjustment(startDateAdj.get()); } if (endDateAdj.Present && !endDateAdj.get().Equals(dateAdj)) { builder.endDateBusinessDayAdjustment(endDateAdj.get()); } // optionals builder.stubConvention(findValueWithFallback(row, leg, STUB_CONVENTION_FIELD).map(s => StubConvention.of(s)).orElse(StubConvention.SMART_INITIAL)); findValue(row, leg, ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s)).ifPresent(v => builder.rollConvention(v)); findValue(row, leg, FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.firstRegularStartDate(v)); findValue(row, leg, LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.lastRegularEndDate(v)); parseAdjustableDate(row, leg, OVERRIDE_START_DATE_FIELD, OVERRIDE_START_DATE_CNV_FIELD, OVERRIDE_START_DATE_CAL_FIELD).ifPresent(d => builder.overrideStartDate(d)); return(builder.build()); }
//------------------------------------------------------------------------- public override void start(Stage primaryStage) { LocalDate today = LocalDate.now(ZoneId.systemDefault()); // setup GUI elements Label startLbl = new Label("Start date:"); DatePicker startInp = new DatePicker(today); startLbl.LabelFor = startInp; startInp.ShowWeekNumbers = false; Label endLbl = new Label("End date:"); DatePicker endInp = new DatePicker(today.plusYears(1)); endLbl.LabelFor = endInp; endInp.ShowWeekNumbers = false; Label freqLbl = new Label("Frequency:"); ChoiceBox <Frequency> freqInp = new ChoiceBox <Frequency>(FXCollections.observableArrayList(Frequency.P1M, Frequency.P2M, Frequency.P3M, Frequency.P4M, Frequency.P6M, Frequency.P12M)); freqLbl.LabelFor = freqInp; freqInp.Value = Frequency.P3M; Label stubLbl = new Label("Stub:"); ObservableList <StubConvention> stubOptions = FXCollections.observableArrayList(StubConvention.values()); stubOptions.add(0, null); ChoiceBox <StubConvention> stubInp = new ChoiceBox <StubConvention>(stubOptions); stubLbl.LabelFor = stubInp; stubInp.Value = StubConvention.SMART_INITIAL; Label rollLbl = new Label("Roll:"); ChoiceBox <RollConvention> rollInp = new ChoiceBox <RollConvention>(FXCollections.observableArrayList(null, RollConventions.NONE, RollConventions.EOM, RollConventions.IMM, RollConventions.IMMAUD, RollConventions.IMMNZD, RollConventions.SFE)); rollLbl.LabelFor = rollInp; rollInp.Value = RollConventions.NONE; Label bdcLbl = new Label("Adjust:"); ChoiceBox <BusinessDayConvention> bdcInp = new ChoiceBox <BusinessDayConvention>(FXCollections.observableArrayList(BusinessDayConventions.NO_ADJUST, BusinessDayConventions.FOLLOWING, BusinessDayConventions.MODIFIED_FOLLOWING, BusinessDayConventions.PRECEDING, BusinessDayConventions.MODIFIED_PRECEDING, BusinessDayConventions.MODIFIED_FOLLOWING_BI_MONTHLY, BusinessDayConventions.NEAREST)); bdcLbl.LabelFor = bdcInp; bdcInp.Value = BusinessDayConventions.MODIFIED_FOLLOWING; Label holidayLbl = new Label("Holidays:"); ChoiceBox <HolidayCalendarId> holidayInp = new ChoiceBox <HolidayCalendarId>(FXCollections.observableArrayList(HolidayCalendarIds.CHZU, HolidayCalendarIds.GBLO, HolidayCalendarIds.EUTA, HolidayCalendarIds.FRPA, HolidayCalendarIds.JPTO, HolidayCalendarIds.NYFD, HolidayCalendarIds.NYSE, HolidayCalendarIds.USNY, HolidayCalendarIds.USGS, HolidayCalendarIds.NO_HOLIDAYS, HolidayCalendarIds.SAT_SUN)); holidayLbl.LabelFor = holidayInp; holidayInp.Value = HolidayCalendarIds.GBLO; TableView <SchedulePeriod> resultGrid = new TableView <SchedulePeriod>(); TableColumn <SchedulePeriod, LocalDate> unadjustedCol = new TableColumn <SchedulePeriod, LocalDate>("Unadjusted dates"); TableColumn <SchedulePeriod, LocalDate> adjustedCol = new TableColumn <SchedulePeriod, LocalDate>("Adjusted dates"); TableColumn <SchedulePeriod, LocalDate> resultUnadjStartCol = new TableColumn <SchedulePeriod, LocalDate>("Start"); resultUnadjStartCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().unadjustedStartDate()); TableColumn <SchedulePeriod, LocalDate> resultUnadjEndCol = new TableColumn <SchedulePeriod, LocalDate>("End"); resultUnadjEndCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().unadjustedEndDate()); TableColumn <SchedulePeriod, Period> resultUnadjLenCol = new TableColumn <SchedulePeriod, Period>("Length"); resultUnadjLenCol.CellValueFactory = ReadOnlyCallback.of(sch => Period.between(sch.UnadjustedStartDate, sch.UnadjustedEndDate)); TableColumn <SchedulePeriod, LocalDate> resultStartCol = new TableColumn <SchedulePeriod, LocalDate>("Start"); resultStartCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().startDate()); TableColumn <SchedulePeriod, LocalDate> resultEndCol = new TableColumn <SchedulePeriod, LocalDate>("End"); resultEndCol.CellValueFactory = new TableCallback <>(SchedulePeriod.meta().endDate()); TableColumn <SchedulePeriod, Period> resultLenCol = new TableColumn <SchedulePeriod, Period>("Length"); resultLenCol.CellValueFactory = ReadOnlyCallback.of(sch => sch.length()); unadjustedCol.Columns.add(resultUnadjStartCol); unadjustedCol.Columns.add(resultUnadjEndCol); unadjustedCol.Columns.add(resultUnadjLenCol); adjustedCol.Columns.add(resultStartCol); adjustedCol.Columns.add(resultEndCol); adjustedCol.Columns.add(resultLenCol); resultGrid.Columns.add(unadjustedCol); resultGrid.Columns.add(adjustedCol); resultGrid.Placeholder = new Label("Schedule not yet generated"); unadjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2)); adjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2)); resultUnadjStartCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3)); resultUnadjEndCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3)); resultUnadjLenCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(3)); resultStartCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3)); resultEndCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3)); resultLenCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(3)); // setup generation button // this uses the GUI thread which is not the best idea Button btn = new Button(); btn.Text = "Generate"; btn.OnAction = @event => { LocalDate start = startInp.Value; LocalDate end = endInp.Value; Frequency freq = freqInp.Value; StubConvention stub = stubInp.Value; RollConvention roll = rollInp.Value; HolidayCalendarId holCal = holidayInp.Value; BusinessDayConvention bdc = bdcInp.Value; BusinessDayAdjustment bda = BusinessDayAdjustment.of(bdc, holCal); PeriodicSchedule defn = PeriodicSchedule.builder().startDate(start).endDate(end).frequency(freq).businessDayAdjustment(bda).stubConvention(stub).rollConvention(roll).build(); try { Schedule schedule = defn.createSchedule(REF_DATA); Console.WriteLine(schedule); resultGrid.Items = FXCollections.observableArrayList(schedule.Periods); } catch (ScheduleException ex) { resultGrid.Items = FXCollections.emptyObservableList(); resultGrid.Placeholder = new Label(ex.Message); Console.WriteLine(ex.Message); } }; // layout the components GridPane gp = new GridPane(); gp.Hgap = 10; gp.Vgap = 10; gp.Padding = new Insets(0, 10, 0, 10); gp.add(startLbl, 1, 1); gp.add(startInp, 2, 1); gp.add(endLbl, 1, 2); gp.add(endInp, 2, 2); gp.add(freqLbl, 1, 3); gp.add(freqInp, 2, 3); gp.add(bdcLbl, 3, 1); gp.add(bdcInp, 4, 1); gp.add(holidayLbl, 3, 2); gp.add(holidayInp, 4, 2); gp.add(stubLbl, 3, 3); gp.add(stubInp, 4, 3); gp.add(rollLbl, 3, 4); gp.add(rollInp, 4, 4); gp.add(btn, 3, 5, 2, 1); gp.add(resultGrid, 1, 7, 4, 1); BorderPane bp = new BorderPane(gp); Scene scene = new Scene(bp, 600, 600); // launch primaryStage.Title = "Periodic schedule generator"; primaryStage.Scene = scene; primaryStage.show(); }
/// <summary> /// This mimics JpmcdsDateListMakeRegular. Produces a set of ascending dates by following the rules:<para> /// If the stub is at the front end, we role backwards from the endDate at an integer multiple of the specified step size (e.g. 3M), /// adding these date until we pass the startDate(this date is not added). If the stub type is short, the startDate is added (as the first date), hence the first period /// will be less than (or equal to) the remaining periods. If the stub type is long, the startDate is also added, but the date immediately /// </para> /// after that is removed, so the first period is longer than the remaining.<para> /// If the stub is at the back end, we role forward from the startDate at an integer multiple of the specified step size (e.g. 3M), /// adding these date until we pass the endDate(this date is not added). If the stub type is short, the endDate is added (as the last date), hence the last period /// will be less than (or equal to) the other periods. If the stub type is long, the endDate is also added, but the date immediately /// before that is removed, so the last period is longer than the others. /// /// </para> /// </summary> /// <param name="startDate"> The start date - this will be the first entry in the list </param> /// <param name="endDate"> The end date - this will be the last entry in the list </param> /// <param name="step"> the step period (e.g. 3M - will produce dates every 3 months, with adjustments at the beginning or end based on stub type) </param> /// <param name="stubType"> the stub convention </param> /// <returns> an array of DateTime </returns> public static DateTime[] getUnadjustedDates(DateTime startDate, DateTime endDate, int step, StubConvention stubType) { if (DateTime.Compare(startDate, endDate) == 0) { // this can only happen if protectionStart == true DateTime[] tempDates = new DateTime[2]; tempDates[0] = startDate; tempDates[1] = endDate; return(tempDates); } OMLib.Conventions.DayCount.ActualActual dc = new OMLib.Conventions.DayCount.ActualActual(OMLib.Conventions.DayCount.ActualActual.Convention.ISDA); double days = (double)365.0 * (step / 12.0); int nApprox = 3 + (int)(dc.DayCount(startDate, endDate) / days); IList <DateTime> dates = new List <DateTime>(nApprox); // stub at front end, so start at endDate and work backwards if (stubType == StubConvention.SHORT_FINAL || stubType == StubConvention.LONG_FINAL || stubType == StubConvention.NONE) { int intervals = 0; DateTime tDate = endDate; while (DateTime.Compare(tDate, startDate) > 0) { dates.Add(tDate); int tStep = step * (++intervals); // this mimics ISDA c code, rather than true market convention tDate = endDate.AddMonths(tStep); } int n = dates.Count; if (tDate.Equals(startDate) || n == 1 || stubType == StubConvention.SHORT_INITIAL) { dates.Add(startDate); } else { // long front stub - remove the last date entry in the list and replace it with startDate dates.RemoveAt(n - 1); dates.Add(startDate); } int m = dates.Count; DateTime[] res = new DateTime[m]; // want to output in ascending chronological order, so need to reverse the list int j = m - 1; for (int i = 0; i < m; i++, j--) { res[j] = dates[i]; } return(res); // stub at back end, so start at startDate and work forward } else { int intervals = 0; DateTime tDate = startDate; while (DateTime.Compare(tDate, endDate) < 0) { dates.Add(tDate); int tStep = step * (++intervals); // this mimics ISDA c code, rather than true market convention tDate = startDate.AddMonths(tStep); } int n = dates.Count; if (tDate.Equals(endDate) || n == 1 || stubType == StubConvention.SHORT_FINAL) { dates.Add(endDate); } else { // long back stub - remove the last date entry in the list and replace it with endDate dates.RemoveAt(n - 1); dates.Add(endDate); } DateTime[] res = new DateTime[dates.Count]; res = dates.ToArray(); return(res); } }
/// <summary> /// Mimics JpmcdsCdsFeeLegMake </summary> /// <param name="startDate"> The protection start date </param> /// <param name="endDate"> The protection end date </param> /// <param name="step"> The period or frequency at which payments are made (e.g. every three months) </param> /// <param name="stubType"> The stub convention </param> /// <param name="businessdayAdjustmentConvention"> options are 'following' or 'proceeding' </param> /// <param name="calandar"> A holiday calendar </param> /// <param name="protectionStart"> If true, protection starts are the beginning rather than end of day (protection still ends at end of day). </param> public IsdaPremiumLegSchedule(DateTime startDate, DateTime endDate, int step, StubConvention stubType, QLNet.BusinessDayConvention businessdayAdjustmentConvention, QLNet.Calendar calandar, bool protectionStart) : this(getUnadjustedDates(startDate, endDate, step, stubType), businessdayAdjustmentConvention, calandar, protectionStart) { }
private static SwapLeg fixedLeg(LocalDate start, LocalDate end, Frequency frequency, PayReceive payReceive, NotionalSchedule notional, double fixedRate, StubConvention stubConvention) { return(RateCalculationSwapLeg.builder().payReceive(payReceive).accrualSchedule(PeriodicSchedule.builder().startDate(start).endDate(end).frequency(frequency).businessDayAdjustment(BDA_MF).stubConvention(stubConvention).build()).paymentSchedule(PaymentSchedule.builder().paymentFrequency(frequency).paymentDateOffset(DaysAdjustment.NONE).build()).notionalSchedule(notional).calculation(FixedRateCalculation.of(fixedRate, THIRTY_U_360)).build()); }
/** * Set up a strip of increasing maturity CDSs that have some coupons in common. The trade date, step-in date and valuation date and * accrual start date are all common, as is the payment frequency. The maturities are expressed as integer multiples of the * payment interval from a reference date (the next IMM date after the trade date for standard CDSs) - this guarantees that premiums * will be the same across several CDSs. * @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 cash settlement date. The date that values are PVed to. Is is normally today + 3 business days. * @param accStartDate Accrual Start Date. 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 * @param payAccOnDefault Is the accrued premium paid in the event of a default * @param paymentInterval The nominal step between premium payments (e.g. 3 months, 6 months). * @param stubType the stub convention * @param protectStart If protectStart = true, then protections starts at the beginning of the day, otherwise it is at the end. * @param recoveryRate The recovery rate * @param businessdayAdjustmentConvention How are adjustments for non-business days made * @param calendar HolidayCalendar defining what is a non-business day * @param accrualDayCount Day count used for accrual * @param curveDayCount Day count used on curve (NOTE ISDA uses ACT/365 and it is not recommended to change this) */ public MultiCdsAnalytic( DateTime tradeDate, DateTime stepinDate, DateTime cashSettlementDate, DateTime accStartDate, DateTime maturityReferanceDate, int[] maturityIndexes, Boolean payAccOnDefault, int paymentInterval, StubConvention stubType, Boolean protectStart, double recoveryRate, QLNet.BusinessDayConvention businessdayAdjustmentConvention, QLNet.Calendar calendar, Enums.DayCount accrualDayCount, Enums.DayCount curveDayCount) { OMLib.Conventions.DayCount.Thirty360 swapDCC = new OMLib.Conventions.DayCount.Thirty360(); OMLib.Conventions.DayCount.Actual360 moneyMarketDCC = new OMLib.Conventions.DayCount.Actual360(); OMLib.Conventions.DayCount.Actual365 curveDCC = new OMLib.Conventions.DayCount.Actual365(); _nMaturities = maturityIndexes.Length; _payAccOnDefault = payAccOnDefault; _accStart = DateTime.Compare(accStartDate, tradeDate) < 0 ? -curveDCC.YearFraction(accStartDate, tradeDate) : curveDCC.YearFraction(tradeDate, accStartDate); DateTime temp = DateTime.Compare(stepinDate, accStartDate) > 0 ? stepinDate : accStartDate; DateTime effectiveStartDate = protectStart ? temp.AddDays(-1) : temp; _cashSettlementTime = curveDCC.YearFraction(tradeDate, cashSettlementDate); _effectiveProtectionStart = curveDCC.YearFraction(tradeDate, effectiveStartDate); _lgd = 1 - recoveryRate; DateTime[] maturities = new DateTime[_nMaturities]; _protectionEnd = new double[_nMaturities]; int period = paymentInterval; for (int i = 0; i < _nMaturities; i++) { int tStep = period * maturityIndexes[i]; maturities[i] = maturityReferanceDate.AddMonths(tStep); _protectionEnd[i] = curveDCC.YearFraction(tradeDate, maturities[i]); } IsdaPremiumLegSchedule fullPaymentSchedule = new IsdaPremiumLegSchedule(accStartDate, maturities[_nMaturities - 1], period, stubType, businessdayAdjustmentConvention, calendar, protectStart); //remove already expired coupons IsdaPremiumLegSchedule paymentSchedule = fullPaymentSchedule.truncateSchedule(stepinDate); int couponOffset = fullPaymentSchedule.getNumPayments() - paymentSchedule.getNumPayments(); _totalPayments = paymentSchedule.getNumPayments(); _standardCoupons = new CdsCoupon[_totalPayments - 1]; for (int i = 0; i < (_totalPayments - 1); i++) { //The last coupon is actually a terminal coupon, so not included here _standardCoupons[i] = new CdsCoupon( tradeDate, paymentSchedule.getAccPaymentDateTriplet(i), protectStart, accrualDayCount, curveDayCount); } //find the terminal coupons _terminalCoupons = new CdsCoupon[_nMaturities]; _matIndexToPayments = new int[_nMaturities]; _accruedDays = new int[_nMaturities]; _accrued = new double[_nMaturities]; long secondJulianDate = stepinDate.Ticks; for (int i = 0; i < _nMaturities; i++) { int index = fullPaymentSchedule.getNominalPaymentDateIndex(maturities[i]); //maturity is unadjusted, but if protectionStart=true (i.e. standard CDS) there is effectively an extra day of accrued interest DateTime accEnd = protectStart ? maturities[i].AddDays(1) : maturities[i]; _terminalCoupons[i] = new CdsCoupon( tradeDate, fullPaymentSchedule.getAccStartDate(index), accEnd, fullPaymentSchedule.getPaymentDate(index), protectStart); _matIndexToPayments[i] = index - couponOffset; //This will only matter for the edge case when the trade date is 1 day before maturity DateTime tDate2 = _matIndexToPayments[i] < 0 ? fullPaymentSchedule.getAccStartDate(couponOffset - 1) : paymentSchedule.getAccStartDate(0); long firstJulianDate = tDate2.Ticks; _accruedDays[i] = secondJulianDate > firstJulianDate ? (int)(secondJulianDate - firstJulianDate) : 0; _accrued[i] = DateTime.Compare(tDate2, stepinDate) < 0 ? swapDCC.YearFraction(tDate2, stepinDate) : 0.0; } }
// ibor rate leg private static SwapLeg iborLeg(LocalDate start, LocalDate end, IborIndex index, PayReceive payReceive, NotionalSchedule notional, StubConvention stubConvention) { Frequency freq = Frequency.of(index.Tenor.Period); return(RateCalculationSwapLeg.builder().payReceive(payReceive).accrualSchedule(PeriodicSchedule.builder().startDate(start).endDate(end).frequency(freq).businessDayAdjustment(BDA_MF).stubConvention(stubConvention).build()).paymentSchedule(PaymentSchedule.builder().paymentFrequency(freq).paymentDateOffset(DaysAdjustment.NONE).build()).notionalSchedule(notional).calculation(IborRateCalculation.builder().index(index).fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, index.FixingCalendar, BDA_P)).build()).build()); }
// parse a trade based on a convention internal static SwapTrade parseWithConvention(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver, string conventionStr) { BuySell buySell = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD)); double notional = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD)); double fixedRate = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD)); Optional <Period> periodToStartOpt = row.findValue(PERIOD_TO_START_FIELD).map(s => LoaderUtils.parsePeriod(s)); Optional <Tenor> tenorOpt = row.findValue(TENOR_FIELD).map(s => LoaderUtils.parseTenor(s)); Optional <LocalDate> startDateOpt = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <LocalDate> endDateOpt = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <RollConvention> rollCnvOpt = row.findValue(ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s)); Optional <StubConvention> stubCnvOpt = row.findValue(STUB_CONVENTION_FIELD).map(s => StubConvention.of(s)); Optional <LocalDate> firstRegStartDateOpt = row.findValue(FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); Optional <LocalDate> lastRegEndDateOpt = row.findValue(LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)); BusinessDayConvention dateCnv = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING); Optional <HolidayCalendarId> dateCalOpt = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s)); double? fxRateOpt = row.findValue(FX_RATE_FIELD).map(str => LoaderUtils.parseDouble(str)); // explicit dates take precedence over relative ones if (startDateOpt.Present && endDateOpt.Present) { if (periodToStartOpt.Present || tenorOpt.Present) { throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD, TENOR_FIELD)); } LocalDate startDate = startDateOpt.get(); LocalDate endDate = endDateOpt.get(); SwapTrade trade = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt); return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt)); } // start date + tenor if (startDateOpt.Present && tenorOpt.Present) { if (periodToStartOpt.Present || endDateOpt.Present) { throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD, END_DATE_FIELD)); } LocalDate startDate = startDateOpt.get(); Tenor tenor = tenorOpt.get(); LocalDate endDate = startDate.plus(tenor); SwapTrade trade = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt); return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt)); } // relative dates if (periodToStartOpt.Present && tenorOpt.Present && info.TradeDate.Present) { if (startDateOpt.Present || endDateOpt.Present) { throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, PERIOD_TO_START_FIELD, TENOR_FIELD, TRADE_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD)); } LocalDate tradeDate = info.TradeDate.get(); Period periodToStart = periodToStartOpt.get(); Tenor tenor = tenorOpt.get(); if (fxRateOpt.HasValue) { XCcyIborIborSwapConvention convention = XCcyIborIborSwapConvention.of(conventionStr); double notionalFlat = notional * fxRateOpt.Value; SwapTrade trade = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, notionalFlat, fixedRate, resolver.ReferenceData); trade = trade.toBuilder().info(info).build(); return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt)); } else { SingleCurrencySwapConvention convention = SingleCurrencySwapConvention.of(conventionStr); SwapTrade trade = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, fixedRate, resolver.ReferenceData); trade = trade.toBuilder().info(info).build(); return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt)); } } // no match throw new System.ArgumentException("Swap trade had invalid combination of fields. These fields are mandatory:" + ImmutableList.of(BUY_SELL_FIELD, NOTIONAL_FIELD, FIXED_RATE_FIELD) + " and one of these combinations is mandatory: " + ImmutableList.of(CONVENTION_FIELD, TRADE_DATE_FIELD, PERIOD_TO_START_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD)); }