public static Lease Create(string id, string propertyReference, DateTime nextReviewDate, DateTime baseDate, Period tenor, string currency, Period paymentFrequency, string businessDayConvention, string businessCentersAsString) { var lease = new Lease { startDate = new IdentifiedDate { id = "StartDate", Value = baseDate }, leaseExpiryDate = new IdentifiedDate { id = "MaturityDate", Value = tenor.Add(baseDate) }, leaseTenor = tenor, businessDayAdjustments = BusinessDayAdjustmentsHelper.Create(businessDayConvention, businessCentersAsString), currency = new IdentifiedCurrency { id = "PaymentCurrency", Value = currency }, leaseType = "Standard", leaseIdentifier = id, propertyReference = propertyReference, nextReviewDate = new IdentifiedDate { id = "NextReviewDate", Value = nextReviewDate }, paymentFrequency = paymentFrequency, }; return(lease); }
public static DateTime Add(DateTime dateTime, Period periodToAdd) { if (periodToAdd == null) { throw new ArgumentNullException(nameof(periodToAdd)); } return(periodToAdd.Add(dateTime)); }
public void Addition_With_IdenticalPeriodTypes() { Period p1 = Period.FromHours(3); Period p2 = Period.FromHours(2); Period sum = p1 + p2; Assert.AreEqual(5, sum.Hours); Assert.AreEqual(sum, Period.Add(p1, p2)); }
/// <summary> /// Gets the unadjusted calculation date schedule. /// </summary> /// <param name="effectiveDate">The effective date.</param> /// <param name="intervalToTerminationDate">The interval to termination date.</param> /// <param name="periodInterval">The period interval.</param> /// <returns></returns> public List <CalculationPeriod> GetUnadjustedCalculationDateSchedule(DateTime effectiveDate, Period intervalToTerminationDate, Period periodInterval) { CalculationPeriodDates = null; PeriodInterval = periodInterval; _effectiveDate = effectiveDate; _termDate = intervalToTerminationDate.Add(effectiveDate); RollConvention = RollConventionEnum.NONE; _unadjustedDateScheduleList = CalculationPeriodHelper.GenerateUnadjustedCalculationDates(effectiveDate, intervalToTerminationDate, periodInterval); return(_unadjustedDateScheduleList); }
/// <summary> /// Process a PPD Grid. The result is a Market structure that camn be published. /// </summary> /// <param name="logger">The logger</param> /// <param name="cache">The cache.</param> /// <param name="swapCurve">The latest rate curve</param> /// <param name="ppdGrid">The raw Points Per Day matrix supplied from the subscriber</param> /// <param name="id">The id to use in publishing the curve</param> /// <param name="nameSpace">The client namespace</param> /// <returns></returns> public static Market ProcessSwaption(ILogger logger, ICoreCache cache, Market swapCurve, SwaptionPPDGrid ppdGrid, string id, string nameSpace) { var mkt = swapCurve; var curve = new SimpleRateCurve(mkt); // List the values so we can build our ATM vols var atmVols = new Dictionary <SimpleKey, decimal>(); // Create a calendar to use to modify the date // default to be Sydney... IBusinessCalendar bc = BusinessCenterHelper.ToBusinessCalendar(cache, new[] { "AUSY" }, nameSpace); //BusinessCalendarHelper("AUSY"); // Use some logic to get the spot date to use // LPM Spot lag is 2 days (modfollowing) DateTime spotDate = curve.GetSpotDate(); // Extract each surface and build an ATM engine therefrom // Build a list of all possible engines foreach (string e in ExpiryKeys) { // Assume frequency = 4 months until 3 years tenor is reached Period expiration = PeriodHelper.Parse(e); double expiryYearFraction = expiration.ToYearFraction(); foreach (string t in TenorKeys) { // Create a Swaprate for each expiry/tenor pair // Assume frequency = 4 months until 3 years tenor is reached double tenorYearFraction = PeriodHelper.Parse(t).ToYearFraction(); int frequency = tenorYearFraction < 4 ? 4 : 2; // Calculation date // Discount factors // Offsets (elapsed days) var rates = new SwapRate(logger, cache, nameSpace, "AUSY", curve.BaseDate, "ACT/365.FIXED", curve.GetDiscountFactors(), curve.GetDiscountFactorOffsets(), frequency, BusinessDayConventionEnum.MODFOLLOWING); // Calculate the volatility given PPD and swap curve DateTime expiry = bc.Roll(expiration.Add(spotDate), BusinessDayConventionEnum.FOLLOWING); decimal vol = CalculateAtmVolatility(rates, expiry, ppdGrid, expiryYearFraction, tenorYearFraction); atmVols.Add(new SimpleKey(e, t), vol); } } var vols = new object[atmVols.Count + 1, 3]; var i = 1; vols[0, 0] = "Expiry"; vols[0, 1] = "Tenor"; vols[0, 2] = "0"; foreach (var key in atmVols.Keys) { vols[i, 0] = key.Expiry; vols[i, 1] = key.Tenor; vols[i, 2] = atmVols[key]; i++; } DateTime buildDateTime = swapCurve.Items1[0].buildDateTime; var volSurface = new VolatilitySurface(vols, new VolatilitySurfaceIdentifier(id), curve.BaseDate, buildDateTime); return(CreateMarketDocument(volSurface.GetFpMLData())); }
/// <summary> /// Gets the first regular period start date. /// </summary> /// <param name="periodInterval">The period interval.</param> /// <param name="rollConvention">The roll convention.</param> /// <param name="startDate">The start date.</param> /// <returns></returns> public static DateTime GetFirstRegularPeriodStartDate(Period periodInterval, RollConventionEnum rollConvention, DateTime startDate) { DateTime advDate = periodInterval.Add(startDate); DateTime regularPeriodStartDate = advDate; if (rollConvention != RollConventionEnum.NONE) { regularPeriodStartDate = RollConventionEnumHelper.AdjustDate(rollConvention, advDate); } return(regularPeriodStartDate); }
/// <summary> /// Gets the unadjusted dates from effective date. /// </summary> /// <param name="effectiveDate">The effective date.</param> /// <param name="terminationDate">The termination date.</param> /// <param name="periodInterval">The period interval.</param> /// <param name="rollConvention">The roll convention.</param> /// <param name="firstRegularPeriodStartDate">The first regular period start date.</param> /// <param name="lastRegularPeriodEndDate">The last regular period end date.</param> /// <returns></returns> public static DateTime[] GetUnadjustedDatesFromEffectiveDate(DateTime effectiveDate, DateTime terminationDate, Period periodInterval, RollConventionEnum rollConvention, out DateTime firstRegularPeriodStartDate, out DateTime lastRegularPeriodEndDate) { lastRegularPeriodEndDate = terminationDate; DateTime firstRollDate = effectiveDate; var periodDates = new List <DateTime> { firstRollDate }; DateTime nextRollDate = periodInterval.Add(firstRollDate); DateTime rollConventionDate = ApplyRollConventionToDate(rollConvention, nextRollDate); firstRegularPeriodStartDate = DateTime.Compare(nextRollDate, rollConventionDate) == 0 ? firstRollDate : rollConventionDate; periodDates.Add(rollConventionDate); Boolean reachedEnd = false; while (!reachedEnd) { rollConventionDate = periodInterval.Add(rollConventionDate); rollConventionDate = ApplyRollConventionToDate(rollConvention, rollConventionDate); if (rollConventionDate <= terminationDate) { if (rollConventionDate.Month == terminationDate.Month && rollConventionDate.Year == terminationDate.Year) { periodDates.Add(terminationDate); reachedEnd = true; lastRegularPeriodEndDate = rollConventionDate.Day == terminationDate.Day ? periodDates[periodDates.Count - 1] : periodDates[periodDates.Count - 2]; } else { periodDates.Add(rollConventionDate); } } else { reachedEnd = true; lastRegularPeriodEndDate = periodDates[periodDates.Count - 1]; periodDates.Add(terminationDate); } } periodDates.Sort(); return(periodDates.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="PriceableZeroRate"/> class. /// </summary> /// <param name="id">The id.</param> /// <param name="baseDate">The base date.</param> /// <param name="amount">The amount of cash.</param> /// <param name="term">The term.</param> /// <param name="nodeStruct">The nodeStruct.</param> /// <param name="paymentCalendar">The payment calendar. If null, a new is constructed based on the business calendars.</param> /// <param name="fixedRate">The fixed rate.</param> public PriceableZeroRate(string id, DateTime baseDate, Decimal amount, Period term, ZeroRateNodeStruct nodeStruct, IBusinessCalendar paymentCalendar, BasicQuotation fixedRate) : base(id, baseDate, amount, nodeStruct.BusinessDayAdjustments, fixedRate) { ModelIdentifier = "ZeroCouponRate"; Adjust = nodeStruct.AdjustDates; DayCountFraction = nodeStruct.DayCountFraction; RiskMaturityDate = !Adjust?term.Add(baseDate) : GetEffectiveDate(baseDate, paymentCalendar, term, nodeStruct.BusinessDayAdjustments.businessDayConvention); CompoundingFrequency = nodeStruct.CompoundingFrequency; AdjustedStartDate = baseDate; YearFraction = GetYearFraction(DayCountFraction.Value, AdjustedStartDate, RiskMaturityDate); }
/// <summary> /// Gets the last regular period end date. /// </summary> /// <param name="periodInterval">The period interval.</param> /// <param name="rollConvention">The roll convention.</param> /// <param name="endDate">The end date.</param> /// <returns></returns> public static DateTime GetLastRegularPeriodEndDate(Period periodInterval, RollConventionEnum rollConvention, DateTime endDate) { int periodMultiplierAsInt = int.Parse(periodInterval.periodMultiplier); if (periodMultiplierAsInt > 0) { periodMultiplierAsInt = periodMultiplierAsInt * -1; } periodInterval.periodMultiplier = periodMultiplierAsInt.ToString(CultureInfo.InvariantCulture); DateTime advDate = periodInterval.Add(endDate); DateTime regularPeriodEndDate = advDate; if (rollConvention != RollConventionEnum.NONE) { regularPeriodEndDate = RollConventionEnumHelper.AdjustDate(rollConvention, advDate); } return(regularPeriodEndDate); }
public void AddEnclosedPeriodShouldReturnSamePeriod() { // Arrange var from = new DateTime(1111); var to = new DateTime(3333); var period = new Period(from, to); ICollection expected = new Period[] { period }; // Act IEnumerable <Period> actual1 = period + period; IEnumerable <Period> actual2 = period.Add(period); // Assert CollectionAssert.AreEqual(expected, (ICollection)actual1.ToList()); CollectionAssert.AreEqual(expected, (ICollection)actual2.ToList()); }
/// <summary> /// Generates the unadjusted calculation dates. /// </summary> /// <param name="effectiveDate">The effective date.</param> /// <param name="intervalToTerminationDate">The interval to termination date.</param> /// <param name="periodInterval">The period interval.</param> /// <param name="rollConvention">The roll convention.</param> /// <returns></returns> public static List <CalculationPeriod> GenerateUnadjustedCalculationDates(DateTime effectiveDate, Period intervalToTerminationDate, Period periodInterval, RollConventionEnum rollConvention) { DateTime startDate = effectiveDate; // Adjust the effective date if (rollConvention != RollConventionEnum.NONE) { startDate = RollConventionEnumHelper.AdjustDate(rollConvention, effectiveDate); } Double divisor = IntervalHelper.Div(intervalToTerminationDate, periodInterval); // The divisor has to be a whole number (i.e. the period must roll to the term date interval if ((divisor % 1) != 0) { throw new ArithmeticException("The period frequency will not roll to the supplied termination date interval"); } DateTime terminationDate = intervalToTerminationDate.Add(startDate); StubPeriodTypeEnum?stubPeriodType = null; return(GenerateUnadjustedCalculationDates(startDate, terminationDate, effectiveDate, periodInterval, rollConvention, stubPeriodType)); }
/// <summary> /// Gets the unadjusted date schedule. /// </summary> /// <param name="effectiveDate">The effective date.</param> /// <param name="intervalToTerminationDate">The interval to termination date.</param> /// <param name="periodInterval">The period interval.</param> /// <returns></returns> public static List <DateTime> GetUnadjustedDateSchedule(DateTime effectiveDate, Period intervalToTerminationDate, Period periodInterval) { Double divisor = IntervalHelper.Div(intervalToTerminationDate, periodInterval); // The divisor has to be a whole number (i.e. the period must roll to the term date interval if (System.Math.Abs(divisor % 1) > Tolerance) { throw new ArithmeticException("The period frequency will not roll to the supplied termination date interval"); } DateTime termDate = intervalToTerminationDate.Add(effectiveDate); var periodDates = new List <DateTime>(); //DateTime periodStartDate = effectiveDate; int multiplier = periodInterval.GetPeriodMultiplier(); periodDates.Add(effectiveDate); for (int i = 1; i < divisor; i++) { var periodEndDate = DateAdd(effectiveDate, periodInterval.period, multiplier * i); periodDates.Add(periodEndDate); } periodDates.Add(termDate); return(periodDates); }
///<summary> ///</summary> ///<param name="discountCurve"></param> ///<param name="baseDate"></param> ///<param name="forwardRateTenor"></param> ///<param name="priceableXibor"></param> ///<returns></returns> public TermCurve ToPriceableXiborForwardCurve(TermCurve discountCurve, DateTime baseDate, Period forwardRateTenor, PriceableXibor priceableXibor) //TODO { //CompoundingFrequency frequency = CompoundingFrequencyHelper.Create("Annual"); var dates = discountCurve.GetListTermDates(); var yearFractions = new List <double>(); foreach (var date in dates) { var yearFraction = (date - baseDate).TotalDays / 365.0;//TODO extend this with a general daycountraction. yearFractions.Add(yearFraction); } var midValues = discountCurve.GetListMidValues(); var discountFactors = new List <double>(Array.ConvertAll(midValues.ToArray(), Convert.ToDouble)); var forwardTermCurve = TermCurve.Create(new List <TermPoint>()); var index = 0; foreach (var startOfPeriodDateTime in dates) { var yearFractionsbeginPeriod = yearFractions[index]; var endOfPeriodDateTime = forwardRateTenor.Add(startOfPeriodDateTime); var yearFractionAtEndOfPeriod = (endOfPeriodDateTime - baseDate).TotalDays / 365.0; //get df corresponding to end of period // IInterpolation interpolation = new LinearRateInterpolation(); interpolation.Initialize(yearFractions.ToArray(), discountFactors.ToArray()); var dfAtEndOfPeriod = interpolation.ValueAt(yearFractionAtEndOfPeriod, true); var dfAtTheBeginingOfPeriod = discountFactors[index]; var forwardRate = (dfAtTheBeginingOfPeriod / dfAtEndOfPeriod - 1) / (yearFractionAtEndOfPeriod - yearFractionsbeginPeriod); var zeroPoint = TermPointFactory.Create(Convert.ToDecimal(forwardRate), startOfPeriodDateTime); forwardTermCurve.Add(zeroPoint); ++index; } return(forwardTermCurve); }
public void AddPeriodWithOverlappingToShouldReturnExtendedPeriod() { // Arrange var from1 = new DateTime(1111); var to1 = new DateTime(3333); var period1 = new Period(from1, to1); var from2 = new DateTime(2222); var to2 = new DateTime(4444); var period2 = new Period(from2, to2); ICollection expected = new Period[] { new Period(from1, to2) }; // Act IEnumerable <Period> actual1 = period1 + period2; IEnumerable <Period> actual2 = period1.Add(period2); // Assert CollectionAssert.AreEqual(expected, (ICollection)actual1.ToList()); CollectionAssert.AreEqual(expected, (ICollection)actual2.ToList()); }
public void AddDistinctPeriodShouldReturnBothPeriods() { // Arrange var from1 = new DateTime(1111); var to1 = new DateTime(3333); var period1 = new Period(from1, to1); var from2 = new DateTime(4444); var to2 = new DateTime(6666); var period2 = new Period(from2, to2); ICollection expected = new Period[] { period1, period2 }; // Act IEnumerable <Period> actual1 = period1 + period2; IEnumerable <Period> actual2 = period1.Add(period2); // Assert CollectionAssert.AreEqual(expected, (ICollection)actual1.ToList()); CollectionAssert.AreEqual(expected, (ICollection)actual2.ToList()); }
/// <summary> /// Convert the cap/floor PPD values to an ATM parVols structure /// This method then calls the bootstrapper <see cref="ProcessCapFloorPpd"/> /// to generate the capvol curve /// </summary> /// <param name="logger">The logger</param> /// <param name="cache">The cache.</param> /// <param name="rateCurve"></param> /// <param name="capFloor"></param> /// <param name="nameSpace"></param> /// <returns></returns> private static Market ProcessCapFloorPpd(ILogger logger, ICoreCache cache, string nameSpace, Market rateCurve, CapFloorATMMatrix capFloor) { var expiry = capFloor.GetExpiries(); var vols = capFloor.GetVolatilities(); var mkt = rateCurve; var curve = new SimpleRateCurve(mkt); var rawOffsets = curve.GetDiscountFactorOffsets(); var offsets = Array.ConvertAll(rawOffsets, IntToDouble); var discountFactors = curve.GetDiscountFactors(); var volType = capFloor.GetVolatilityTypes(); var atmVols = new Dictionary <string, decimal>(); var settings = CreateCapFloorProperties(capFloor.GetVolatilitySettings()); var bc = BusinessCenterHelper.ToBusinessCalendar(cache, new[] { "AUSY" }, nameSpace); // Use some logic to get the spot date to use // Step through each vol and convert ppd to ATM vol for (var i = 0; i < expiry.Length; i++) { // Create a Swaprate for each expiry // Assume frequency = 4 months until 4 years tenor is reached Period tv = PeriodHelper.Parse(expiry[i]); //double tvYearFraction = tv.ToYearFraction(); //int frequency = tvYearFraction < 4 ? 4 : 2; const int frequency = 4; var rates = new SwapRate(logger, cache, nameSpace, "AUSY", curve.GetBaseDate(), "ACT/365.FIXED", discountFactors, curve.GetDiscountFactorOffsets(), frequency, BusinessDayConventionEnum.MODFOLLOWING); switch (volType[i]) { case "ETO": { DateTime spotDate = settings.GetValue("Calculation Date", DateTime.MinValue); var rollConvention = settings.GetValue("RollConvention", BusinessDayConventionEnum.MODFOLLOWING); DateTime etoDate = bc.Roll(tv.Add(spotDate), rollConvention); atmVols[expiry[i]] = CalculateATMVolatility(settings, spotDate, etoDate, offsets, discountFactors, vols[i][0]); } break; case "Cap/Floor": { DateTime spotDate = settings.GetValue("Calculation Date", DateTime.MinValue); var rollConvention = settings.GetValue("RollConvention", BusinessDayConventionEnum.MODFOLLOWING); DateTime expiryDate = bc.Roll(tv.Add(spotDate), rollConvention); string tenor = DateToTenor(spotDate, expiryDate); double tenorYearFraction = PeriodHelper.Parse(tenor).ToYearFraction(); // Add the caplet maturity to the expiry and then calculate the vol atmVols[expiry[i]] = CalculateCAPATMVolatility(rates, spotDate, tenorYearFraction, vols[i][0]); } break; } } // Fudge to switch the PPD header to ATM // We've converted so we want the new name var headers = capFloor.GetHeaders(); for (var i = 0; i < headers.Length; i++) { if (!headers[i].Contains("PPD")) { continue; } headers[i] = "ATM"; break; } // Convert our lovely dictionary to a grubby array of arrays var volatilities = new object[atmVols.Keys.Count][]; var row = 0; foreach (var key in atmVols.Keys) { volatilities[row] = new object[3]; volatilities[row][0] = key; volatilities[row][1] = atmVols[key]; volatilities[row][2] = volType[row++]; } var convertedCapFloor = new CapFloorATMMatrix(headers, volatilities, capFloor.GetVolatilitySettings(), capFloor.baseDate.Value, capFloor.id); return(ProcessCapFloorATM(logger, cache, nameSpace, rateCurve, convertedCapFloor)); }
///<summary> ///</summary> ///<param name="directionDateGeneration"></param> ///<param name="effectiveDate"></param> ///<param name="terminationDate"></param> ///<param name="periodInterval"></param> ///<param name="rollDayConvention"></param> ///<returns></returns> ///<exception cref="ArgumentOutOfRangeException"></exception> public static DateTime[] GetUnadjustedDates(int directionDateGeneration, DateTime effectiveDate, DateTime terminationDate, Period periodInterval, RollConventionEnum rollDayConvention) { DateTime firstRegularPeriodStartDate; DateTime lastRegularPeriodEndDate; switch (directionDateGeneration) { case 1: { var result = new List <DateTime>(GetUnadjustedDatesFromEffectiveDate(effectiveDate, terminationDate, periodInterval, rollDayConvention, out firstRegularPeriodStartDate, out lastRegularPeriodEndDate)); // remove extra(faulty-generated) date from the end if a swap is shorter than a period // if (periodInterval.Add(effectiveDate) > terminationDate) { result.RemoveAt(result.Count - 1); //remove last element } // if there is a long stub at the back // if (result[0] != lastRegularPeriodEndDate && periodInterval.Add(lastRegularPeriodEndDate) < result[result.Count - 1]) // { // it it is long - make it short // DateTime realLastRegularPeriodEndDate = periodInterval.Add(lastRegularPeriodEndDate); result.Insert(result.Count - 1, realLastRegularPeriodEndDate); } return(result.ToArray()); } case 2: { var result = new List <DateTime>(GetUnadjustedDatesFromTerminationDate(effectiveDate, terminationDate, periodInterval, rollDayConvention, out firstRegularPeriodStartDate, out lastRegularPeriodEndDate)); // if there is a long stub at the front // if (result[0] != firstRegularPeriodStartDate && periodInterval.Subtract(firstRegularPeriodStartDate) > result[0]) // add a check if a period is short ... { // it it is long - make it short // DateTime realFirstRegularPeriodStartDate = periodInterval.Subtract(firstRegularPeriodStartDate); result.Insert(1, realFirstRegularPeriodStartDate); } return(result.ToArray()); } default: { const string message = "Argument value is out of range. Only 1 and 2 are the valid values for this argument"; throw new ArgumentOutOfRangeException(nameof(directionDateGeneration), directionDateGeneration, message); } } }