public static SortedDictionary<DateTime, double> GetRepoOISSpread(this ICarbonClient client, BondAnalytics.Country country, List<DateTime> asOfDate, List<DateTime> holidays) { // Not the most efficient function, but split out from original object o = null; int nDates = asOfDate.Count; //double[,] result = new double[nDates, 2]; //result[0, 0] = -1.0; var discCurves = new SortedDictionary<DateTime, Tuple<DateTime, double>[]>(); var spreads = new SortedDictionary<DateTime, double>(); var result = new SortedDictionary<DateTime, double>(); int nAvDates = 20; string ccy = getRepoCCYFromCountry(country); if (ccy == null) { // This country hasn't been configured yet. return result; } var datelist = new List<DateTime>(); for (var k = 0; k < nDates; k++) { var dateSeries = new List<DateTime> { asOfDate[k] }; for (var i = 1; i < nAvDates; i++) { dateSeries.Add(BondAnalytics.PrevBusDay(dateSeries.Last().AddDays(-1), holidays)); } datelist.AddRange(dateSeries); } datelist = datelist.Distinct().ToList(); var curvesResult = client.BulkGetHistoricEodDiscountCurves(datelist, ccy, true); var gcRatesResult = GetGcRates(client, country, datelist); for (int k = 0; k < nDates; k++) { List<DateTime> dateSeries = new List<DateTime> { asOfDate[k] }; // Need 20 business days prior to asOfDate[k] for (int i = 1; i < nAvDates; i++) { dateSeries.Add(BondAnalytics.PrevBusDay(dateSeries.Last().AddDays(-1), holidays)); } // Need discount curves for each date. May already have them. for (int i = 0; i < nAvDates; i++) { if (!discCurves.ContainsKey(dateSeries[i])) { DiscountCurve curve; curvesResult.TryGetValue(dateSeries[i], out curve); if (curve != null) discCurves.Add(dateSeries[i], curve.AsTuples()); } } // Need repo spread history for each date. May already have it. // If US then use Nomura data, otherwise use ICAP via Carbon // var gmcrProvider = new GenericPricePropertyProvider("gcmr", 1M); for (int i = 0; i < nAvDates; i++) { if (spreads.ContainsKey(dateSeries[i])) continue; double scaleFactor = 0.01; if (country == BondAnalytics.Country.US) { try { double value; if (gcRatesResult.TryGetValue(dateSeries[i], out value)) { o = value; } scaleFactor = 1.0; } catch { // Missing data } } else if (country == BondAnalytics.Country.DE) { try { o = client.GetCbnTimeSeriesDataCell("GC_GERMAN_SUB_10YR", "eod-icaprepo", dateSeries[i], "wtdRate", new Dictionary<string, string> { { "term", "T-N" } }); } catch { // Missing data } } else if (country == BondAnalytics.Country.FR) { try { o = client.GetCbnTimeSeriesDataCell("GC_FRANCE_FIXED_SUB_10YR", "eod-icaprepo", dateSeries[i], "wtdRate", new Dictionary<string, string> { { "term", "T-N" } }); } catch { // Missing data } } else if (country == BondAnalytics.Country.IT) { try { o = client.GetCbnTimeSeriesDataCell("GC_ITALY_CCP_ALL_BONDS", "eod-icaprepo", dateSeries[i], "wtdRate"); } catch { // Missing data } } else if (country == BondAnalytics.Country.ES) { try { o = client.GetCbnTimeSeriesDataCell("GC_CNET_SPAIN", "eod-icaprepo", dateSeries[i], "wtdRate"); } catch { // Missing data } } else if (country == BondAnalytics.Country.UK) { try { o = client.GetCbnTimeSeriesDataCell("GC_GILT_LCH", "eod-icaprepo", dateSeries[i], "wtdRate", new Dictionary<string, string> { { "term", "O" } }); } catch { // Missing data } } else if (country == BondAnalytics.Country.JP) { try { o = client.GetCbnTimeSeriesDataCell("JPYGCRate", "eod", dateSeries[i], "gcRate"); } catch { // Missing data } } if (discCurves.ContainsKey(dateSeries[i])) { spreads.Add(dateSeries[i], ((o as double?) * scaleFactor ?? 0.0) - Math.Round( (1.0 / discCurves[dateSeries[i]].ElementAt(1).Item2 - 1.0) * 360.0 / (discCurves[dateSeries[i]].ElementAt(1).Item1 - discCurves[dateSeries[i]].ElementAt(0).Item1).TotalDays, 5)); } } double repoSpread = 0.0; for (int i = 0; i < nAvDates; i++) { if (spreads.ContainsKey(dateSeries[i])) repoSpread += spreads[dateSeries[i]] / nAvDates; } //result[k, 0] = repoSpread; result[asOfDate[k]] = repoSpread; } return result; }
// Alternative that allows for an arbitrary set of forward dates public static double[,] GetRepoRate(this ICarbonClient client, BondAnalytics.Country country, List<DateTime> asOfDate, List<DateTime> forwardDates, List<DateTime> holidays, bool bCalcRate) { int nDates = asOfDate.Count; double[,] result = new double[nDates, 2]; result[0, 0] = -1.0; var discCurves = new SortedDictionary<DateTime, Tuple<DateTime, double>[]>(); //var spreads = new SortedDictionary<DateTime, double>(); int nAvDates = 20; String ccy = getRepoCCYFromCountry(country); // Check that asOfDates and forwardDates have same length if (asOfDate.Count != forwardDates.Count) return result; // Setup var datelist = new List<DateTime>(); for (var k = 0; k < nDates; k++) { var dateSeries = new List<DateTime> { asOfDate[k] }; for (var i = 1; i < nAvDates; i++) { dateSeries.Add(BondAnalytics.PrevBusDay(dateSeries.Last().AddDays(-1), holidays)); } datelist.AddRange(dateSeries); } datelist = datelist.Distinct().ToList(); var curvesResult = client.BulkGetHistoricEodDiscountCurves(datelist, ccy, true); var repoois = GetRepoOISSpread(client, country, datelist, holidays); if (repoois.Count < 0) return result; // skip if no repos // Enhance results with repo rates for (var k = 0; k < nDates; k++) { if (repoois.ContainsKey(asOfDate[k])) { // Setup spread. double repoSpread = repoois[asOfDate[k]]; result[k, 0] = repoSpread; // Setup repo rate if (bCalcRate) { // Get Curves... List<DateTime> dateSeries = new List<DateTime> { asOfDate[k] }; // Need 20 business days prior to asOfDate[k] for (int i = 1; i < nAvDates; i++) { dateSeries.Add(BondAnalytics.PrevBusDay(dateSeries.Last().AddDays(-1), holidays)); } // Need discount curves for each date. May already have them. for (int i = 0; i < nAvDates; i++) { if (!discCurves.ContainsKey(dateSeries[i])) { DiscountCurve curve; curvesResult.TryGetValue(dateSeries[i], out curve); if (curve != null) discCurves.Add(dateSeries[i], curve.AsTuples()); } } // Calc repo rate double oisSwap = -1.0; // Have already caught the case of missing discount curve above. if (discCurves.ContainsKey(asOfDate[k])) { DateTime[] discDfDates = discCurves[asOfDate[k]].Select(x => x.Item1).ToArray(); double[] discDfs = discCurves[asOfDate[k]].Select(x => x.Item2).ToArray(); BondAnalytics.DayCountType oisDct = (country == BondAnalytics.Country.CA || country == BondAnalytics.Country.UK ? BondAnalytics.DayCountType.Act365 : BondAnalytics.DayCountType.Act360); oisSwap = asOfDate[k] < forwardDates[k] ? BondAnalytics.CalcMMS(asOfDate[k], forwardDates[k], oisDct, 12, 12, discDfDates, discDfs, discDfDates, discDfs, holidays, null, null, null, null, null, DateTime.MinValue, 5) : 0.0; } double repoRate = (oisSwap > -1.0 ? oisSwap + repoSpread : -1.0); result[k, 1] = repoRate; } } } return result; }
// Compute repo rates based on an input repo-ois spread public static double[,] CalcRepoRatesFromOisSpread(this ICarbonClient client, Series<DateTime, double> repoSpdSrs, BondAnalytics.Country country, List<DateTime> asOfDate, List<DateTime> forwardDates, List<DateTime> holidays, Dictionary<DateTime, Tuple<DateTime, double>[]> discCurves = null) { // Init var holSet = new HashSet<DateTime>(holidays); var ccy = getRepoCCYFromCountry(country); // Checks if (asOfDate.Count != forwardDates.Count) { throw new ArgumentException("#Error: as of dates and forward dates need to have the same length!"); } // Get swap curves if not specified if (discCurves == null) { discCurves = new Dictionary<DateTime, Tuple<DateTime, double>[]>(); var rawCurves = client.BulkGetHistoricEodDiscountCurves(asOfDate, ccy, true); foreach (var kvp in rawCurves) { discCurves[kvp.Key] = kvp.Value.AsTuples(); } } // Get Results double[,] results = new double[asOfDate.Count, 2]; for (int i = 0; i < asOfDate.Count; ++i) { var dte = asOfDate[i]; var fwddte = forwardDates[i]; var spdAttempt = repoSpdSrs.TryGet(dte); double repoRate; double repoSpread; if (spdAttempt.HasValue && !holSet.Contains(dte)) { // Calc repo rate repoSpread = spdAttempt.Value; double oisSwap = double.NaN; // Have already caught the case of missing discount curve above. if (discCurves.ContainsKey(dte)) { var tups = discCurves[dte]; DateTime[] discDfDates = tups.Select(x => x.Item1).ToArray(); double[] discDfs = tups.Select(x => x.Item2).ToArray(); BondAnalytics.DayCountType oisDct = (country == BondAnalytics.Country.CA || country == BondAnalytics.Country.UK ? BondAnalytics.DayCountType.Act365 : BondAnalytics.DayCountType.Act360); oisSwap = dte < fwddte ? BondAnalytics.CalcMMS(dte, fwddte, oisDct, 12, 12, discDfDates, discDfs, discDfDates, discDfs, holidays, null, null, null, null, null, DateTime.MinValue, 5) : double.NaN; } repoRate = double.IsNaN(oisSwap) ? double.NaN : oisSwap + repoSpread; } else { repoRate = double.NaN; repoSpread = double.NaN; } results[i, 0] = repoSpread; results[i, 1] = repoRate; } return results; }