//------------------------------------------------------------------------------------------------ public SpreadSeriesBuilder(string metric, FuturesSeriesBuilder rawfuturesBuilder, SwapCurveSeriesBuilder swapBuilder, Dictionary<string, TimeSeriesBondStatic> bondStatics, SpreadConventions conventions, List<DateTime> holidays=null) //------------------------------------------------------------------------------------------------ { if (holidays == null) { holidays = new List<DateTime>(); } // Setup Everything var futuresBuilder = new FuturesSeriesBuilder(rawfuturesBuilder); //use copy constructor FuturesPrices = futuresBuilder.RawFuturesPrices; FuturesStatic = futuresBuilder.FuturesStatic; BondStatic = bondStatics; CombinedStatic = SpreadSeriesBuilder.combineFuturesAndBondStatic(BondStatic, FuturesStatic); if (conventions.bForecastCurve) { ForecastCurves = swapBuilder.ForecastCurves; DiscountCurves = swapBuilder.DiscountCurves; } else { ForecastCurves = swapBuilder.DiscountCurves; DiscountCurves = swapBuilder.DiscountCurves; } SpreadMetric_ = metric; Conv_ = conventions; Holidays_ = holidays; var rawSpreads = computeFuturesSpreads(); // Now use this to get rolling futures too futuresBuilder.RawFuturesPrices = rawSpreads; futuresBuilder.interpolateRawPriceFrame(); SpreadValues = futuresBuilder.getCombinedResults(); FuturesBuilder_ = futuresBuilder; }
//------------------------------------------------------------------------------------------------ public static double calcFwdBondMeasure(string measure, AnalyticsBondStaticData bondstatic, double fwdPrice, DateTime asofDate, DateTime settle, SpreadConventions convs, SortedDictionary<DateTime, Tuple<DateTime,double>[]> ForecastCurves, SortedDictionary<DateTime, Tuple<DateTime, double>[]> DiscountCurves, List<DateTime> hols, Tuple<DateTime, double> previous = null) //------------------------------------------------------------------------------------------------ { // Cast forecast and discount curves var newForecastCurves = new SortedDictionary<DateTime, DiscountFactors>( ForecastCurves.ToDictionary(kvp => kvp.Key, kvp => new DiscountFactors(kvp.Value))); var newDiscountCurves = new SortedDictionary<DateTime, DiscountFactors>( DiscountCurves.ToDictionary(kvp => kvp.Key, kvp => new DiscountFactors(kvp.Value))); // Run them through original code return calcFwdBondMeasure(measure,bondstatic,fwdPrice,asofDate,settle,convs,newForecastCurves,newDiscountCurves,hols,previous); }
//------------------------------------------------------------------------------------------------ public static double calcFwdBondMeasure(string measure, AnalyticsBondStaticData bondstatic, double fwdPrice, DateTime asofDate, DateTime settle, SpreadConventions convs, SortedDictionary<DateTime,DiscountFactors> ForecastCurves, SortedDictionary<DateTime, DiscountFactors> DiscountCurves, List<DateTime> hols, Tuple<DateTime,double> previous = null) //------------------------------------------------------------------------------------------------ { //string identifier = bondstatic.Id; // Setup Params DateTime FwdDate = settle; DateTime effectiveDate = bondstatic.EffectiveDate; DateTime firstCpnDate = bondstatic.FirstCouponDate; DateTime maturity = bondstatic.MaturityDate; double coupon = bondstatic.Coupon; long bondCpnFreq = bondstatic.CpnFreq; long fixedFreq = convs.SwapFixedFrequency; long floatFreq = convs.SwapFloatFrequency; BondAnalytics.Country eCountry = bondstatic.Country; BondAnalytics.DayCountType dct = convs.DayCount; bool bOIS = !convs.bForecastCurve; int blendIdx = convs.BlendIndex; double output = double.NaN; switch (measure) { case "Yield": { output = 10000.0 * BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[0]; break; } case "TrueSpread": { if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } DiscountFactors curve = ForecastCurves[asofDate]; DateTime[] dfDates = curve.CurveDates; double[] dfs = curve.Dfs; // Check. Sometimes (holidays) the first date on the curve can be repeated, which will cause an exception in the pricer. if (dfDates[0] == dfDates[1]) { dfDates = dfDates.GetSubArray(1, dfDates.GetLength(0)).ToArray(); dfs = dfs.GetSubArray(1, dfs.GetLength(0)).ToArray(); } output = -10000.0 * BondAnalytics.SolveZSpread(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq, dfDates, dfs, hols); break; } case "MMS": { if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[asofDate]; var forecastCurve = ForecastCurves[asofDate]; DateTime[] discDfDates = discountCurve.CurveDates; DateTime[] fcstDfDates = forecastCurve.CurveDates; double[] discDfs = discountCurve.Dfs; double[] fcstDfs = forecastCurve.Dfs; //double mms = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); var mms = SwapAnalytics.CalcSwapRate(FwdDate, maturity, 0.0, dct, fixedFreq, dct, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, hols, 0.0, blendIdx, bOIS ? blendIdx : 0); output = 10000.0 * mms; break; } case "Spread": { if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[asofDate]; var forecastCurve = ForecastCurves[asofDate]; DateTime[] discDfDates = discountCurve.CurveDates; DateTime[] fcstDfDates = forecastCurve.CurveDates; double[] discDfs = discountCurve.Dfs; double[] fcstDfs = forecastCurve.Dfs; var mms = SwapAnalytics.CalcSwapRate(FwdDate, maturity, 0.0, dct, fixedFreq, dct, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, hols, 0.0, blendIdx, bOIS ? blendIdx : 0); double yield = 0.0; yield = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[0]; output = 10000.0 * (mms - yield); break; } case "FuturesDV01": { double previous_price = double.NaN; if (previous != null) { previous_price = previous.Item2; } // Get the CTD Bond DV01 here double dv01 = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[1] / 1000000 * 100; // Get next price output = dv01; break; } case "MMSDV01": { // Setup current swap curve if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[asofDate]; var forecastCurve = ForecastCurves[asofDate]; double rate = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); // Get Current DV01 double dv01 = SwapAnalytics.CalcSwapDv01(FwdDate, maturity, 1, rate, dct, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // DV01 adjusted PnL output = dv01 * 100; // 100 Notional Terms here break; } case "FuturesPnlDV01Adj": { double previous_fwdprice = double.NaN; if (previous != null) { previous_fwdprice = previous.Item2; } // Get the CTD Bond DV01 here double dv01 = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[1] / 1000000 * 100; // Get next price output = (fwdPrice - previous_fwdprice) / Math.Abs(dv01); //Normalise into 100 par terms break; } case "FuturesPnl": { double previous_fwdprice = double.NaN; if (previous != null) { previous_fwdprice = previous.Item2; } // PnL in notional terms output = fwdPrice - previous_fwdprice; // Actual pnl is given by price change of the CTD bond break; } case "SwapPnl": { // Previous date, curve to get original MMS rate DateTime previousDate = DateTime.MinValue; if (previous != null) { previousDate = previous.Item1; } if (!ForecastCurves.ContainsKey(previousDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[previousDate]; var forecastCurve = ForecastCurves[previousDate]; double previouRate = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); previouRate *= 100; // For cents // Setup current swap curve if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } discountCurve = DiscountCurves[asofDate]; forecastCurve = ForecastCurves[asofDate]; // Get PnL of rate //priceSwap(DateTime startDate, DateTime endDate, int payRec, double fixedRate, BondAnalytics.DayCountType fixedDctType, long fixedFreq, double floatSpread, BondAnalytics.DayCountType floatDctType, long floatFreq, DateTime[] discCurveDates, double[] discDfs, DateTime[] fcstCurveDates, double[] fcstDfs, List<DateTime> holidays, double lastFixing = 0.0, int blendIndexD = 0, int blendIndexF = 0, bool incPrin = false) double pnl = SwapAnalytics.PriceSwap(FwdDate, maturity, 1, previouRate, dct, fixedFreq, 0.0, dct, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // Raw PnL innotional terms output = pnl * 100; // pnl in cents break; } case "SwapPnlDV01Adj": { // Previous date, curve to get original MMS rate DateTime previousDate = DateTime.MinValue; if (previous != null) { previousDate = previous.Item1; } if (!ForecastCurves.ContainsKey(previousDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[previousDate]; var forecastCurve = ForecastCurves[previousDate]; double previousRate = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); previousRate *= 100; // To put this into cents // Setup current swap curve if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } discountCurve = DiscountCurves[asofDate]; forecastCurve = ForecastCurves[asofDate]; // Get PnL of rate double pnl = SwapAnalytics.PriceSwap(FwdDate, maturity, 1, previousRate, dct, fixedFreq, 0.0, dct, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // Get Current DV01 double dv01 = SwapAnalytics.CalcSwapDv01(FwdDate, maturity, 1, previousRate, dct, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // DV01 adjusted PnL output = pnl / Math.Abs(dv01); // 100 Notional Terms here break; } case "SpreadPnlDV01Adj": { // FUTURES. double previous_fwdprice = double.NaN; if (previous != null) { previous_fwdprice = previous.Item2; } // Get the CTD Bond DV01 here double dv01 = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[1] / 1000000 * 100; // Get next price double futures01AdjPnl = (fwdPrice - previous_fwdprice) / Math.Abs(dv01); // SWAP. // Previous date, curve to get original MMS rate DateTime previousDate = DateTime.MinValue; if (previous != null) { previousDate = previous.Item1; } if (!ForecastCurves.ContainsKey(previousDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[previousDate]; var forecastCurve = ForecastCurves[previousDate]; double previousRate = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); previousRate *= 100; // To put in cents // Setup current swap curve if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } discountCurve = DiscountCurves[asofDate]; forecastCurve = ForecastCurves[asofDate]; // Get PnL of rate double pnl = SwapAnalytics.PriceSwap(FwdDate, maturity, 1, previousRate, dct, fixedFreq, 0.0, dct, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // Get Current DV01 dv01 = SwapAnalytics.CalcSwapDv01(FwdDate, maturity, 1, previousRate, dct, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); // DV01 adjusted PnL double swap01AdjPnl = pnl / Math.Abs(dv01); // Notional Terms here output = swap01AdjPnl - futures01AdjPnl; break; } case "SpreadHedgeRatio": { // Get Bond DV01 double previous_price = double.NaN; if (previous != null) { previous_price = previous.Item2; } // Get the CTD Bond DV01 here double futuresDv01 = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[1] / 1000000;// Match futures notional (1mil notional. prices in cents) // Setup current swap curve if (!ForecastCurves.ContainsKey(asofDate)) { output = double.NaN; break; } var discountCurve = DiscountCurves[asofDate]; var forecastCurve = ForecastCurves[asofDate]; double mms = BondAnalytics.CalcMMS(FwdDate, maturity, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols, null, null, null, null, null, firstCpnDate, blendIdx); mms *= 100; // Get Swap DV01 double swapDv01 = SwapAnalytics.CalcSwapDv01(FwdDate, maturity, 1, mms, dct, dct, fixedFreq, floatFreq, discountCurve.CurveDates, discountCurve.Dfs, forecastCurve.CurveDates, forecastCurve.Dfs, hols); output = Math.Abs(futuresDv01) / Math.Abs(swapDv01); break; } } return output; }
//---------------------------------------------------------------------------------------- public static Frame<DateTime, String> GenerateInvoiceSpreadTRS( List<string> tickers, DateTime start, DateTime end, string countryCode, string pnlType = "InvoiceSpread", bool bCumulative = true, bool bOIS = true, string samplingFreq= "1b", string rollMethod = "FirstNoticeDate", string holcal = "", double notional = double.NaN, ICarbonClient client = null) //---------------------------------------------------------------------------------------- { var eRollMethod = TimeSeriesUtilities.GetRollMethods(rollMethod); var eInterpolationTypes = TimeSeriesUtilities.GetInterpolationType("None"); var eSmoothingTypes = TimeSeriesUtilities.GetSmoothingTypes("None"); // Don't smooth, doesn't make sense for PnL bool bForecastCurve = !bOIS; /* CARBON REQUIRES UTC TIME - MODIFY DATES TO ACCOMODATE */ start = new DateTime(start.Year, start.Month, start.Day, 0, 0, 0, DateTimeKind.Utc); end = new DateTime(end.Year, end.Month, end.Day, 0, 0, 0, DateTimeKind.Utc); #region cache string all_tickers = ";"; foreach (var s in tickers) all_tickers += s; string cacheKey = "GenerateInvoiceSpread" + tickers.ToString() + start.ToString() + end.ToString() + countryCode + pnlType + bCumulative.ToString() + bOIS.ToString() + samplingFreq + rollMethod + holcal + notional.ToString(); if (TimeSeriesCache.ContainsKey(cacheKey)) { return TimeSeriesCache[cacheKey]; } #endregion if (client == null) { throw new ArgumentException("No Carbon Client!"); } #region MeasureSetup string swapMeasure = ""; string futMeasure = ""; string ratio = ""; bool bDefaultNoCumulative = false; switch (pnlType) { case "InvoiceSpread": if (double.IsNaN(notional)) // work in DV01 terms { swapMeasure = "SwapPnlDV01Adj"; futMeasure = "FuturesPnlDV01Adj"; } else { swapMeasure = "SwapPnl"; futMeasure = "FuturesPnl"; //ratio = "SpreadHedgeRatio"; // required to construct the correct pnl } break; case "Futures": if (double.IsNaN(notional)) // work in DV01 terms { swapMeasure = ""; futMeasure = "FuturesPnlDV01Adj"; } else { swapMeasure = ""; futMeasure = "FuturesPnl"; } break; case "MMS": if (double.IsNaN(notional)) // work in DV01 terms { swapMeasure = "SwapPnlDV01Adj"; futMeasure = ""; } else { swapMeasure = "SwapPnl"; futMeasure = ""; } break; case "MMSDV01": swapMeasure = "MMSDV01"; futMeasure = ""; bDefaultNoCumulative = true; break; case "FuturesDV01": swapMeasure = "FuturesDV01"; futMeasure = ""; bDefaultNoCumulative = true; break; case "HedgeRatio": swapMeasure = "SpreadHedgeRatio"; futMeasure = ""; bDefaultNoCumulative = true; break; default: throw new ArgumentException(""); } #endregion #region Configs SpreadTimeSeriesConfigs config = new SpreadTimeSeriesConfigs(countryCode, !bOIS); string ccy = config.ccy; string calendarcode = (holcal != "") ? holcal : config.calendarcode; string futuresStaticMoniker = config.futuresStaticMoniker; string carbonEnv = config.carbonEnv; BondAnalytics.Country country = config.country; BondAnalytics.DayCountType dct = config.dct; long swpfixfreq = config.swpfixfreq; long swpfloatfreq = config.swpfloatfreq; long bndCouponFreq = config.bndCouponFreq; int BlendIndex = config.BlendIndex; string symForecastCurveName = config.SymForecastCurveName; string symDiscountCurveName = config.SymDiscountCurveName; List<string> contractSortOrder = config.contractSortOrder; List<DateTime> holidays = TimeSeriesUtilities.GetHolidays(calendarcode, client); #endregion var dateRange = TimeSeriesUtilities.GetAllDatesInDateime(start, end, calendarcode, client, samplingFreq); // Spread Static. SpreadConventions spreadconventions = new SpreadConventions(country, dct, swpfixfreq, swpfloatfreq, bndCouponFreq, bForecastCurve, BlendIndex); // Futures. FuturesSeriesBuilder seriesBuilder = new FuturesSeriesBuilder(tickers, dateRange, holidays, futuresStaticMoniker, client, carbonEnv, rollMthd: eRollMethod, interpType: eInterpolationTypes, contractSortOrder: contractSortOrder, smoothingType: eSmoothingTypes); // Bond Static var bndStatics = TimeSeriesUtilities.GetBondStaticsFromFuturesBuilder(seriesBuilder, config, client); // Swap Curves var curves = TimeSeriesUtilities.GetCurvesFromCarbon(dateRange, ccy, client); if (curves == null || bndStatics == null) return null; var forecastCurves = curves.Item1; var discountCurves = curves.Item2; SwapCurveSeriesBuilder swapBuilder = new SwapCurveSeriesBuilder(dateRange, symForecastCurveName, symDiscountCurveName, ccy, holidays, forecastCurves, discountCurves, client); // Generate Pnls Frame<DateTime,string> swapPnl = null; Frame<DateTime, string> futPnl = null; if (swapMeasure != "") { SpreadSeriesBuilder swapPnlBuilder = new SpreadSeriesBuilder(swapMeasure, seriesBuilder, swapBuilder, bndStatics, spreadconventions, holidays); swapPnl = swapPnlBuilder.SpreadValues; } if (futMeasure != "") { SpreadSeriesBuilder futPnlBuilder = new SpreadSeriesBuilder(futMeasure, seriesBuilder, swapBuilder, bndStatics, spreadconventions, holidays); futPnl = futPnlBuilder.SpreadValues; } // Setup pnl correctly Frame<DateTime, string> pnl; if ( (swapPnl != null) && (futPnl != null)) { // This allows it to match movements on the invoice spread chart. // Long TRS = pay fixed, long bond // Spread increases, mms increases, yield decreases -> swap/bond +ve pnl pnl = futPnl - swapPnl; } else if (swapPnl != null) { pnl = swapPnl; } else { pnl = futPnl; } // Make it cumulative if flagged, but not for hedge ratios etc if (bCumulative && !bDefaultNoCumulative) { pnl = pnl.SortRowsByKey(); // in case pnl = TimeSeriesUtilities.DeedleFrameCumsum(pnl); } //Notional Adjust this thing if (!double.IsNaN(notional) && pnlType!="HedgeRatio") { pnl *= notional/100; // Default 100 } TimeSeriesCache[cacheKey] = pnl; return pnl; }
//---------------------------------------------------------------------------------------- public static Frame<DateTime, String> GenerateRollingBondForwardSeries( List<string> tickers, DateTime start, DateTime end, string tenor, string countryCode, string measure, string holidayCode, bool bOIS = true, int optExDivDays = 0, bool bSpreadOrRepo = true, List<double> reposOrSpreads = null, ICarbonClient client = null) //---------------------------------------------------------------------------------------- { // Checks if (client == null) { throw new ArgumentException("No Carbon Client!"); } #region cache string all_tickers = ";"; foreach (var s in tickers) all_tickers += s; string allRepoOis = ""; if (reposOrSpreads != null) foreach (var s in reposOrSpreads) allRepoOis+= s; string cacheKey = "GenerateRollingBondForwardSeries" + tickers.ToString() + start.ToString() + end.ToString() + tenor + countryCode + measure + holidayCode + bOIS.ToString() + optExDivDays.ToString() + bSpreadOrRepo.ToString() + allRepoOis; if (TimeSeriesCache.ContainsKey(cacheKey)) { return TimeSeriesCache[cacheKey]; } #endregion #region Checks if (start >end) throw new ArgumentException("#Error: start date cannot be after end date"); #endregion var settings = new List<Tuple<string/*moniker*/, string/*tickercol*/, string/*pricecol*/>>(); // Get Configs foreach (var ticker in tickers) { if (ticker.Contains('.')) // it's a CTD series! { settings.Add(MonikerConfigs.getCTDMoniker(countryCode,ticker,client)); } else if (ticker.ToLower().Contains("ct")) { settings.Add(MonikerConfigs.getCTMoniker(countryCode, ticker, client)); } else { throw new ArgumentException("#Error: Invalid ticker found - " + ticker); } } #region DATA bool bHaveEverything = true; var configs = new SpreadTimeSeriesConfigs(countryCode, !bOIS); var spreadConventions = new SpreadConventions(configs); var dateRange = TimeSeriesUtilities.GetAllDatesInDateime(start, end, configs.calendarcode, client, "1b"); // Force daily sampling var fwdDates = dateRange.Select(dte => dte.AddTenor(Tenor.FromString(tenor))).ToList(); var holidays = TimeSeriesUtilities.GetHolidays(holidayCode,client); // Parcel input repo rates or spreads Series<DateTime, double> inputSrs = null; if (reposOrSpreads != null ) if (reposOrSpreads.Count != dateRange.Count && reposOrSpreads.Count != 1) { throw new ArgumentException("#Error: number of spreads or rates do not much the days in range"); } else { var sb = new SeriesBuilder<DateTime, double>(); double scale_factor = bSpreadOrRepo ? 10000 : 1; for (int i = 0; i < dateRange.Count; ++i) { if (reposOrSpreads.Count == 1) { sb.Add(dateRange[i], reposOrSpreads[0]/scale_factor); } else { sb.Add(dateRange[i], reposOrSpreads[i]/scale_factor); } } inputSrs = sb.Series; } // Swap Curves var curves = TimeSeriesUtilities.GetCurvesFromCarbon(dateRange, configs.ccy, client); if (curves == null) bHaveEverything = false; // Prices and tickers from ad-hoc persistence var frames = new Dictionary<string, Frame<DateTime, string>>(); for (int i = 0; i < tickers.Count; ++i) { var setting = settings[i]; var ticker = tickers[i]; var moniker = setting.Item1; var tickercol = setting.Item2; var pricecol = setting.Item3; var tmp_df = client.GetFrameAsync<DateTime>(moniker, "AdHocData").Result; if (tmp_df == null) { bHaveEverything = false; } else { // Extract price and ticker cols only var colsOfInterest = new Dictionary<string, Series<DateTime,object>>(); // Filter data to contain date range tmp_df = tmp_df.Where(kvp => (kvp.Key >= start) && (kvp.Key <= end)); colsOfInterest["price"] = tmp_df.GetColumn<object>(pricecol); colsOfInterest["isin"] = tmp_df.GetColumn<object>(tickercol); frames[ticker] = Frame.FromColumns(colsOfInterest); } } //Bond static var bondIsinSet = new HashSet<string>(); foreach(var kvp in frames) { var ticker = kvp.Key; var data = kvp.Value; var isins = data.GetColumn<string>("isin").Values; //isins.Select(isin => bondIsinSet.Add(isin)); foreach (string isin in isins) { bondIsinSet.Add(isin); } } var bondStatics = client.BulkGetBondStaticData( bondIsinSet.ToList()); if (curves == null || bondStatics == null ) return null; #endregion #region RepoRegion Series<DateTime, double> repoSrs = null; if (reposOrSpreads == null) { // Load default repo-OIS Spread double[,] repoRates = client.GetRepoRateFromSavedRepoOisSpread(BondAnalytics.CountryMappings[countryCode], dateRange, fwdDates, holidays); // Break out if no data if (repoRates == null) return null; var repoSrsBlder = new SeriesBuilder<DateTime, double>(); for (int i = 0; i < dateRange.Count; ++i) { repoSrsBlder.Add(dateRange[i], repoRates[i, 1]); } repoSrs = repoSrsBlder.Series; } else { // User-defined repo-OIS Spread or repo rates if (bSpreadOrRepo) { //Inputs are spreads double[,] repoRates = client.CalcRepoRatesFromOisSpread(inputSrs, BondAnalytics.CountryMappings[countryCode], dateRange, fwdDates, holidays); // Break out if no data if (repoRates == null) return null; var repoSrsBlder = new SeriesBuilder<DateTime, double>(); for (int i = 0; i < dateRange.Count; ++i) { repoSrsBlder.Add(dateRange[i], repoRates[i, 1]); } repoSrs = repoSrsBlder.Series; } else { //Inputs are repo rates repoSrs = inputSrs; } } #endregion // Calculation loop var forecastCurves = curves.Item1; var discountCurves = curves.Item2; // Overwrite forecast curve if we want OIS if (bOIS) { forecastCurves = discountCurves; } var outputs = new Dictionary<string, Series<DateTime, double>> (); foreach (string ticker in tickers) { var sb = new SeriesBuilder<DateTime, double>(); var df = frames[ticker]; var idx = df.RowKeys; var isins = df.GetColumn<string>("isin"); var prices = df.GetColumn<double>("price"); foreach (var dte in idx) { var tryisin = isins.TryGet(dte); var tryprice = prices.TryGet(dte); var tryrepo = repoSrs.TryGet(dte); if (!tryprice.HasValue || !tryisin.HasValue || !tryrepo.HasValue) continue; var isin = tryisin.Value; var price = tryprice.Value; var repo = tryrepo.Value; var fwddate = dte.AddTenor(Tenor.FromString(tenor)); var bondstatic = bondStatics[isin]; double value = double.NaN; if (measure == "Repo") { value = repo; } else { var fwdprice = BondAnalytics.CalcBondFwd(configs.country, dte, price, bondstatic.EffectiveDate, bondstatic.FirstCouponDate, bondstatic.MaturityDate, bondstatic.Coupon, bondstatic.CpnFreq, fwddate, repo, optExDivDays)[0]; if (measure == "Price") { value = fwdprice; } else { value = MeasureCalculator.calcFwdBondMeasure(measure, bondstatic, fwdprice, dte, fwddate, spreadConventions, forecastCurves, discountCurves, holidays); } } sb.Add(dte,value); } outputs[ticker] = sb.Series; } var consolidatedMeasures = Frame.FromColumns(outputs); // Cache results TimeSeriesCache[cacheKey] = consolidatedMeasures; return consolidatedMeasures; }
//--------------------------------------------------------------------------------------------------------- //[Test] public void SpreadSeriesToArrayTests() //--------------------------------------------------------------------------------------------------------- { // Params. DateTime start = new DateTime(2016, 2, 28); DateTime end = new DateTime(2016, 3, 18); List<String> tickers = new List<string>() { "TUH6", "TUM6", "TUU6" }; string samplingFreq = "1b"; // Default Configs SpreadTimeSeriesConfigs config = new SpreadTimeSeriesConfigs("US"); string forecastCurveName = config.forecastCurveName; string discountCurveName = config.discountCurveName; string ccy = config.ccy; string calendarcode = config.calendarcode; string futuresStaticMoniker = config.futuresStaticMoniker; string carbonEnv = config.carbonEnv; BondAnalytics.Country country = config.country; BondAnalytics.DayCountType dct = config.dct; long swpfixfreq = config.swpfixfreq; long swpfloatfreq = config.swpfloatfreq; long bndCouponFreq = config.bndCouponFreq; int BlendIndex = config.BlendIndex; bool bForecastCurve = true; // Bond Static Dictionary<string, TimeSeriesBondStatic> bondstatic = new Dictionary<string, TimeSeriesBondStatic>() { {"US912828G799", new TimeSeriesBondStatic("US912828G799", new DateTime(2017,12,15), new DateTime(2015,12,15),DateTime.MinValue,1.0)}, {"US912828J686", new TimeSeriesBondStatic("US912828J686", new DateTime(2018,03,15), new DateTime(2015,03,16),DateTime.MinValue,1.0)}, {"US912828VK31", new TimeSeriesBondStatic("US912828VK31", new DateTime(2018,06,30), new DateTime(2015,07,01),DateTime.MinValue,1.0)} }; //Spread Static SpreadConventions spreadconventions = new SpreadConventions(country, dct, swpfixfreq, swpfloatfreq, bndCouponFreq, bForecastCurve, BlendIndex); // Dates var holidays = new List<DateTime>(); var dateRange = new List<DateTime>(); using (var client = new CarbonClient(carbonEnv)) { // Holidays if (calendarcode != "") { var nodaHols = client.GetCalendarAsync(calendarcode).Result.Dates; foreach (LocalDate hol in nodaHols) { holidays.Add(hol.ToDateTime()); } } // DateRange DateTime startDate = start.AddTenor(Tenor.FromString("1b"), "").AddTenor(Tenor.FromString("-1b"), ""); DateTime nextDate = end.AddTenor(Tenor.FromString("1b"), "").AddTenor(Tenor.FromString("-1b"), ""); //TimeSpan EOD = new TimeSpan(23, 59, 59); /*if (startDate > nextDate) { return "Error! Bad Inputs!"; }*/ var tenor = Tenor.FromString("-" + samplingFreq); while (nextDate >= startDate) { dateRange.Add(nextDate); nextDate = BondAnalytics.PrevBusDay(nextDate.AddTenor(tenor, ""), holidays); } } //Swap. var swapBuilder = new SwapCurveSeriesBuilder(dateRange, forecastCurveName, discountCurveName, ccy, holidays, mCarbonClient); swapBuilder.buildAllCurves(); // Futures. var seriesBuilder = new FuturesSeriesBuilder(tickers, dateRange, holidays, futuresStaticMoniker, mCarbonClient, carbonEnv); // Spread Series. Dictionary<string, double> testVals = new Dictionary<string, double>() { {"Price", 109.1015625}, {"Yield", 0.009007303 * 10000}, {"TrueSpread",6.7788999}, {"MMS", 0.009689381* 10000}, {"Spread", 6.820787365} }; Dictionary<string /*metric*/, SpreadSeriesBuilder /*builder*/> spreadbuildermap = new Dictionary<string, SpreadSeriesBuilder>(); SpreadSeriesBuilder output = null; foreach (var metric in testVals.Keys.ToList()) { output = new SpreadSeriesBuilder(metric, seriesBuilder, swapBuilder, bondstatic, spreadconventions); Console.WriteLine(metric + " :"); output.SpreadValues.Print(); var row = output.SpreadValues.GetRow<double>(new DateTime(2016, 03, 18)); double TUM6 = row.Get("TUM6"); double error = Math.Abs(TUM6 - testVals[metric]); Assert.LessOrEqual(error, Math.Pow(10, -3) * 5, "Error found in " + metric + ", test: " + testVals[metric].ToString() + ", actual: " + TUM6.ToString()); // 0.005bps Console.WriteLine("Error :{0}", error); } // Now let's look at converting this to an array if (output != null) { var objArr = output.getSpreadAsObjArr(); } }
//--------------------------------------------------------------------------------------------------------- //[Test] public void SpreadSeries() //--------------------------------------------------------------------------------------------------------- { // Params. DateTime start = new DateTime(2016, 2, 28); DateTime end = new DateTime(2016, 3, 18); List<String> tickers = new List<string>() { "TUH6", "TUM6", "TUU6","TU.Front" }; // Default Configs SpreadTimeSeriesConfigs config = new SpreadTimeSeriesConfigs("US"); string forecastCurveName = config.forecastCurveName; string discountCurveName = config.discountCurveName; string ccy = config.ccy; string calendarcode = config.calendarcode; string futuresStaticMoniker = config.futuresStaticMoniker; string carbonEnv = config.carbonEnv; BondAnalytics.Country country = config.country; BondAnalytics.DayCountType dct = config.dct; long swpfixfreq = config.swpfixfreq; long swpfloatfreq = config.swpfloatfreq; long bndCouponFreq = config.bndCouponFreq; int BlendIndex = config.BlendIndex; bool bForecastCurve = true; // Bond Static Dictionary<string, TimeSeriesBondStatic> bondstatic = new Dictionary<string, TimeSeriesBondStatic>() { {"US912828G799", new TimeSeriesBondStatic("US912828G799", new DateTime(2017,12,15), new DateTime(2015,12,15),DateTime.MinValue,1.0)}, {"US912828J686", new TimeSeriesBondStatic("US912828J686", new DateTime(2018,03,15), new DateTime(2015,03,16),DateTime.MinValue,1.0)}, {"US912828VK31", new TimeSeriesBondStatic("US912828VK31", new DateTime(2018,06,30), new DateTime(2015,07,01),DateTime.MinValue,1.0)} }; //Spread Static SpreadConventions spreadconventions = new SpreadConventions(country,dct,swpfixfreq,swpfloatfreq,bndCouponFreq,bForecastCurve,BlendIndex); //Swap. var swapBuilder = new SwapCurveSeriesBuilder(start, end, forecastCurveName, discountCurveName, ccy, mCarbonClient, calendarcode); swapBuilder.buildAllCurves(); //swapBuilder.DiscountCurves[new DateTime(2016, 03, 18)].PrintDump(); swapBuilder.ForecastCurves[new DateTime(2016, 03, 18)].PrintDump(); // Futures. var seriesBuilder = new FuturesSeriesBuilder(tickers, start, end, calendarcode, futuresStaticMoniker, mCarbonClient,carbonEnv); // Spread Series. Dictionary<string, double> testVals = new Dictionary<string, double>() { {"Price", 109.1015625}, {"Yield", 0.009007303 * 10000}, {"TrueSpread",6.7788999}, {"MMS", 0.009689381* 10000}, {"Spread", 6.820787365} }; Dictionary<string /*metric*/, SpreadSeriesBuilder /*builder*/> spreadbuildermap = new Dictionary<string, SpreadSeriesBuilder>(); SpreadSeriesBuilder output = null; foreach (var metric in testVals.Keys.ToList()) { output = new SpreadSeriesBuilder(metric, seriesBuilder, swapBuilder, bondstatic, spreadconventions); Console.WriteLine(metric + " :"); output.SpreadValues.Print(); var row = output.SpreadValues.GetRow<double>(new DateTime(2016, 03, 18)); double TUM6 = row.Get("TUM6"); double error = Math.Abs(TUM6 - testVals[metric]); Assert.LessOrEqual(error, Math.Pow(10, -3) * 5, "Error found in " + metric + ", test: " + testVals[metric].ToString() + ", actual: " + TUM6.ToString()); // 0.005bps Console.WriteLine("Error :{0}", error); } // Now let's try to index 1 Mar if (output != null) { var spreadVals = output.SpreadValues; var myList = spreadVals.RowKeys.ToList(); Console.WriteLine("Key List: {0}", myList); // Try on individual series Dictionary<string/*colname*/, Series<DateTime,object>/*actualsrs*/> tmp = new Dictionary<string, Series<DateTime, object>>(); foreach (string colname in spreadVals.ColumnKeys) { tmp[colname] = spreadVals.Columns[colname].FillMissing("#N/A"); } spreadVals = Frame.FromColumns(tmp); //spreadVals.FillMissing("#N/A").Print(); var row = spreadVals.GetRow<string>(new DateTime(2016, 03, 01)); Console.WriteLine("Row values"); row.Print(); } }