public void OISFuture() { var bd = DateTime.Today; var pillars = new[] { bd, bd.AddDays(1000) }; var flatRate = 0.05; var rates = pillars.Select(p => flatRate).ToArray(); CalendarProvider.Collection.TryGetCalendar("LON", out var cal); var usd = TestProviderHelper.CurrencyProvider["USD"]; var discoCurve = new IrCurve(pillars, rates, bd, "USD.BLAH", Interpolator1DType.Linear, usd); var fModel = new FundingModel(bd, new[] { discoCurve }, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider); var price = 93.0; var ix = new FloatRateIndex { Currency = usd, DayCountBasis = DayCountBasis.ACT360, FixingOffset = 2.Bd(), HolidayCalendars = cal, ResetTenor = 3.Months(), RollConvention = RollType.MF }; var maturity = bd.AddDays(365); var accrualStart = maturity.AddPeriod(RollType.F, ix.HolidayCalendars, ix.FixingOffset); var accrualEnd = accrualStart.AddPeriod(ix.RollConvention, ix.HolidayCalendars, ix.ResetTenor); var dcf = maturity.CalculateYearFraction(accrualEnd, DayCountBasis.ACT360); var s = new OISFuture { Currency = usd, ContractSize = 1e6, Position = 1, DCF = dcf, AverageStartDate = accrualStart, AverageEndDate = accrualEnd, ForecastCurve = "USD.BLAH", Price = price, Index = ix }; var pv = s.Pv(fModel, false); var rateEst = discoCurve.GetForwardRate(accrualStart, accrualEnd, RateType.Linear, ix.DayCountBasis); var fairPrice = 100.0 - rateEst * 100; var expectedPv = (price - fairPrice) * 1e6 * dcf; Assert.Equal(expectedPv, pv); var ss = s.Sensitivities(fModel); Assert.True(ss.Count == 1 && ss.Keys.Single() == "USD.BLAH"); Assert.True(ss["USD.BLAH"].Count == 2 && ss["USD.BLAH"].Keys.Contains(accrualStart) && ss["USD.BLAH"].Keys.Contains(accrualEnd)); Assert.Equal(accrualEnd, s.LastSensitivityDate); Assert.Empty(s.Dependencies(null)); var s2 = (OISFuture)s.SetParRate(97); Assert.Equal(97, s2.Price); }
public double Pv(IrCurve discountCurve, IrCurve forecastCurve, bool updateState, bool updateDF, bool updateEstimate) { var totalPV = 0.0; if (FlowScheduleFra.Flows.Count != 1) { throw new InvalidOperationException("FRA should have a sinlge flow"); } var flow = FlowScheduleFra.Flows.Single(); var s = flow.AccrualPeriodStart; var e = flow.AccrualPeriodEnd; double FV, DF; if (updateEstimate) { var RateFix = flow.FixedRateOrMargin; var RateFloat = forecastCurve.GetForwardRate(s, e, RateType.Linear, Basis); var YF = flow.NotionalByYearFraction; FV = ((RateFloat - RateFix) * YF) / (1 + RateFloat * YF) * flow.Notional; FV *= (PayRec == SwapPayReceiveType.Payer) ? 1.0 : -1.0; } else { FV = flow.Fv; } if (updateDF) { DF = discountCurve.Pv(1.0, flow.SettleDate); } else { DF = flow.Pv / flow.Fv; } totalPV = discountCurve.Pv(FV, flow.SettleDate); if (!updateState) { return(totalPV); } flow.Fv = FV; flow.Pv = totalPV; return(totalPV); }
public static double PV(this CashFlowSchedule schedule, IrCurve discountCurve, IrCurve forecastCurve, bool updateState, bool updateDf, bool updateEstimate, DayCountBasis basisFloat, DateTime?filterDate) { double totalPv = 0; for (var i = 0; i < schedule.Flows.Count; i++) { var flow = schedule.Flows[i]; if (filterDate.HasValue && flow.SettleDate < filterDate.Value) { continue; } double fv, pv, df; switch (flow.FlowType) { case FlowType.FixedRate: { if (updateState) { var rateLin = flow.FixedRateOrMargin; var yf = flow.YearFraction; fv = rateLin * yf * flow.Notional; } else { fv = flow.Fv; } if (updateDf) { df = discountCurve.Pv(1, flow.SettleDate); } else { df = flow.Fv == flow.Pv ? 1.0 : flow.Pv / flow.Fv; } pv = fv * df; totalPv += pv; if (updateState) { flow.Fv = fv; flow.Pv = pv; } break; } case FlowType.FloatRate: { if (updateEstimate) { var s = flow.AccrualPeriodStart; var e = flow.AccrualPeriodEnd; var rateLin = forecastCurve.GetForwardRate(s, e, RateType.Linear, basisFloat); rateLin += flow.FixedRateOrMargin; var yf = flow.YearFraction; fv = rateLin * yf * flow.Notional; } else { fv = flow.Fv; } if (updateDf) { df = discountCurve.Pv(1, flow.SettleDate); } else { df = flow.Fv == flow.Pv ? 1.0 : flow.Pv / flow.Fv; } pv = fv * df; totalPv += pv; if (updateState) { flow.Fv = fv; flow.Pv = pv; } break; } case FlowType.FixedAmount: { fv = flow.Notional; if (updateDf) { df = discountCurve.Pv(1, flow.SettleDate); } else { df = flow.Fv == flow.Pv ? 1.0 : flow.Pv / flow.Fv; } pv = fv * df; totalPv += pv; if (updateState) { flow.Fv = fv; flow.Pv = pv; } break; } } } return(totalPv); }
private double PV(IrCurve discountCurve, IrCurve forecastCurve, bool updateState, bool updateDf, bool updateEstimate) { double totalPv = 0; for (var i = 0; i < FlowScheduleFixed.Flows.Count; i++) { var flow = FlowScheduleFixed.Flows[i]; double fv, df; if (updateState) { var rateLin = flow.FixedRateOrMargin; var yf = flow.NotionalByYearFraction; fv = rateLin * yf * flow.Notional; } else { fv = flow.Fv; } if (updateDf) { df = discountCurve.Pv(1, flow.SettleDate); } else { df = flow.Fv == flow.Pv ? 1.0 : flow.Pv / flow.Fv; } var pv = fv * df; totalPv += pv; if (updateState) { flow.Fv = fv; flow.Pv = pv; } } for (var i = 0; i < FlowScheduleFloat.Flows.Count; i++) { var flow = FlowScheduleFloat.Flows[i]; double fv, df; if (updateEstimate) { var s = flow.AccrualPeriodStart; var e = flow.AccrualPeriodEnd; var rateLin = forecastCurve.GetForwardRate(s, e, RateType.Linear, BasisFloat); var yf = flow.NotionalByYearFraction; fv = rateLin * yf * flow.Notional; } else { fv = flow.Fv; } if (updateDf) { df = discountCurve.Pv(1, flow.SettleDate); } else { df = flow.Fv == flow.Pv ? 1.0 : flow.Pv / flow.Fv; } var pv = fv * df; totalPv += pv; if (updateState) { flow.Fv = fv; flow.Pv = pv; } } return(totalPv); }
public double Pv(IrCurve discountCurve, IrCurve forecastCurvePay, IrCurve forecastCurveRec, bool updateState, bool updateDF, bool updatePayEst, bool updateRecEst) { double totalPV = 0; for (var i = 0; i < FlowSchedulePay.Flows.Count; i++) { double FV, DF; var flow = FlowSchedulePay.Flows[i]; if (updatePayEst) { var s = flow.AccrualPeriodStart; var e = flow.AccrualPeriodEnd; var RateLin = forecastCurvePay.GetForwardRate(s, e, RateType.Linear, BasisPay) + flow.FixedRateOrMargin; var YF = flow.NotionalByYearFraction; FV = RateLin * YF * flow.Notional; } else { FV = flow.Fv; } if (updateDF) { DF = discountCurve.Pv(1, flow.SettleDate); } else { DF = (flow.Fv == flow.Pv) ? 1.0 : flow.Pv / flow.Fv; } var PV = DF * FV; if (updateState) { flow.Fv = FV; flow.Pv = PV; } totalPV += PV; } for (var i = 0; i < FlowScheduleRec.Flows.Count; i++) { double FV, DF; var flow = FlowScheduleRec.Flows[i]; if (updateRecEst) { var s = flow.AccrualPeriodStart; var e = flow.AccrualPeriodEnd; var RateLin = forecastCurveRec.GetForwardRate(s, e, RateType.Linear, BasisRec) + flow.FixedRateOrMargin; var YF = flow.NotionalByYearFraction; FV = RateLin * YF * flow.Notional; } else { FV = flow.Fv; } if (updateDF) { DF = discountCurve.Pv(1, flow.SettleDate); } else { DF = (flow.Fv == flow.Pv) ? 1.0 : flow.Pv / flow.Fv; } var PV = DF * FV; if (updateState) { flow.Fv = FV; flow.Pv = PV; } totalPV += PV; } return(totalPV); }