public static object CreateFundingModelParallel( [ExcelArgument(Description = "Funding model name")] string ObjectName, [ExcelArgument(Description = "Build date")] DateTime BuildDate, [ExcelArgument(Description = "Funding instrument collection")] string FundingInstrumentCollection, [ExcelArgument(Description = "Curve to solve stage mappings")] object SolveStages, [ExcelArgument(Description = "Fx matrix object")] object FxMatrix, [ExcelArgument(Description = "Fx vol surfaces")] object FxVolSurfaces) { return(ExcelHelper.Execute(_logger, () => { ContainerStores.GetObjectCache <FundingInstrumentCollection>().TryGetObject(FundingInstrumentCollection, out var fic); IFxMatrix fxMatrix = null; if (!(FxMatrix is ExcelMissing)) { var fxMatrixCache = ContainerStores.GetObjectCache <FxMatrix>(); fxMatrix = fxMatrixCache.GetObject((string)FxMatrix).Value; } var stageDict = fic.Value.ImplySolveStages2(fxMatrix); var emptyCurves = fic.Value.ImplyContainedCurves(BuildDate, Interpolator1DType.LinearFlatExtrap); var model = new FundingModel(BuildDate, emptyCurves.Values.ToArray(), ContainerStores.CurrencyProvider, ContainerStores.CalendarProvider); if (!(FxMatrix is ExcelMissing)) { model.SetupFx(fxMatrix); } if (!(FxVolSurfaces is ExcelMissing)) { IEnumerable <IVolSurface> surfaces = null; if (FxVolSurfaces is string vsStr) { surfaces = (new object[] { vsStr }).GetAnyFromCache <IVolSurface>(); } else { surfaces = ((object[, ])FxVolSurfaces).GetAnyFromCache <IVolSurface>(); } if (surfaces.Any()) { model.VolSurfaces = surfaces.ToDictionary(k => k.Name, v => v); } } if (fic != null) { var calibrator = new NewtonRaphsonMultiCurveSolverStaged() { InLineCurveGuessing = true }; calibrator.Solve(model, fic.Value, stageDict); } return ExcelHelper.PushToCache <IFundingModel>(model, ObjectName); })); }
public static ICube BenchmarkRisk(this IPvModel pvModel, FundingInstrumentCollection riskCollection, ICurrencyProvider currencyProvider, Currency reportingCcy) { var cube = new ResultCube(); var dataTypes = new Dictionary <string, Type> { { "TradeId", typeof(string) }, { "TradeType", typeof(string) }, { "Curve", typeof(string) }, { "RiskDate", typeof(DateTime) }, { "Benchmark", typeof(string) }, { "Metric", typeof(string) }, { "Units", typeof(string) }, { "BumpSize", typeof(double) }, }; cube.Initialize(dataTypes); //var lastDate = pvModel.Portfolio.LastSensitivityDate; var insByCurve = riskCollection.GroupBy(x => x.SolveCurve); var dependencies = riskCollection.FindDependenciesInverse(pvModel.VanillaModel.FundingModel.FxMatrix); var lastDateByCurve = insByCurve.ToDictionary(x => x.Key, x => DateTime.MinValue); foreach (var ins in pvModel.Portfolio.UnWrapWrappers().Instruments) { if (ins is IFundingInstrument fins) { var cvs = fins.Dependencies(pvModel.VanillaModel.FundingModel.FxMatrix); foreach (var c in cvs) { if (!lastDateByCurve.ContainsKey(c)) { lastDateByCurve[c] = DateTime.MinValue; } lastDateByCurve[c] = lastDateByCurve[c].Max(ins.LastSensitivityDate); } } else if (ins is IAssetInstrument ains) { var cvs = ains.IrCurves(pvModel.VanillaModel); foreach (var c in cvs) { if (!lastDateByCurve.ContainsKey(c)) { lastDateByCurve[c] = DateTime.MinValue; } lastDateByCurve[c] = lastDateByCurve[c].Max(ins.LastSensitivityDate); } } } foreach (var c in lastDateByCurve.Keys.ToArray()) { if (dependencies.ContainsKey(c)) { foreach (var d in dependencies[c]) { lastDateByCurve[c] = lastDateByCurve[c].Max(lastDateByCurve[d]); } } } var insToRisk = new List <IFundingInstrument>(); foreach (var gp in insByCurve) { var lastDate = lastDateByCurve[gp.Key]; var sorted = gp.OrderBy(x => x.LastSensitivityDate).ToList(); if (sorted.Last().LastSensitivityDate <= lastDate) { insToRisk.AddRange(sorted); } else { var lastIns = sorted.First(x => x.LastSensitivityDate > lastDate); var lastIx = sorted.IndexOf(lastIns); lastIx = System.Math.Min(lastIx + 1, sorted.Count); insToRisk.AddRange(sorted.Take(lastIx)); } } var parRates = insToRisk.Select(x => x.CalculateParRate(pvModel.VanillaModel.FundingModel)).ToList(); var newIns = insToRisk.Select((x, ix) => x.SetParRate(parRates[ix])); var newFic = new FundingInstrumentCollection(currencyProvider); newFic.AddRange(newIns.OrderBy(x => x.SolveCurve).ThenBy(x => x.PillarDate)); var fModel = pvModel.VanillaModel.FundingModel.DeepClone(null); var s = new NewtonRaphsonMultiCurveSolverStaged(); s.Solve(fModel, newFic); var vModel = pvModel.VanillaModel.Clone(fModel); var newPvModel = pvModel.Rebuild(vModel, pvModel.Portfolio); //var basePVbyCurrency = new Dictionary<Currency, ICube>(); var basePV = newPvModel.PV(reportingCcy); ParallelUtils.Instance.For(0, newIns.Count(), 1, i => //for (var i = 0; i < newIns.Count(); i++) { //if (!basePVbyCurrency.TryGetValue(insToRisk[i].Currency, out var basePV)) //{ // basePV = newPvModel.PV(insToRisk[i].Currency); // basePVbyCurrency[insToRisk[i].Currency] = basePV; //} var tIdIx = basePV.GetColumnIndex("TradeId"); var tTypeIx = basePV.GetColumnIndex("TradeType"); var bumpSize = GetBumpSize(insToRisk[i]); var bumpedIns = newIns.Select((x, ix) => x.SetParRate(parRates[ix] + (ix == i ? bumpSize : 0.0))); var newFicb = new FundingInstrumentCollection(currencyProvider); newFicb.AddRange(bumpedIns); var fModelb = fModel.DeepClone(null); var sb = new NewtonRaphsonMultiCurveSolverStaged(); sb.Solve(fModelb, newFicb); var vModelb = pvModel.VanillaModel.Clone(fModelb); var newPvModelb = pvModel.Rebuild(vModelb, pvModel.Portfolio); //var bumpedPV = newPvModelb.PV(insToRisk[i].Currency); var bumpedPV = newPvModelb.PV(reportingCcy); var bumpName = insToRisk[i].TradeId; var riskDate = insToRisk[i].PillarDate; var riskCurve = insToRisk[i].SolveCurve; var riskUnits = GetRiskUnits(insToRisk[i]); var deltaCube = bumpedPV.QuickDifference(basePV); var deltaScale = GetScaleFactor(insToRisk[i], parRates[i], parRates[i] + bumpSize, fModel); var fxToCurveCcy = fModel.GetFxRate(fModel.BuildDate, reportingCcy, insToRisk[i].Currency); foreach (var dRow in deltaCube.GetAllRows()) { if (dRow.Value == 0.0) { continue; } var row = new Dictionary <string, object> { { "TradeId", dRow.MetaData[tIdIx] }, { "TradeType", dRow.MetaData[tTypeIx] }, { "Benchmark", bumpName }, { "RiskDate", riskDate }, { "Curve", riskCurve }, { "Metric", "IrBenchmarkDelta" }, { "Units", riskUnits }, { "BumpSize", bumpSize }, }; cube.AddRow(row, dRow.Value * deltaScale * fxToCurveCcy); } }).Wait(); return(cube.Sort(new List <string> { "Curve", "RiskDate", "TradeId" })); }
public static object CreateFundingModel( [ExcelArgument(Description = "Funding model name")] string ObjectName, [ExcelArgument(Description = "Build date")] DateTime BuildDate, [ExcelArgument(Description = "Funding instrument collection")] string FundingInstrumentCollection, [ExcelArgument(Description = "Curve to solve stage mappings")] object SolveStages, [ExcelArgument(Description = "Fx matrix object")] object FxMatrix, [ExcelArgument(Description = "Fx vol surfaces")] object FxVolSurfaces) { return(ExcelHelper.Execute(_logger, () => { ContainerStores.GetObjectCache <FundingInstrumentCollection>().TryGetObject(FundingInstrumentCollection, out var fic); var emptyCurves = new Dictionary <string, IrCurve>(); if (fic != null) { emptyCurves = fic.Value.ImplyContainedCurves(BuildDate, Interpolator1DType.Linear); if (!(SolveStages is ExcelMissing)) { var stageDict = ((object[, ])SolveStages).RangeToDictionary <string, int>(); foreach (var kv in stageDict) { if (emptyCurves.TryGetValue(kv.Key, out var curve)) { curve.SolveStage = kv.Value; } else { throw new Exception($"Solve stage specified for curve {kv.Key} but curve not present"); } } } } var model = new FundingModel(BuildDate, emptyCurves.Values.ToArray(), ContainerStores.CurrencyProvider, ContainerStores.CalendarProvider); if (!(FxMatrix is ExcelMissing)) { var fxMatrixCache = ContainerStores.GetObjectCache <FxMatrix>(); var fxMatrix = fxMatrixCache.GetObject((string)FxMatrix); model.SetupFx(fxMatrix.Value); } if (!(FxVolSurfaces is ExcelMissing)) { IEnumerable <IVolSurface> surfaces = null; if (FxVolSurfaces is string vsStr) { surfaces = (new object[] { vsStr }).GetAnyFromCache <IVolSurface>(); } else { surfaces = ((object[, ])FxVolSurfaces).GetAnyFromCache <IVolSurface>(); } if (surfaces.Any()) { model.VolSurfaces = surfaces.ToDictionary(k => k.Name, v => v); } } if (fic != null) { var calibrator = new NewtonRaphsonMultiCurveSolverStaged(); calibrator.Solve(model, fic.Value); } return ExcelHelper.PushToCache <IFundingModel>(model, ObjectName); })); }
public void ComplexerCurve() { var startDate = new DateTime(2016, 05, 20); Frequency[] depoTenors = { 3.Months() }; Frequency[] OISdepoTenors = { 1.Bd() }; double[] depoPricesZAR = { 0.06 }; double[] depoPricesUSD = { 0.01 }; double[] OISdepoPricesZAR = { 0.055 }; double[] OISdepoPricesUSD = { 0.009 }; string[] FRATenors = { "3x6", "6x9", "9x12", "12x15", "15x18", "18x21", "21x24" }; double[] FRAPricesZAR = { 0.065, 0.07, 0.075, 0.077, 0.08, 0.081, 0.082 }; double[] FRAPricesUSD = { 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018 }; Frequency[] swapTenors = { 3.Years(), 4.Years(), 5.Years(), 6.Years(), 7.Years(), 8.Years(), 9.Years(), 10.Years(), 12.Years(), 15.Years(), 20.Years(), 25.Years(), 30.Years() }; double[] swapPricesZAR = { 0.08, 0.083, 0.085, 0.087, 0.089, 0.091, 0.092, 0.093, 0.094, 0.097, 0.099, 0.099, 0.099 }; double[] swapPricesUSD = { 0.017, 0.018, 0.019, 0.020, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.03 }; Frequency[] oisTenors = { 3.Months(), 6.Months(), 1.Years(), 18.Months(), 2.Years(), 3.Years(), 4.Years(), 5.Years(), 6.Years(), 7.Years(), 8.Years(), 9.Years(), 10.Years(), 12.Years(), 15.Years(), 20.Years(), 25.Years(), 30.Years() }; double[] oisPricesZAR = { 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004 }; double[] oisPricesUSD = { 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002 }; var fxSpot = 14.0; Frequency[] fxForwardTenors = { 3.Months(), 6.Months(), 1.Years(), 18.Months(), 2.Years(), 3.Years() }; double[] fxForwardPrices = { 14.10, 14.20, 14.40, 14.60, 14.80, 15.20 }; Frequency[] xcySwapTenors = { 4.Years(), 5.Years(), 6.Years(), 7.Years(), 8.Years(), 9.Years(), 10.Years(), 12.Years(), 15.Years(), 20.Years(), 25.Years(), 30.Years() }; double[] xcySwapPrices = { 0.0055, 0.0050, 0.0045, 0.0040, 0.0035, 0.0030, 0.0025, 0.0020, 0.0015, 0.0010, 0.0005, 0.0000 }; var ZARpillarDatesDepo = depoTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesFRA = FRATenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, new Frequency(x.Split('x')[1] + "M"))).ToArray(); var ZARpillarDatesSwap = swapTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDates3m = ZARpillarDatesDepo.Union(ZARpillarDatesSwap).Union(ZARpillarDatesFRA).Distinct().OrderBy(x => x).ToArray(); var ZARpillarDatesDepoOIS = OISdepoTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesOISSwap = oisTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesOIS = ZARpillarDatesDepoOIS.Union(ZARpillarDatesOISSwap).Distinct().OrderBy(x => x).ToArray(); var USDpillarDatesDepo = depoTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesFRA = FRATenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, new Frequency(x.Split('x')[1] + "M"))).ToArray(); var USDpillarDatesSwap = swapTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDates3m = USDpillarDatesDepo.Union(USDpillarDatesSwap).Union(USDpillarDatesFRA).Distinct().OrderBy(x => x).ToArray(); var USDpillarDatesDepoOIS = OISdepoTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesOISSwap = oisTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesOIS = USDpillarDatesDepoOIS.Union(USDpillarDatesOISSwap).Distinct().OrderBy(x => x).ToArray(); var fxForwardPillarDates = fxForwardTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var xcySwapDates = xcySwapTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var fxPillarDates = fxForwardPillarDates.Union(xcySwapDates).Distinct().OrderBy(x => x).ToArray(); var ZARswaps = new IrSwap[swapTenors.Length]; var ZARdepos = new IrSwap[depoTenors.Length]; var ZARdeposOIS = new IrSwap[OISdepoTenors.Length]; var ZARoisSwaps = new IrBasisSwap[oisTenors.Length]; var ZARFRAs = new ForwardRateAgreement[FRATenors.Length]; var USDswaps = new IrSwap[swapTenors.Length]; var USDdepos = new IrSwap[depoTenors.Length]; var USDdeposOIS = new IrSwap[OISdepoTenors.Length]; var USDoisSwaps = new IrBasisSwap[oisTenors.Length]; var USDFRAs = new ForwardRateAgreement[FRATenors.Length]; var fxForwards = new FxForward[fxForwardTenors.Length]; var xcySwaps = new XccyBasisSwap[xcySwapTenors.Length]; var FIC = new FundingInstrumentCollection(TestProviderHelper.CurrencyProvider); for (var i = 0; i < FRATenors.Length; i++) { ZARFRAs[i] = new ForwardRateAgreement(startDate, FRATenors[i], FRAPricesZAR[i], _zar3m, SwapPayReceiveType.Payer, FraDiscountingType.Isda, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARFRAs[i]); USDFRAs[i] = new ForwardRateAgreement(startDate, FRATenors[i], FRAPricesUSD[i], usd3m, SwapPayReceiveType.Payer, FraDiscountingType.Isda, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDFRAs[i]); } for (var i = 0; i < oisTenors.Length; i++) { ZARoisSwaps[i] = new IrBasisSwap(startDate, oisTenors[i], oisPricesZAR[i], true, zaron, _zar3m, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.DISC.CSA_ZAR" }; FIC.Add(ZARoisSwaps[i]); USDoisSwaps[i] = new IrBasisSwap(startDate, oisTenors[i], oisPricesUSD[i], true, usdon, usd3m, "USD.LIBOR.3M", "USD.DISC.CSA_USD", "USD.DISC.CSA_USD") { SolveCurve = "USD.DISC.CSA_USD" }; FIC.Add(USDoisSwaps[i]); } for (var i = 0; i < swapTenors.Length; i++) { ZARswaps[i] = new IrSwap(startDate, swapTenors[i], _zar3m, swapPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARswaps[i]); USDswaps[i] = new IrSwap(startDate, swapTenors[i], usd3m, swapPricesUSD[i], SwapPayReceiveType.Payer, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDswaps[i]); } for (var i = 0; i < depoTenors.Length; i++) { ZARdepos[i] = new IrSwap(startDate, depoTenors[i], _zar3m, depoPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARdepos[i]); USDdepos[i] = new IrSwap(startDate, depoTenors[i], usd3m, depoPricesUSD[i], SwapPayReceiveType.Payer, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDdepos[i]); } for (var i = 0; i < OISdepoTenors.Length; i++) { ZARdeposOIS[i] = new IrSwap(startDate, OISdepoTenors[i], zaron, OISdepoPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.DISC.CSA_ZAR", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.DISC.CSA_ZAR" }; FIC.Add(ZARdeposOIS[i]); USDdeposOIS[i] = new IrSwap(startDate, OISdepoTenors[i], usdon, OISdepoPricesUSD[i], SwapPayReceiveType.Payer, "USD.DISC.CSA_USD", "USD.DISC.CSA_USD") { SolveCurve = "USD.DISC.CSA_USD" }; FIC.Add(USDdeposOIS[i]); } for (var i = 0; i < fxForwards.Length; i++) { fxForwards[i] = new FxForward { SolveCurve = "ZAR.DISC.CSA_USD", DeliveryDate = fxForwardPillarDates[i], DomesticCCY = ccyUsd, ForeignCCY = ccyZar, DomesticQuantity = 1e6 / fxForwardPrices[i], Strike = fxForwardPrices[i], ForeignDiscountCurve = "ZAR.DISC.CSA_USD", }; FIC.Add(fxForwards[i]); } for (var i = 0; i < xcySwapTenors.Length; i++) { xcySwaps[i] = new XccyBasisSwap(startDate, xcySwapTenors[i], xcySwapPrices[i], true, usd3m, _zar3m, ExchangeType.Both, MTMSwapType.ReceiveNotionalFixed, "USD.LIBOR.3M", "ZAR.JIBAR.3M", "USD.DISC.CSA_USD", "ZAR.DISC.CSA_USD") { SolveCurve = "ZAR.DISC.CSA_USD" }; FIC.Add(xcySwaps[i]); } var ZARcurve3m = new IrCurve(ZARpillarDates3m, new double[ZARpillarDates3m.Length], startDate, "ZAR.JIBAR.3M", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var ZARcurveOIS = new IrCurve(ZARpillarDatesOIS, new double[ZARpillarDatesOIS.Length], startDate, "ZAR.DISC.CSA_ZAR", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var USDcurve3m = new IrCurve(USDpillarDates3m, new double[USDpillarDates3m.Length], startDate, "USD.LIBOR.3M", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var USDcurveOIS = new IrCurve(USDpillarDatesOIS, new double[USDpillarDatesOIS.Length], startDate, "USD.DISC.CSA_USD", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var fxCurve = new IrCurve(fxPillarDates, new double[fxPillarDates.Length], startDate, "ZAR.DISC.CSA_USD", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 2 }; var engine = new FundingModel(startDate, new IrCurve[] { ZARcurve3m, ZARcurveOIS, USDcurve3m, USDcurveOIS, fxCurve }, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider); var fxMatrix = new FxMatrix(TestProviderHelper.CurrencyProvider); var spotRates = new Dictionary <Currency, double> { { ccyZar, fxSpot } }; var fxPairs = new List <FxPair> { new FxPair { Domestic = ccyUsd, Foreign = ccyZar, SettlementCalendar = _usd, SpotLag = new Frequency("2b") } }; var discountMap = new Dictionary <Currency, string> { { ccyUsd, "USD.DISC.CSA_USD" }, { ccyZar, "ZAR.DISC.CSA_USD" }, }; fxMatrix.Init(ccyUsd, startDate, spotRates, fxPairs, discountMap); engine.SetupFx(fxMatrix); var S = new NewtonRaphsonMultiCurveSolverStaged() { Tollerance = IsCoverageOnly ? 1 : 0.00000001, MaxItterations = IsCoverageOnly ? 1 : 100, }; S.Solve(engine, FIC); if (!IsCoverageOnly) { foreach (var ins in FIC) { var pv = ins.Pv(engine, false); Assert.Equal(0.0, pv, 7); } } }
public void ComplexCurve() { var startDate = new DateTime(2016, 05, 20); var depoTenors = new Frequency[] { 3.Months() }; var OISdepoTenors = new Frequency[] { 1.Bd() }; double[] depoPricesZAR = { 0.06 }; double[] depoPricesUSD = { 0.01 }; double[] OISdepoPricesZAR = { 0.055 }; double[] OISdepoPricesUSD = { 0.009 }; string[] FRATenors = { "3x6", "6x9", "9x12", "12x15", "15x18", "18x21", "21x24" }; double[] FRAPricesZAR = { 0.065, 0.07, 0.075, 0.077, 0.08, 0.081, 0.082 }; double[] FRAPricesUSD = { 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018 }; Frequency[] swapTenors = { 3.Years(), 4.Years(), 5.Years(), 6.Years(), 7.Years(), 8.Years(), 9.Years(), 10.Years(), 12.Years(), 15.Years(), 20.Years(), 25.Years(), 30.Years() }; double[] swapPricesZAR = { 0.08, 0.083, 0.085, 0.087, 0.089, 0.091, 0.092, 0.093, 0.094, 0.097, 0.099, 0.099, 0.099 }; double[] swapPricesUSD = { 0.017, 0.018, 0.019, 0.020, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026, 0.027, 0.028, 0.03 }; Frequency[] oisTenors = { 3.Months(), 6.Months(), 1.Years(), 18.Months(), 2.Years(), 3.Years(), 4.Years(), 5.Years(), 6.Years(), 7.Years(), 8.Years(), 9.Years(), 10.Years(), 12.Years(), 15.Years(), 20.Years(), 25.Years(), 30.Years() }; double[] oisPricesZAR = { 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004 }; double[] oisPricesUSD = { 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002 }; var ZARpillarDatesDepo = depoTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesFRA = FRATenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, new Frequency(x.Split('x')[1] + "M"))).ToArray(); var ZARpillarDatesSwap = swapTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDates3m = ZARpillarDatesDepo.Union(ZARpillarDatesSwap).Union(ZARpillarDatesFRA).Distinct().OrderBy(x => x).ToArray(); var ZARpillarDatesDepoOIS = OISdepoTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesOISSwap = oisTenors.Select(x => startDate.AddPeriod(RollType.MF, JHB, x)).ToArray(); var ZARpillarDatesOIS = ZARpillarDatesDepoOIS.Union(ZARpillarDatesOISSwap).Distinct().OrderBy(x => x).ToArray(); var USDpillarDatesDepo = depoTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesFRA = FRATenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, new Frequency(x.Split('x')[1] + "M"))).ToArray(); var USDpillarDatesSwap = swapTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDates3m = USDpillarDatesDepo.Union(USDpillarDatesSwap).Union(USDpillarDatesFRA).Distinct().OrderBy(x => x).ToArray(); var USDpillarDatesDepoOIS = OISdepoTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesOISSwap = oisTenors.Select(x => startDate.AddPeriod(RollType.MF, _usd, x)).ToArray(); var USDpillarDatesOIS = USDpillarDatesDepoOIS.Union(USDpillarDatesOISSwap).Distinct().OrderBy(x => x).ToArray(); var ZARswaps = new IrSwap[swapTenors.Length]; var ZARdepos = new IrSwap[depoTenors.Length]; var ZARdeposOIS = new IrSwap[OISdepoTenors.Length]; var ZARoisSwaps = new IrBasisSwap[oisTenors.Length]; var ZARFRAs = new ForwardRateAgreement[FRATenors.Length]; var USDswaps = new IrSwap[swapTenors.Length]; var USDdepos = new IrSwap[depoTenors.Length]; var USDdeposOIS = new IrSwap[OISdepoTenors.Length]; var USDoisSwaps = new IrBasisSwap[oisTenors.Length]; var USDFRAs = new ForwardRateAgreement[FRATenors.Length]; var FIC = new FundingInstrumentCollection(TestProviderHelper.CurrencyProvider); for (var i = 0; i < FRATenors.Length; i++) { ZARFRAs[i] = new ForwardRateAgreement(startDate, FRATenors[i], FRAPricesZAR[i], _zar3m, SwapPayReceiveType.Payer, FraDiscountingType.Isda, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARFRAs[i]); USDFRAs[i] = new ForwardRateAgreement(startDate, FRATenors[i], FRAPricesUSD[i], usd3m, SwapPayReceiveType.Payer, FraDiscountingType.Isda, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDFRAs[i]); } for (var i = 0; i < oisTenors.Length; i++) { ZARoisSwaps[i] = new IrBasisSwap(startDate, oisTenors[i], oisPricesZAR[i], true, zaron, _zar3m, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.DISC.CSA_ZAR" }; FIC.Add(ZARoisSwaps[i]); USDoisSwaps[i] = new IrBasisSwap(startDate, oisTenors[i], oisPricesUSD[i], true, usdon, usd3m, "USD.LIBOR.3M", "USD.DISC.CSA_USD", "USD.DISC.CSA_USD") { SolveCurve = "USD.DISC.CSA_USD" }; FIC.Add(USDoisSwaps[i]); } for (var i = 0; i < swapTenors.Length; i++) { ZARswaps[i] = new IrSwap(startDate, swapTenors[i], _zar3m, swapPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARswaps[i]); USDswaps[i] = new IrSwap(startDate, swapTenors[i], usd3m, swapPricesUSD[i], SwapPayReceiveType.Payer, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDswaps[i]); } for (var i = 0; i < depoTenors.Length; i++) { ZARdepos[i] = new IrSwap(startDate, depoTenors[i], _zar3m, depoPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.JIBAR.3M", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.JIBAR.3M" }; FIC.Add(ZARdepos[i]); USDdepos[i] = new IrSwap(startDate, depoTenors[i], usd3m, depoPricesUSD[i], SwapPayReceiveType.Payer, "USD.LIBOR.3M", "USD.DISC.CSA_USD") { SolveCurve = "USD.LIBOR.3M" }; FIC.Add(USDdepos[i]); } for (var i = 0; i < OISdepoTenors.Length; i++) { ZARdeposOIS[i] = new IrSwap(startDate, OISdepoTenors[i], zaron, OISdepoPricesZAR[i], SwapPayReceiveType.Payer, "ZAR.DISC.CSA_ZAR", "ZAR.DISC.CSA_ZAR") { SolveCurve = "ZAR.DISC.CSA_ZAR" }; FIC.Add(ZARdeposOIS[i]); USDdeposOIS[i] = new IrSwap(startDate, OISdepoTenors[i], usdon, OISdepoPricesUSD[i], SwapPayReceiveType.Payer, "USD.DISC.CSA_USD", "USD.DISC.CSA_USD") { SolveCurve = "USD.DISC.CSA_USD" }; FIC.Add(USDdeposOIS[i]); } var ZARcurve3m = new IrCurve(ZARpillarDates3m, new double[ZARpillarDates3m.Length], startDate, "ZAR.JIBAR.3M", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var ZARcurveOIS = new IrCurve(ZARpillarDatesOIS, new double[ZARpillarDatesOIS.Length], startDate, "ZAR.DISC.CSA_ZAR", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var USDcurve3m = new IrCurve(USDpillarDates3m, new double[USDpillarDates3m.Length], startDate, "USD.LIBOR.3M", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var USDcurveOIS = new IrCurve(USDpillarDatesOIS, new double[USDpillarDatesOIS.Length], startDate, "USD.DISC.CSA_USD", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var engine = new FundingModel(startDate, new IrCurve[] { ZARcurve3m, ZARcurveOIS, USDcurve3m, USDcurveOIS }, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider); var ZARcurve3m0 = new IrCurve(ZARpillarDates3m, new double[ZARpillarDates3m.Length], startDate, "ZAR.JIBAR.3M", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var ZARcurveOIS0 = new IrCurve(ZARpillarDatesOIS, new double[ZARpillarDatesOIS.Length], startDate, "ZAR.DISC.CSA_ZAR", Interpolator1DType.LinearFlatExtrap, ccyZar) { SolveStage = 0 }; var USDcurve3m0 = new IrCurve(USDpillarDates3m, new double[USDpillarDates3m.Length], startDate, "USD.LIBOR.3M", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var USDcurveOIS0 = new IrCurve(USDpillarDatesOIS, new double[USDpillarDatesOIS.Length], startDate, "USD.DISC.CSA_USD", Interpolator1DType.LinearFlatExtrap, ccyUsd) { SolveStage = 1 }; var engine0 = new FundingModel(startDate, new IrCurve[] { ZARcurve3m0, ZARcurveOIS0, USDcurve3m0, USDcurveOIS0 }, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider); var S = new NewtonRaphsonMultiCurveSolverStagedWithAnalyticJacobian() { Tollerance = IsCoverageOnly ? 1 : 0.00000001, MaxItterations = IsCoverageOnly ? 1 : 100, }; var S0 = new NewtonRaphsonMultiCurveSolverStaged() { Tollerance = IsCoverageOnly ? 1 : 0.00000001, MaxItterations = IsCoverageOnly ? 1 : 100, }; S.Solve(engine, FIC); S0.Solve(engine0, FIC); if (!IsCoverageOnly) { foreach (var ins in FIC) { var pv = ins.Pv(engine, false); Assert.Equal(0.0, pv, 7); } foreach (var curve in engine.Curves) { var otherCurve = engine0.Curves[curve.Key]; Assert.Equal(curve.Value.NumberOfPillars, otherCurve.NumberOfPillars); var otherRates = otherCurve.GetRates(); var rates = curve.Value.GetRates(); for (var i = 0; i < otherRates.Length; i++) { Assert.Equal(otherRates[i], rates[i], 10); } } } }