private static TermStructure CalcCurveFromMaturity(DateTime Maturity, DateTime StartDate, double CouponRate, NextWorkingDayConvention nextDay, int Freq, Dictionary <DateTime, DateTime> Holidays, bool FixedCashPayments) { List <TermPoint> points = new List <TermPoint>(); DateTime pointDate = Maturity; bool lastPoint = true; while (pointDate > StartDate) { if (lastPoint) { // Only do the last point once, decrement the date next time around lastPoint = false; } else { pointDate = pointDate.AddMonths(-(12 / Freq)); } TermPoint point = new TermPoint(); point.Rate = CouponRate; point.PointDate = pointDate; int month = point.PointDate.Month; point.PayDate = GetWorkingDayDate(1, pointDate.AddDays(-1), Holidays, nextDay); if (!FixedCashPayments) { point.PointDate = point.PayDate; } points.Add(point); } ; TermStructure ts = new TermStructure(); for (int i = points.Count - 1; i >= 0; i--) { ts.Points.Add(points[i]); } return(ts); }
internal static double AccruedForDaysInPeriod(DateTime AccrueFrom, DateTime AccrueTo, TermStructure ts, double Rate, bool FixedCashPayments) { double ret = 0; TermPoint periodStart = ts.Points[0]; TermPoint periodEnd = null; if (AccrueTo > ts.Points[0].PointDate && AccrueFrom < ts.Points[ts.PointCount - 1].PointDate) { // Find the applicable period foreach (TermPoint point in ts.Points) { if (point.PointDate <= AccrueFrom) { periodStart = point; } else if (point.PointDate >= AccrueTo) { periodEnd = point; break; } } // If the caller has asked for Accrued to a point past the end of the term structure it is not valid // and the PeriodEnd variable will be equal to zero if (periodEnd == null) { throw new Exception(string.Format("AccrueTo data [{0}] is past the end of the curve [{1}].", AccrueTo.ToString("dd MMM yy"), ts.Points[ts.PointCount - 1].PointDate.ToString("dd MMM yy"))); } int days = DaysBetween(AccrueFrom, AccrueTo, ts.DayCount); int periodLength = DaysBetween(periodStart.PointDate, periodEnd.PointDate, ts.DayCount); int freq = (int)Math.Round((double)365 / periodLength, 0); // We need to get the rate of the point to which we are accrueing up to // A rate quoted within the Curve is the portion of rate for that period. So the rate according to the curve for a // semi annual bond paying 5% would be 2.5% if (Rate == 0) { Rate = periodEnd.Amount; } if (FixedCashPayments) { if (periodLength > 366) { // it's longer than a year. // We need to work out the accrued as if a coupon "was" paid each year // This will take account of when a Feb 29 occurrs // Split the accrued to before and after an imaginary paydate being one year before the real pay date DateTime couponPoint2 = periodEnd.PointDate; do { DateTime couponPoint = couponPoint2.AddYears(-1); periodLength = DaysBetween(couponPoint, couponPoint2, ts.DayCount); if (couponPoint < AccrueTo) { if (couponPoint2 < AccrueTo) { // We have done the part up to AccrueTo if (AccrueFrom < couponPoint) { days = DaysBetween(couponPoint, couponPoint2, ts.DayCount); } else { days = DaysBetween(AccrueFrom, couponPoint, ts.DayCount); } } else { // Work out accrued from the CouponPoint to the AccrueTo date if (AccrueFrom < couponPoint) { days = DaysBetween(couponPoint, AccrueTo, ts.DayCount); } else { days = DaysBetween(AccrueFrom, AccrueTo, ts.DayCount); } } ret += (Rate * days / periodLength); } couponPoint2 = couponPoint; } while (couponPoint2 < AccrueFrom); } else { if (periodLength != 0) { ret += (Rate / freq) * (days / periodLength); } } } else { switch (ts.DayCount) { case DayCountConvention.e30_360: case DayCountConvention.e30E_360: case DayCountConvention.e30E1_360: case DayCountConvention.eActual_360: ret = Rate * days / 360; break; case DayCountConvention.eActual_365: case DayCountConvention.eActualNL_365: ret = Rate * days / 365; break; case DayCountConvention.eActual_Actual: // Check for leap years int year1 = (int)DateTime.Parse("1 Jan " + AccrueTo.AddYears(1).Year).Subtract(DateTime.Parse("1 Jan " + AccrueFrom.Year)).TotalDays; if (year1 == 731) { // it goes into two years one of which is a leap year // A bit different for this // This assumes that the period is <= 1 year, ie, cannot span more than 2 adjacent years // Days = startpoint up to the first of next year days = (int)DateTime.Parse("1 Jan " + periodEnd.PointDate.Year).Subtract(periodStart.PointDate).TotalDays; // Days2 = the first of the next year to the end point int days2 = (int)periodEnd.PointDate.Subtract(DateTime.Parse("1 Jan " + periodEnd.PointDate.Year)).TotalDays; // Number of days in each seperate period which falls in each year year1 = (int)DateTime.Parse("1 Jan " + periodEnd.PointDate.Year).Subtract(DateTime.Parse("1 Jan " + periodStart.PointDate.Year)).TotalDays; int year2 = (int)DateTime.Parse("1 Jan " + periodEnd.PointDate.Year + 1).Subtract(DateTime.Parse("1 Jan " + periodEnd.PointDate.Year)).TotalDays; ret = (((Rate / year1) * days)) + (((Rate / year2) * days2)); } else { ret = (Rate * days) / year1; } break; } } } return(ret); }