public static RollResultContractItem CalculateFutureResult(IContract contract, Func<FutureSeries, FutureStatic> getFutureFuc, Func<FutureSeries, string> getContractFunc, Func<FutureSeries, double> getBondPriceFunc)
        {

            var market = AsFuture(contract).BbgBase.Market();
            var country = (BondAnalytics.Country) Enum.Parse(typeof(BondAnalytics.Country), market);
            // byran lim config coded in symmetry.net. we use this until we have a centralised place for the curve static
            var fcstCfg = new SpreadTimeSeriesConfigs(market, bForecastCurve: true);
            var discCfg = new SpreadTimeSeriesConfigs(market, bForecastCurve: false);

            
            var rollresults = contract.ContractSeries.Select(c =>
            {
                var s = c as FutureSeries;
                if (s == null)
                    return null;

                var forCurve = SymmetryDataModel.GetDiscountCurve(fcstCfg.SymForecastCurveName, c.Date);
                var disCurve = SymmetryDataModel.GetDiscountCurve(fcstCfg.SymDiscountCurveName, c.Date);
                var mms = BondCalc.CalcMeasure(CalcMeasure.MMS, getBondPriceFunc(s), country, getFutureFuc(s).FirstNoticeDate, disCurve, forCurve,
                                                DateTime.MinValue, s.CurrentFuture.Expiry, DateTime.MinValue, 0, 6, true, BondAnalytics.DayCountType.Act360, 12,12,null);

                var mmsSeries = new Tuple<DateTime, RollResultItem>(c.Date, new RollResultItem
                {
                    Name = getContractFunc(s),
                    Value = mms,
                });

                return new {m = mmsSeries};
            }).Where(x => x != null).ToArray();
            
            return new RollResultContractItem
            {
                MMS = new DatedDataCollectionGen<RollResultItem>(rollresults.Select(r => r.m.Item1).ToArray(), rollresults.Select(r => r.m.Item2).ToArray()),
            };
        }
        //-----------------------------------------------------------------------------------
        // function to return carry adjusted smooth series, together with Bond ISIN, series price, convfac
        public static Frame<DateTime, String> GenerateCarryAdjSeries(
            string ticker,
            DateTime start,
            DateTime end,
            string countryCode,
            ICarbonClient client = null
            )
        //-----------------------------------------------------------------------------------
        {
            //variables used for futureSeriesBuilder 
            var eRollMethod = TimeSeriesUtilities.GetRollMethods("FirstNoticeDate");
            var eInterpolationTypes = TimeSeriesUtilities.GetInterpolationType("None");
            var eSmoothingTypes = TimeSeriesUtilities.GetSmoothingTypes("None");


            #region Configs
            SpreadTimeSeriesConfigs config = new SpreadTimeSeriesConfigs(countryCode, false);
            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;
            List<string> contractSortOrder = config.contractSortOrder;

            List<DateTime> holidays = TimeSeriesUtilities.GetHolidays(calendarCode, client);
            #endregion

            // in rolling series US is following calendar of USGS rather than USNY
            var dateRange = TimeSeriesUtilities.GetAllDatesInDateime(start, end, countryCode.ToUpper() == "US" ? "USGS" : calendarCode, client, "1b");

            //Get Rolling Series
            HashSet<string> futuresList = new HashSet<string> { "TU", "FV", "TY", "UXY", "US", "WN", "DU", "OE", "RX", "UB", "IK", "BTS", "OAT" };
            bool tickerIsFuture = futuresList.Contains(ticker);
            bool isCT = ticker.ToUpper().Contains("CT");
            var rollType = isCT ? "ct" : "ctd";
            string moniker = string.Format("symapp.roll.{0}.{1}.{2}", rollType, ticker.Market(), ticker).ToLower();
            string fmoniker;

            // Carbon frame //
            var frame = client.GetFrameAsync<DateTime>(moniker).Result;
            if (!frame.ColumnKeys.Contains("price")) return null;// need better null value checker here

            Series<DateTime, string> bondISIN = null;
            Series<DateTime, double> bondPrice = null;
            Dictionary<DateTime, string> futureTicker = new Dictionary<DateTime, string>();
            Dictionary<DateTime, double> convFac = new Dictionary<DateTime, double>();
            Dictionary<DateTime, double> futurePrice = new Dictionary<DateTime, double>();
            Dictionary<DateTime, double> smoothSeries = new Dictionary<DateTime, double>();
            Series<DateTime, double> futureConvertedPrice = null;

            //Repo series and carry series
            Dictionary<DateTime, double> repoSeries = new Dictionary<DateTime, double>();
            Dictionary<DateTime, double> carrySeries = new Dictionary<DateTime, double>();

            //DV01 series (Future DV01 = CTD DV01/ConvFac; CT DV01 = Bond DV01)
            Dictionary<DateTime, double> DV01Series = new Dictionary<DateTime, double>();


            //Variables needed for futures
            Frame<string, string> combinedStatic = null;
            int RowNum = 0;

            try
            {
                bondISIN = frame.GetColumn<string>("ticker").Between(start, end);//Need check on sorted by date
                bondPrice = frame.GetColumn<double>("price").Between(start, end);
            }
            catch (Exception)
            {
                //Error handling
            }
            //Future tickers and Future Price as well as conversion factors
            if (tickerIsFuture)
            {
                fmoniker = string.Format("symapp.roll.{0}.{1}.{2}", "f" + rollType, ticker.Market(), ticker).ToLower();
                frame = client.GetFrameAsync<DateTime>(fmoniker).Result;
                if (!frame.ColumnIndex.KeySequence.Contains("price")) return null;//need better null value checker here
                try
                {
                    futureConvertedPrice = frame.GetColumn<double>("price").Between(start, end).Sort();
                }
                catch (Exception)
                {
                    //Error handling
                }

                //Get the future static table
                //Futures
                List<string> tickers = new List<string>();
                tickers.Add(ticker.ToUpper() + ".Front");
                FuturesSeriesBuilder
                    seriesBuilder = new FuturesSeriesBuilder(tickers, dateRange, holidays, futuresStaticMoniker, client, carbonEnv, rollMthd: eRollMethod, interpType: eInterpolationTypes, contractSortOrder: config.contractSortOrder, smoothingType: eSmoothingTypes);
                var futStatic = seriesBuilder.FuturesStatic;
                //Bond Static
                Dictionary<String, TimeSeriesBondStatic> bndStatics = TimeSeriesUtilities.GetBondStaticsFromFuturesBuilder(seriesBuilder, config, client);
                combinedStatic = SpreadSeriesBuilder.combineFuturesAndBondStatic(bndStatics, futStatic);

                RowNum = combinedStatic.RowCount;
            }

            double futureConvertedPx = 0.0;
            double lastRepo = 0.0;
            double fwdPrice = 0.0;
            object dailyRepo = null;
            bool bHaveEverthing = true;
            DateTime prevD8 = DateTime.MinValue;

            //loop through each date to find the corresponding future ticker and conversion factors
            // and add repo and carry for bond series
            // can we get the sorted key list
            #region buildSeries
            foreach (DateTime d8 in bondISIN.Keys.OfType<DateTime>())
            {
                // DV01Series
                string currBondISIN = bondISIN.TryGet(d8).Value;

                Double bondDV01 = 0.0;

                DateTime settleDate = d8;

                var currBondStatic = AnalyticsUtilities.GetBondStaticData(client, currBondISIN);
                if (currBondStatic == null)
                {
                    bHaveEverthing = false;
                    DV01Series.Add(d8, 0.0);//Need better handling on empty bond static
                }
                else
                {

                    if (config.bondSettleLag > 0)
                    {
                        settleDate = BondAnalytics.NextBusDay(settleDate.AddDays(1), holidays);
                    }
                    if (config.bondSettleLag > 1)
                    {
                        settleDate = BondAnalytics.NextBusDay(settleDate.AddDays(1), holidays);
                    }
                    bondDV01 = BondAnalytics.SolveYield(country, settleDate, bondPrice.TryGet(d8).Value, currBondStatic.EffectiveDate, currBondStatic.FirstCouponDate,
                        currBondStatic.MaturityDate, currBondStatic.Coupon, currBondStatic.CpnFreq)[1];
                    DV01Series.Add(d8, bondDV01);
                }

                if (tickerIsFuture)
                {
                    //Need gaurantee that the table is sorted
                    int i = 0;
                    while (combinedStatic.GetColumn<DateTime>("fut_notice_first").GetAt(i) <= d8 && i < RowNum)
                    {
                        i++;
                    }
                    if (i == RowNum)
                    {
                        futureTicker.Add(d8, string.Empty);
                        convFac.Add(d8, double.NaN);
                        futurePrice.Add(d8, double.NaN);
                    }
                    else
                    {
                        futureTicker.Add(d8, combinedStatic.GetColumn<string>("ticker").GetAt(i));
                        convFac.Add(d8, combinedStatic.GetColumn<double>("fut_cnvs_factor").GetAt(i));
                        futureConvertedPx = futureConvertedPrice.TryGet(d8).Value;
                        futurePrice.Add(d8, futureConvertedPx / combinedStatic.GetColumn<double>("fut_cnvs_factor").GetAt(i));
                        //update CTD DV01 to be future DV01
                        DV01Series[d8] = DV01Series[d8] / combinedStatic.GetColumn<double>("fut_cnvs_factor").GetAt(i);
                    }
                    //Add SmoothSeries
                    if (prevD8 == DateTime.MinValue)
                    {
                        smoothSeries.Add(d8, futurePrice[d8]);
                    }
                    else
                    {
                        //check if there is ticker change
                        if (futureTicker[d8] == futureTicker[prevD8])
                        {
                            smoothSeries.Add(d8, smoothSeries[prevD8] + futurePrice[d8] - futurePrice[prevD8]);
                        }
                        else
                        {
                            //find the old future price on current date
                            string oldFutureTicker = futureTicker[prevD8];
                            string full_ticker = oldFutureTicker + " COMDTY";
                            var oldFuturePrice = client.GetCbnTimeSeriesDataCell(full_ticker, "eod", d8, "settle");
                            if (oldFuturePrice == null)
                            {
                                full_ticker = AnalyticsUtilities.GetAlternativeFuturesName(full_ticker);
                                oldFuturePrice = client.GetCbnTimeSeriesDataCell(full_ticker, "eod", d8, "settle");
                            }
                            //Otherwise report error: assume no price change a good way?
                            if (oldFuturePrice == null) oldFuturePrice = futurePrice[prevD8];
                            smoothSeries.Add(d8, smoothSeries[prevD8] + (oldFuturePrice as double? ?? double.NaN) - futurePrice[prevD8]);// potential problem if current res is NaN, all following value would be NaN  
                        }
                    }
                }
                else
                {
                    //repo and carry series for bond
                    try
                    {
                        dailyRepo = client.GetCbnTimeSeriesDataCell(currBondISIN, "eod-mlp", d8, "wtdRate");
                        // repoSeries.Add(d8, dailyRepo as double?);
                    }
                    catch
                    {
                        //Missing Data 
                        //need to convert it 
                    }
                    lastRepo = (dailyRepo as double?) ?? lastRepo;
                    repoSeries.Add(d8, lastRepo);
                    //need bond static info
                    if (currBondStatic == null)
                    {
                        bHaveEverthing = false;
                        carrySeries.Add(d8, 0.0);//Need better handling for missing bond static
                        smoothSeries.Add(d8, 0.0);//Need better handling for missing bond static
                    }
                    else
                    {
                        //calculate one-day fwdPrice
                        //Current next business day function doesn't handle number of days so get settleDate the hard way.
                        //one day carry
                        DateTime fwdDate = settleDate;
                        fwdDate = BondAnalytics.NextBusDay(fwdDate.AddDays(1), holidays);
                        if (fwdDate <= settleDate)
                        {
                            //error handling here : fwdDate must be bigger than settleDate
                        }
                        fwdPrice = BondAnalytics.CalcBondFwd(country, settleDate, bondPrice.TryGet(d8).Value, currBondStatic.EffectiveDate, currBondStatic.FirstCouponDate, currBondStatic.MaturityDate,
                            currBondStatic.Coupon, currBondStatic.CpnFreq, fwdDate, lastRepo)[0];
                        carrySeries.Add(d8, bondPrice.TryGet(d8).Value - fwdPrice);

                        //Smooth series for bond
                        if (prevD8 == DateTime.MinValue)
                        {
                            smoothSeries.Add(d8, bondPrice.TryGet(d8).Value);//assume no carry added on day 1
                        }
                        else
                        {
                            if (bondISIN.TryGet(prevD8).Value == bondISIN.TryGet(d8).Value)
                            {
                                //no change in series   
                                smoothSeries.Add(d8, smoothSeries[prevD8] + bondPrice.TryGet(d8).Value - bondPrice.TryGet(prevD8).Value);
                            }
                            else
                            {
                                string oldBondISIN = bondISIN.TryGet(prevD8).Value;
                                var oldBondPrice = client.GetCbnTimeSeriesDataCell(oldBondISIN, "eod-mlp", d8, "close");
                                if (oldBondPrice == null) oldBondPrice = bondPrice.TryGet(prevD8).Value;// May need better way to handle this error
                                smoothSeries.Add(d8, smoothSeries[prevD8] + (oldBondPrice as double? ?? double.NaN) - bondPrice.TryGet(prevD8).Value);
                            }
                        }
                    }
                }
                //update prevD8
                prevD8 = d8;
            }
            #endregion

            //Sort the dictionary and package into frame for output
            if (tickerIsFuture)
            {
                //building using dictionary
                Dictionary<string, Series<DateTime, string>> resHolder = new Dictionary<string, Series<DateTime, string>>();
                resHolder["futureTicker"] = futureTicker.ToSeries();

                var res = Frame.FromColumns(resHolder);
                res.AddColumn("futruePrice", futurePrice.ToSeries());
                res.AddColumn("CTD_ISIN", bondISIN);
                res.AddColumn("ConvFac", convFac.ToSeries());
                res.AddColumn("DV01", DV01Series.ToSeries());
                res.AddColumn("smoothSeries", smoothSeries.ToSeries());

                res.SortRowsByKey();

                return res;
            }
            else
            {
                //if bond
                Dictionary<string, Series<DateTime, string>> resHolder = new Dictionary<string, Series<DateTime, string>>();
                resHolder["BondISIN"] = bondISIN;

                var res = Frame.FromColumns(resHolder);
                res.AddColumn("BondPrice", bondPrice);
                res.AddColumn("repo", repoSeries.ToSeries());
                res.AddColumn("carry", carrySeries.ToSeries());
                res.AddColumn("DV01", DV01Series.ToSeries());
                res.AddColumn("smoothSeries", smoothSeries.ToSeries());

                res.SortRowsByKey();
                return res;

            }
        }
        //----------------------------------------------------------------------------------------
        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;
        }
Example #5
0
        public static double Calculate(CalcMeasure Measure, 
                                        DateTime settle,
                                        double price,
                                        Bond bondStatic, 
                                        BondAnalytics.Country eCountry, 
                                        DateTime asOfDate,                                         
                                        List<DateTime> hols)
        {
            
            // byran lim config coded in symmetry.net. we use this until we have a centralised place for the curve static
            // different country has different setting of using forcast and discount curve
            bool bForecastCurve;
            switch (eCountry)
            {                
                case BondAnalytics.Country.DE:
                    bForecastCurve = false;
                    break;                
                default:
                    bForecastCurve = true;
                    break;
            }

            var fcstCfg = new SpreadTimeSeriesConfigs(eCountry.ToString(), bForecastCurve);            

            int trial = 0;
            DiscountCurve forCurve = null;
            DiscountCurve disCurve = null;
            if (discountCurveCache.ContainsKey(fcstCfg.SymForecastCurveName))
            {
                var forTup = discountCurveCache[fcstCfg.SymForecastCurveName].FirstOrDefault(i => i.Item1 == asOfDate);
                if (forTup != null) forCurve = forTup.Item2;
            }
            if (discountCurveCache.ContainsKey(fcstCfg.SymDiscountCurveName))
            {
                var disTup = discountCurveCache[fcstCfg.SymDiscountCurveName].FirstOrDefault(i => i.Item1 == asOfDate);
                if (disTup != null) disCurve = disTup.Item2;
            }
            if (forCurve == null || disCurve == null)
            {
                while (trial < 3)
                {
                    try
                    {
                        forCurve = SymmetryDataModel.GetDiscountCurve(fcstCfg.SymForecastCurveName, asOfDate);
                        disCurve = SymmetryDataModel.GetDiscountCurve(fcstCfg.SymDiscountCurveName, asOfDate);

                        trial = 5;
                        break;
                    }
                    catch (Exception)
                    {
                        trial++;
                        continue;
                    }
                }

                if (forCurve != null && disCurve != null)
                {
                    var forTup = new Tuple<DateTime, DiscountCurve>(asOfDate, forCurve);
                    var disTup = new Tuple<DateTime, DiscountCurve>(asOfDate, disCurve);
                    if (discountCurveCache.ContainsKey(fcstCfg.SymForecastCurveName))
                        discountCurveCache[fcstCfg.SymForecastCurveName].Add(forTup);
                    else
                        discountCurveCache[fcstCfg.SymForecastCurveName] = new[] {forTup}.ToList();
                    if (discountCurveCache.ContainsKey(fcstCfg.SymDiscountCurveName))
                        discountCurveCache[fcstCfg.SymDiscountCurveName].Add(disTup);
                    else
                        discountCurveCache[fcstCfg.SymDiscountCurveName] = new[] { disTup }.ToList();
                }
            }

            if (forCurve == null || disCurve == null)
                return double.NaN;

            DateTime effectiveDate = bondStatic.EffectiveDate ?? DateTime.MinValue;
            DateTime maturity = bondStatic.Maturity ?? DateTime.MinValue;
            DateTime firstCpnDate = bondStatic.FirstCouponDate ?? DateTime.MinValue;
            double coupon = bondStatic.Coupon;


            long bondCpnFreq = fcstCfg.bndCouponFreq;
            bool bOIS = !fcstCfg.bForecastCurve;
            BondAnalytics.DayCountType dct = fcstCfg.dct;
            long swapFixedFreq = fcstCfg.swpfixfreq;
            long swapFloatFreq = fcstCfg.swpfloatfreq;

            return CalcMeasure(Measure, price, eCountry, settle, disCurve, forCurve, effectiveDate, maturity, firstCpnDate, coupon, bondCpnFreq, bOIS, dct, swapFixedFreq, swapFloatFreq, hols);
        }
         //---------------------------------------------------------------------------------------------------------
         //[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();

             }
         }
         //---------------------------------------------------------------------------------------------------------
         //[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();
             }


         }
 //------------------------------------------------------------------------------------------------
 public SpreadConventions(SpreadTimeSeriesConfigs configs)
     //------------------------------------------------------------------------------------------------
 {
     Country = configs.country;
     DayCount = configs.dct;
     SwapFixedFrequency = configs.swpfixfreq;
     SwapFloatFrequency = configs.swpfloatfreq;
     BondCouponFrequency = configs.bndCouponFreq;
     bForecastCurve = configs.bForecastCurve;
     BlendIndex = configs.BlendIndex;
 }
Example #9
0
        // GBP is only currently setup to get spot ASW terms. Will move on to futures only if it becomes necessary.
        //----------------------------------------------------------------------------------------
        public static void run(DateTime start, DateTime end, string samplingFreq, string outputFolderPath)
        //----------------------------------------------------------------------------------------
        {
            Console.WriteLine("Commencing GBP Run");
            // INIT
            BondAnalytics.Country eCountry = BondAnalytics.Country.UK;
            List<string> SwapMeasures = new List<string>() { "MMS", "Spread", "TrueSpread" }; //
            List<string> BondMeasures = new List<string>() { "Price", "Yield"};



            // FIND ALL SECURITIES.
            DateTime fDate = DateTime.Today.AddDays(30);
            List<string> rawmlptickers = DataHandler.GetAllSecurities("UKT", "Term", fDate);

            // Remove everything with AuC in it
            List<string> mlptickers = new List<string>();
            foreach (string tic in rawmlptickers)
            {
                if (!tic.ToLower().Contains("auc"))
                {
                    mlptickers.Add(tic);
                }
            }

            Console.WriteLine();
            Console.WriteLine("Found UKT tickers");

            foreach (string tic in mlptickers)
            {
                Console.WriteLine(tic);
            }

            // GET THE RIGHT STATICS
            var fcstCfg = new SpreadTimeSeriesConfigs("UK", bForecastCurve:true);
            var discCfg = new SpreadTimeSeriesConfigs("UK", bForecastCurve:false);
            var bondStaticMap = new Dictionary<string, BondStatic>();

            foreach (string tic in mlptickers)
            {
                bondStaticMap[tic] = DataHandler.GetBondStatic(tic);
            }

            // GET DATES.
            Console.WriteLine();
            Console.WriteLine("Setting Dates");
            
            var res = DataHandler.GetCarbonClient().GetCalendarAsync("GBLO");
            res.Wait();
            var holsInLocalDate = res.Result.Dates;
            List<DateTime> hols = holsInLocalDate.Select(d => d.ToDateTime()).ToList();


            DateTime startDate =    start.AddTenor(Tenor.FromString("-1b"), "").AddTenor(Tenor.FromString("1b"), "");
            DateTime nextDate =     end.AddTenor(Tenor.FromString("1b"), "").AddTenor(Tenor.FromString("-1b"), "");
            
            List<DateTime> dateRange = new List<DateTime>();
            if (startDate > nextDate)
            {
                throw new ArgumentException("Start date cannot be after end date");
            }
            var tenor = Tenor.FromString("-" + samplingFreq);
            while (nextDate >= startDate)
            {
                dateRange.Add(nextDate);
                nextDate = BondAnalytics.PrevBusDay(nextDate.AddTenor(tenor, ""), hols);
            }


            // GET ALL PRICES.
            Console.WriteLine();
            Console.WriteLine("Setting Prices");
            var result = DataHandler.GetBondPricesAsync(mlptickers, dateRange, eCountry);
            Frame<DateTime, string> bondFrame;
            if (result.IsCompleted) bondFrame =  result.Result;
            else throw new ArgumentNullException("No bond prices came back!");
            bondFrame.Print();

            // GET ALL SWAP CURVES.
            Console.WriteLine();
            Console.WriteLine("Getting Swap Cruves");
            var fCurves = DataHandler.getDiscountCurvesInDateRangeAsync(fcstCfg.SymForecastCurveName, dateRange).Result;
            var dCurves = DataHandler.getDiscountCurvesInDateRangeAsync(fcstCfg.SymDiscountCurveName, dateRange).Result;

            // GET ALL MEASURES.
            var output = new Dictionary<string/*measure*/,Frame<DateTime,string>>();
            var configs = new List<SpreadTimeSeriesConfigs>(){fcstCfg, discCfg};

            // Swap measures
            foreach (string measure in SwapMeasures)
            {
                Console.WriteLine("Calculating {0}", measure);
                foreach (var config in configs)
                {
                    Console.WriteLine("Forecast curve ? {0}", config);
                    var valueMap = new Dictionary<string/*id*/, Series<DateTime,double>>();
                    bool bForecast = config.bForecastCurve;

                    foreach (var ticker in mlptickers)
                    {
                        var srs = bondFrame.Columns[ticker];
                        var bndStatic = bondStaticMap[ticker];

                        var sb = new SeriesBuilder<DateTime, double>();
                        foreach (DateTime dte in srs.Keys)
                        {
                            // Skip if we're missing data somewhere
                            if (!(dCurves.ContainsKey(dte)  &&
                                  srs.ContainsKey(dte)))
                                continue;

                            if (config.bForecastCurve && !fCurves.ContainsKey(dte)) // only press on if we need forecast curves
                                continue;

                            // Proceed.
                            DiscountCurve discount = dCurves[dte];
                            DiscountCurve forecast = bForecast ? fCurves[dte] : discount;

                            DateTime settle = BondAnalytics.NextBusDay(dte.Date.AddDays(config.bondSettleLag), hols);
                            double price = srs.TryGetAs<double>(dte).OrDefault(double.NaN);

                            if (double.IsNaN(price)) continue;
                            double value = BondASWCalc.calcMeasure( measure, price, eCountry,
                                                                    dte, settle, discount, forecast, 
                                                                    bndStatic, config, hols);
                            if (double.IsNaN(value)) continue;
                            sb.Add(dte, value);
                        }
                        valueMap[ticker] = sb.Series;

                        Console.WriteLine("Completed for  {0}", ticker);
                        valueMap[ticker].Print();
                    }

                    var df = Frame.FromColumns(valueMap);
                    string prefix = bForecast ? "L" : "OIS";
                    output[prefix + measure] = df;

                    Console.WriteLine();
                    Console.WriteLine("Swap Measures complete.");
                }
            }


            //Bond Measure
            foreach(string measure in BondMeasures)
            {
                var config = fcstCfg; 

                Console.WriteLine("Calculating {0}", measure);

                var valueMap = new Dictionary<string/*id*/, Series<DateTime, double>>();

                foreach (var ticker in mlptickers)
                {
                    var srs = bondFrame.Columns[ticker];
                    var bndStatic = bondStaticMap[ticker];

                    var sb = new SeriesBuilder<DateTime, double>();
                    foreach (DateTime dte in srs.Keys)
                    {
                        // Skip if we're missing data somewhere
                        if (!srs.ContainsKey(dte))
                            continue;

                        // Proceed.

                        DateTime settle = BondAnalytics.NextBusDay(dte.Date.AddDays(config.bondSettleLag), hols);
                        double price = srs.TryGetAs<double>(dte).OrDefault(double.NaN);

                        if (double.IsNaN(price)) continue;
                        double value = BondASWCalc.calcMeasure(measure, price, eCountry,
                                                                dte, settle, null, null,
                                                                bndStatic, config, hols);
                        if (double.IsNaN(value)) continue;
                        sb.Add(dte, value);
                    }
                    valueMap[ticker] = sb.Series;

                    Console.WriteLine("Completed for  {0}", ticker);
                    valueMap[ticker].Print();
                }

                var df = Frame.FromColumns(valueMap);
                output[ measure] = df;

                Console.WriteLine();
                Console.WriteLine("Bond Measures complete.");
                
            }

            // SAVE OUTPUT.
            Console.WriteLine("Saving CSV Files");

            var renameMap = new Dictionary<string, string>()
            {
                {"LTrueSpread", "LOAS"},
                {"OISTrueSpread", "OISOAS"},
                {"LSpread", "LASW"},
                {"OISSpread", "OISASW"}
            };

            foreach (var kvp in output)
            {
                var measure = kvp.Key;
                var df = convertFrameToString(kvp.Value);

                if (renameMap.ContainsKey(measure))
                {
                    measure = renameMap[measure];
                }

                var fileName = outputFolderPath + "\\" + eCountry.ToString()+ "_" +  measure + ".csv";

                df = df.FillMissing("");

                
                df.SaveCsv(fileName,includeRowKeys:true);

                Console.WriteLine("Saved {0}", fileName);
            }
        }
Example #10
0
        //----------------------------------------------------------------------------------------
        public static double calcMeasure(   string Measure, 
                                            double price, 
                                            BondAnalytics.Country eCountry,
                                            DateTime asof,
                                            DateTime settle,
                                            DiscountCurve discCurve, 
                                            DiscountCurve fcstCurve,
                                            BondStatic bondStatic,
                                            SpreadTimeSeriesConfigs configs,
                                            List<DateTime> hols)
         //----------------------------------------------------------------------------------------
        {

            DateTime effectiveDate  = DateTime.FromOADate( bondStatic.EffectiveDate);
            DateTime maturity       = DateTime.FromOADate( bondStatic.Maturity);
            DateTime firstCpnDate   = DateTime.FromOADate(bondStatic.FirstCoupon);
            double coupon           = bondStatic.Coupon;


            long bondCpnFreq                = configs.bndCouponFreq;
            bool bOIS                       = !configs.bForecastCurve;
            BondAnalytics.DayCountType dct  = configs.dct;
            long fixedFreq                  = configs.swpfixfreq;
            long floatFreq                  = configs.swpfloatfreq; 



            double output = double.NaN;
            switch (Measure)
            {
                case "Price":
                    {
                        output= price;
                        break;
                    }
                case "Yield":
                    {
                        output= 10000.0 * BondAnalytics.SolveYield(eCountry, settle, price, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[0];
                        break;
                    }
                case "TrueSpread":
                    {
                            DateTime[] dfDates = (bOIS ? discCurve.AsTuples().Select(x => x.Item1).ToArray() : fcstCurve.AsTuples().Select(x => x.Item1).ToArray());
                            double[] dfs = (bOIS ? discCurve.AsTuples().Select(x => x.Item2).ToArray() : fcstCurve.AsTuples().Select(x => x.Item2).ToArray());

                            //  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, settle, price, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq, dfDates, dfs,hols );

                        break;
                    }
                case "MMS":
                {
                    DateTime[] discDfDates = discCurve.AsTuples().Select(x => x.Item1).ToArray();
                    DateTime[] fcstDfDates = (bOIS ? discCurve.AsTuples().Select(x => x.Item1).ToArray() : fcstCurve.AsTuples().Select(x => x.Item1).ToArray());
                    double[] discDfs = discCurve.AsTuples().Select(x => x.Item2).ToArray();
                    double[] fcstDfs =(bOIS ? discCurve.AsTuples().Select(x => x.Item2).ToArray() : fcstCurve.AsTuples().Select(x => x.Item2).ToArray());

                    double mms = BondAnalytics.CalcMMS(settle, maturity, dct, fixedFreq, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, hols, null, null, null, null, null, firstCpnDate, (bOIS ? 5 : 0));
                    output= 10000.0 * mms;
                    
                    break;
                    }
                case "Spread":
                    {

                        DateTime[] discDfDates = discCurve.AsTuples().Select(x => x.Item1).ToArray();
                        DateTime[] fcstDfDates = (bOIS ? discCurve.AsTuples().Select(x => x.Item1).ToArray() : fcstCurve.AsTuples().Select(x => x.Item1).ToArray());
                        double[] discDfs = discCurve.AsTuples().Select(x => x.Item2).ToArray();
                        double[] fcstDfs = (bOIS ? discCurve.AsTuples().Select(x => x.Item2).ToArray() : fcstCurve.AsTuples().Select(x => x.Item2).ToArray());

                        double mms = BondAnalytics.CalcMMS(settle, maturity, dct, fixedFreq, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, hols, null, null, null, null, null, firstCpnDate, (bOIS ? 5 : 0));
                        double yield = BondAnalytics.SolveYield(eCountry,settle ,price, effectiveDate, firstCpnDate, maturity, coupon, bondCpnFreq)[0];
                        output= 10000.0 * (mms - yield);


                        break;
                    }
            }
            return output;
        }
Example #11
0
        //----------------------------------------------------------------------------------------
        public static Frame<DateTime, string> SymBondFwdTimeSeries(  string[] BondId,
                                                    DateTime StartDate, 
                                                    DateTime EndDate, 
                                                    String TenorString, 
                                                    DateTime FwdDate, 
                                                    object[,] SpreadOrPrice, 
                                                    String Measure, 
                                                    Boolean bOIS, 
                                                    Boolean bSpread, 
                                                    List<DateTime> Holidays)
        //----------------------------------------------------------------------------------------
        {
            bool bHaveEverything = true;

            CarbonClient cbnClient = DataHandler.GetCarbonClient();

            try
            {
                int nBonds = BondId.GetLength(0);

                //  Holidays can be given as holiday code (string) or as array of dates.

                //  Get Bond static data

                #region Bond Static Data

                object o = null;
                DateTime[] maturity = new DateTime[nBonds],
                    effectiveDate = new DateTime[nBonds],
                    firstCpnDate = new DateTime[nBonds];
                double[] coupon = new double[nBonds];
                bool bEUR = false;
                long bondCpnFreq = 6;
                BondAnalytics.Country eCountry = BondAnalytics.Country.US, prevCountry = BondAnalytics.Country.US;
                for (int i = 0; i < nBonds; i++)
                {
                    var lid = ((String) BondId[i]).Trim().ToLower();

                    BondStatic bndStatic = DataHandler.GetBondStatic(lid);

                    maturity[i] = DateTime.FromOADate(bndStatic.Maturity);
                    effectiveDate[i] = DateTime.FromOADate(bndStatic.EffectiveDate);
                    firstCpnDate[i] = DateTime.FromOADate(bndStatic.FirstCoupon);
                    coupon[i] = bndStatic.Coupon;

                    BondAnalytics.CountryMappings.TryGetValue(((String) BondId[i]).Substring(0, 2), out eCountry);
                    if (i > 0 && eCountry != prevCountry)
                    {
                        throw new ArgumentException("#Error! All bonds must be same country!");
                    }
                    prevCountry = eCountry;
                }


                // Let's use spreadseries config
                string sCountry = ((String) BondId[0]).Substring(0, 2); // since all countries are the same
                var fcstConfig = new SpreadTimeSeriesConfigs(sCountry, bForecastCurve: true);
                var discConfig = new SpreadTimeSeriesConfigs(sCountry, bForecastCurve: false);


                bEUR = (eCountry == BondAnalytics.Country.DE || eCountry == BondAnalytics.Country.FR ||
                        eCountry == BondAnalytics.Country.IT || eCountry == BondAnalytics.Country.ES ||
                        eCountry == BondAnalytics.Country.BE
                    ? true
                    : false);
                bondCpnFreq = fcstConfig.bndCouponFreq;
                    //(eCountry == BondAnalytics.Country.US || eCountry == BondAnalytics.Country.UK || eCountry == BondAnalytics.Country.JP || eCountry == BondAnalytics.Country.CA ? 6 : 12);

                #endregion

                //  Build timeseries calendar

                #region DateSeries

                List<DateTime> dateSeries = new List<DateTime>();

                //  Ensure start and end date are good business days. Move dates forward then back to minimise chance of future dates in series.
                DateTime startDate = StartDate.AddTenor(Tenor.FromString("1b"), "")
                    .AddTenor(Tenor.FromString("-1b"), "");
                DateTime nextDate = EndDate.AddTenor(Tenor.FromString("1b"), "").AddTenor(Tenor.FromString("-1b"), "");
                if (startDate > nextDate)
                {
                    throw new ArgumentException("nextDate must be after start date");
                }
                var tenor = Tenor.FromString("-" + TenorString);
                while (nextDate >= startDate)
                {
                    dateSeries.Add(nextDate);
                    nextDate = BondAnalytics.PrevBusDay(nextDate.AddTenor(tenor, ""), Holidays);
                }
                int M = dateSeries.Count();
                //  Keep a track of pricing errors so that a failure for one bond / date does not have to cause a failure of the whole function.
                Boolean[,] bPricingCheck = new Boolean[M, nBonds];

                #endregion

                //  Need discount curve before calculating repo series.
                #region InterestCurves

                String discCurveName = discConfig.SymDiscountCurveName;
                String fcstCurveName = fcstConfig.SymForecastCurveName;
                String ccy = fcstConfig.ccy;


                // Convert DiscountCurve Object to tuples.
                var DiscCurves = new SortedDictionary<DateTime, Tuple<DateTime, double>[]>();
                var FcstCurves = new SortedDictionary<DateTime, Tuple<DateTime, double>[]>();

                // DISC.
                SortedDictionary<DateTime, DiscountCurve> DiscCurvesRaw =
                    DataHandler.getDiscountCurvesInDateRange(discCurveName, dateSeries);
                foreach (var dte in DiscCurvesRaw.Keys)
                {
                    DiscCurves[dte] = DiscCurvesRaw[dte].AsTuples();
                }

                // FCST.
                if (!bOIS && (Measure != "Repo" && Measure != "Yield" && Measure != "Price")) // only get fcst curves here
                {
                    SortedDictionary<DateTime, DiscountCurve> FcstCurvesRaw =
                    DataHandler.getDiscountCurvesInDateRange(fcstCurveName, dateSeries);
                    foreach (var dte in FcstCurvesRaw.Keys)
                    {
                        FcstCurves[dte] = FcstCurvesRaw[dte].AsTuples();
                    }
                }

                #endregion InterestCurves

                //  Get repo spread. Three cases: default is 20 day moving average of GC-OIS, alternatives are input flat rate or interpolation from input table.
                #region RepoHistory
                double[,] fwdPrices = new double[M, nBonds];
                double[,] repoSpread = new double[M, nBonds];
                //  Two column array - dates / spreads. Linear interpolation in date.
                if ((SpreadOrPrice.GetLength(1) == 2 || SpreadOrPrice.GetLength(1) == nBonds + 1) && SpreadOrPrice.GetLength(0) > 1)
                {
                    int nRepos = SpreadOrPrice.GetLength(0);
                    int nCols = SpreadOrPrice.GetLength(1);
                    DateTime[] rDates = new DateTime[nRepos];
                    double[,] rSpreads = new double[nRepos, nBonds];

                    for (int j = 0; j < nBonds; j++)
                    {
                        for (int i = 0; i < nRepos; i++)
                        {
                            if (SpreadOrPrice[i, 0] is double)
                            {
                                rDates[i] = DateTime.FromOADate((double)SpreadOrPrice[i, 0]).Date;
                                if (nCols > 1 + j && SpreadOrPrice[i, 1 + j] is double)
                                    rSpreads[i, j] = (double)SpreadOrPrice[i, 1 + j];
                                else if (1 + j >= nCols)
                                {
                                    rSpreads[i, j] = rSpreads[i, j - 1];
                                }
                                else
                                {
                                    // Spread override is not a double, pricing fails. Use -1e8 as an error warning.
                                    rSpreads[i, j] = -1e8;
                                }
                            }
                            else
                            {
                                rDates[i] = DateTime.MinValue;
                            }
                        }
                    }
                    //  Not very efficient, but need to identify matching dates when not necessarily in order because of input errors.
                    if (bSpread)
                    {
                        int k;
                        for (int i = 0; i < M; i++)
                        {
                            for (k = 0; k < nRepos; k++)
                            {
                                if (rDates[k].Date == dateSeries[i].Date)
                                {
                                    for (int j = 0; j < nBonds; j++)
                                    {
                                        if (rSpreads[i, j] < -1e7)
                                            bPricingCheck[i, j] = true;
                                        else
                                            repoSpread[i, j] = rSpreads[i, j] / 10000.0;
                                    }
                                    break;
                                }
                            }
                            if (k == nRepos)
                            {
                                for (int j = 0; j < nBonds; j++)
                                {
                                    bPricingCheck[i, j] = true;
                                }
                            }
                        }
                    }
                    else
                    {
                        int k;
                        for (int i = 0; i < M; i++)
                        {
                            for (k = 0; k < nRepos; k++)
                            {
                                if (rDates[k].Date == dateSeries[i].Date)
                                {
                                    for (int j = 0; j < nBonds; j++)
                                    {
                                        if (rSpreads[i, j] < -1e7)
                                            bPricingCheck[i, j] = true;
                                        else
                                            fwdPrices[i, j] = rSpreads[i, j];
                                    }
                                    break;
                                }
                            }
                            if (k == nRepos)
                            {
                                for (int j = 0; j < nBonds; j++)
                                {
                                    bPricingCheck[i, j] = true;
                                }
                            }
                        }
                    }
                }
                //  Cases: Single entry, double then this is the flat spread.
                else if (SpreadOrPrice.GetLength(0) == 1 && SpreadOrPrice.GetLength(1) == 1 && SpreadOrPrice[0, 0] is double)
                {
                    if (bSpread)
                    {
                        for (int j = 0; j < nBonds; j++)
                        {
                            for (int i = 0; i < M; i++)
                            {
                                repoSpread[i, j] = (double)SpreadOrPrice[0, 0] / 10000.0;
                            }
                        }
                    }
                    else
                    {
                        for (int j = 0; j < nBonds; j++)
                        {
                            for (int i = 0; i < M; i++)
                            {
                                fwdPrices[i, j] = (double)SpreadOrPrice[0, 0];
                            }
                        }
                    }
                }
                //  Vector, length nBonds
                else if (((SpreadOrPrice.GetLength(0) == nBonds && SpreadOrPrice.GetLength(1) == 1) || (SpreadOrPrice.GetLength(1) == nBonds && SpreadOrPrice.GetLength(0) == 1)) && SpreadOrPrice[0, 0] is double)
                {
                    bool bRow = SpreadOrPrice.GetLength(1) == 1;
                    if (bSpread)
                    {
                        for (int j = 0; j < nBonds; j++)
                        {
                            for (int i = 0; i < M; i++)
                                repoSpread[i, j] = (double)(bRow ? SpreadOrPrice[j, 0] : SpreadOrPrice[0, j]) / 10000.0;
                        }
                    }
                    else
                    {
                        for (int j = 0; j < nBonds; j++)
                        {
                            for (int i = 0; i < M; i++)
                                fwdPrices[i, j] = (double)(bRow ? SpreadOrPrice[j, 0] : SpreadOrPrice[0, j]);
                        }
                    }
                }
                //  Otherwise (empty, or not a double or a two column array).
                else
                {
                    bSpread = true;

                    //  Repo spread is 20 day moving average of GC - OIS
                    double[] gcHist = new double[M + 19];
                    double[] oisHist = new double[M + 19];

                    var opGC = DataHandler.GetRepoRates(eCountry, dateSeries);

                    for (int i = 0; i < M; i++)
                    {

                        // Copy GC values over (we need to extend this later)
                        gcHist[i] = opGC[i];

                        if (DiscCurves.ContainsKey(dateSeries[i]))
                        {
                            oisHist[i] = 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);
                        }
                        else
                        {
                            bHaveEverything = false;
                        }
                    }
                    //  Dates prior to dateSeries[0]
                    List<DateTime> prevDates = new List<DateTime>();
                    for (int i = 0; i < 19; i++)
                    {
                        prevDates.Add(BondAnalytics.PrevBusDay((i == 0 ? dateSeries[M - 1] : prevDates.Last()).AddDays(-1), Holidays));
                    }

                    // Get old curves
                    var PrevDiscCurves = new SortedDictionary<DateTime, Tuple<DateTime, double>[]>();

                    var prevDiscCurvesRaw = DataHandler.getDiscountCurvesInDateRange(discCurveName, prevDates);

                    foreach (var kvp in prevDiscCurvesRaw)
                    {
                        PrevDiscCurves[kvp.Key] = kvp.Value.AsTuples();
                    }

                    // Get old rates
                    double[] oldRepoRates = DataHandler.GetRepoRates(eCountry, prevDates);

                    for (int i = 0; i < 19; i++)
                    {
                        o = oldRepoRates[i];
                        if (o is double)
                        {
                            gcHist[M + i] = (double)o / 100.0;
                        }
                        else if (i > 0)
                        {
                            gcHist[M + i] = gcHist[M + i];
                        }
                        else
                            gcHist[M + i] = 0.0;

                        if (PrevDiscCurves.ContainsKey(prevDates[i]))
                        {
                            oisHist[M + i] = Math.Round((1.0 / PrevDiscCurves[prevDates[i]].ElementAt(1).Item2 - 1.0) * 360.0 / (PrevDiscCurves[prevDates[i]].ElementAt(1).Item1 - PrevDiscCurves[prevDates[i]].ElementAt(0).Item1).TotalDays, 5);
                        }
                        else
                        {
                            bHaveEverything = false;
                        }
                    }
                    for (int i = 0; i < M; i++)
                    {
                        for (int j = i; j < i + 20; j++)
                        {
                            repoSpread[i, 0] += (gcHist[j] - oisHist[j]) / 20.0;
                        }
                    }
                    for (int i = 0; i < M; i++)
                        for (int j = 1; j < nBonds; j++)
                            repoSpread[i, j] = repoSpread[i, 0];
                }
                #endregion

                //  Get Price Data (Clean Prices, Repo rates - i.e. term OIS rates + repo spreads)
                #region GetPricingData
                List<double[]> priceSeries = new List<double[]>();
                List<double[]> repoSeries = new List<double[]>();

                // Let's get price data from symmetry service
                if (bSpread)
                {

                    for (int i = 0; i < M; i++)
                    {
                        priceSeries.Add(new double[nBonds]);
                        repoSeries.Add(new double[nBonds]);
                        DateTime settleDate = BondAnalytics.NextBusDay(dateSeries[i].Date.AddDays(1), Holidays);
                        if (eCountry != BondAnalytics.Country.US)
                        {
                            settleDate = BondAnalytics.NextBusDay(dateSeries[i].Date.AddDays(2), Holidays);
                        }

                        for (int j = 0; j < nBonds; j++)
                        {
                            if (settleDate.Date > FwdDate.Date)
                            {
                                bPricingCheck[i, j] = true;
                                continue;
                            }
                            var priceMonikerName = ((String)BondId[j]).ToLower().Trim();
                            var priceMonikerDate = dateSeries[i];
                            var closeTup = DataHandler.GetCloseSnap(priceMonikerDate, eCountry);
                            var priceMonikerClose = closeTup.Item1;
                            var priceMonikerSource = closeTup.Item2;
                            
                            try
                            {
                                o = DataHandler.GetHistoryPrice(priceMonikerName, priceMonikerDate, priceMonikerClose, priceMonikerSource);
                            }
                            catch
                            {
                            }

                            if (o is double)
                                priceSeries[i][j] = (double)o;
                            else if (dateSeries[i].Date < effectiveDate[j].Date || !DiscCurves.ContainsKey(dateSeries[i]))
                            {
                                //  No price information available
                                bPricingCheck[i, j] = true;
                            }
                            else
                                bHaveEverything = false;
                        }

                        double oisSwap = 0.0;
                        if (DiscCurves.ContainsKey(dateSeries[i]))
                        {
                            DateTime[] discDfDates = DiscCurves[dateSeries[i]].Select(x => x.Item1).ToArray();
                            double[] discDfs = DiscCurves[dateSeries[i]].Select(x => x.Item2).ToArray();

                            oisSwap = settleDate.Date < FwdDate.Date ? BondAnalytics.CalcMMS(settleDate, FwdDate, BondAnalytics.DayCountType.Act360, 12, 12, discDfDates, discDfs, discDfDates, discDfs, Holidays, null, null, null, null, null, DateTime.MinValue, 5) : 0.0;
                        }
                        for (int j = 0; j < nBonds; j++)
                        {
                            repoSeries[i][j] = oisSwap + repoSpread[i, j];
                        }
                    }
                }
                #endregion

                //  Calculate measures
                #region CalcMeasures
                List<double[]> outputSeries = new List<double[]>();
                for (int i = 0; i < M; i++)
                {
                    outputSeries.Add(new double[nBonds + (Measure == "Repo" ? 1 : 0)]);
                    DateTime settleDate = BondAnalytics.NextBusDay(dateSeries[i].Date.AddDays(1), Holidays);
                    if (eCountry != BondAnalytics.Country.US)
                    {
                        settleDate = BondAnalytics.NextBusDay(dateSeries[i].Date.AddDays(2), Holidays);
                    }
                    for (int j = 0; j < nBonds; j++)
                    {
                        //  Only attempt to price if there is a chance of success!
                        if (bPricingCheck[i, j])
                            continue;
                        double fwdPrice = bSpread ? BondAnalytics.CalcBondFwd(eCountry, settleDate, priceSeries[i][j], effectiveDate[j], firstCpnDate[j], maturity[j], coupon[j], bondCpnFreq, FwdDate, repoSeries[i][j])[0] : fwdPrices[i, j];
                        switch (Measure)
                        {
                            case "Price":
                                {
                                    outputSeries[i][j] = fwdPrice;
                                    break;
                                }
                            case "Yield":
                                {
                                    outputSeries[i][j] = 10000.0 * BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate[j], firstCpnDate[j], maturity[j], coupon[j], bondCpnFreq)[0];
                                    break;
                                }
                            case "TrueSpread":
                                {
                                    if ((bOIS && DiscCurves.ContainsKey(dateSeries[i])) || FcstCurves.ContainsKey(dateSeries[i]))
                                    {
                                        DateTime[] dfDates = (bOIS ? DiscCurves[dateSeries[i]].Select(x => x.Item1).ToArray() : FcstCurves[dateSeries[i]].Select(x => x.Item1).ToArray());
                                        double[] dfs = (bOIS ? DiscCurves[dateSeries[i]].Select(x => x.Item2).ToArray() : FcstCurves[dateSeries[i]].Select(x => x.Item2).ToArray());

                                        //  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();
                                        }
                                        outputSeries[i][j] = -10000.0 * BondAnalytics.SolveZSpread(eCountry, FwdDate, fwdPrice, effectiveDate[j], firstCpnDate[j], maturity[j], coupon[j], bondCpnFreq, dfDates, dfs, Holidays);
                                    }
                                    else
                                    {
                                        bPricingCheck[i, j] = true;
                                    }
                                    break;
                                }
                            case "MMS":
                                {
                                    if (DiscCurves.ContainsKey(dateSeries[i]) && (bOIS || FcstCurves.ContainsKey(dateSeries[i])))
                                    {
                                        DateTime[] discDfDates = DiscCurves[dateSeries[i]].Select(x => x.Item1).ToArray();
                                        DateTime[] fcstDfDates = (bOIS ? discDfDates : FcstCurves[dateSeries[i]].Select(x => x.Item1).ToArray());
                                        double[] discDfs = DiscCurves[dateSeries[i]].Select(x => x.Item2).ToArray();
                                        double[] fcstDfs = (bOIS ? discDfs : FcstCurves[dateSeries[i]].Select(x => x.Item2).ToArray());
                                        BondAnalytics.DayCountType dct = (bOIS ? BondAnalytics.DayCountType.Act360 : BondAnalytics.DayCountType.E30360);
                                        int fixedFreq = (bEUR || bOIS ? 12 : 6);
                                        int floatFreq = (bOIS ? 12 : (bEUR ? 6 : 3));

                                        double mms = BondAnalytics.CalcMMS(FwdDate, maturity[j], dct, fixedFreq, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, Holidays, null, null, null, null, null, firstCpnDate[j], (bOIS ? 5 : 0));
                                        outputSeries[i][j] = 10000.0 * mms;
                                    }
                                    else
                                    {
                                        bPricingCheck[i, j] = true;
                                    }
                                    break;
                                }
                            case "Spread":
                                {
                                    if (DiscCurves.ContainsKey(dateSeries[i]) && (bOIS || FcstCurves.ContainsKey(dateSeries[i])))
                                    {
                                        DateTime[] discDfDates = DiscCurves[dateSeries[i]].Select(x => x.Item1).ToArray();
                                        DateTime[] fcstDfDates = (bOIS ? discDfDates : FcstCurves[dateSeries[i]].Select(x => x.Item1).ToArray());
                                        double[] discDfs = DiscCurves[dateSeries[i]].Select(x => x.Item2).ToArray();
                                        double[] fcstDfs = (bOIS ? discDfs : FcstCurves[dateSeries[i]].Select(x => x.Item2).ToArray());
                                        BondAnalytics.DayCountType dct = (bOIS ? BondAnalytics.DayCountType.Act360 : BondAnalytics.DayCountType.E30360);
                                        int fixedFreq = (bEUR || bOIS ? 12 : 6);
                                        int floatFreq = (bOIS ? 12 : (bEUR ? 6 : 3));

                                        double mms = BondAnalytics.CalcMMS(FwdDate, maturity[j], dct, fixedFreq, floatFreq, discDfDates, discDfs, fcstDfDates, fcstDfs, Holidays, null, null, null, null, null, firstCpnDate[j], (bOIS ? 5 : 0));
                                        double yield = BondAnalytics.SolveYield(eCountry, FwdDate, fwdPrice, effectiveDate[j], firstCpnDate[j], maturity[j], coupon[j], bondCpnFreq)[0];
                                        outputSeries[i][j] = 10000.0 * (mms - yield);
                                    }
                                    else
                                    {
                                        bPricingCheck[i, j] = true;
                                    }
                                    break;
                                }
                            case "Repo":
                                {
                                    if (bSpread)
                                    {
                                        outputSeries[i][j] = 10000 * repoSpread[i, j];
                                        if (j == 0)
                                            outputSeries[i][nBonds] = 10000 * (repoSeries[i][0] - repoSpread[i, 0]);
                                    }
                                    break;
                                }
                        }
                    }
                }
                #endregion

                Dictionary<DateTime, Series<string,double>> output = new Dictionary<DateTime, Series<string, double>>(); 

                for (int i = 0; i < M; i++)
                {
                    SeriesBuilder<string, double> sb = new SeriesBuilder<string, double>();
                    for (int j = 0; j < nBonds + (Measure == "Repo" ? 1 : 0); j++)
                    {
                        if (j < nBonds && bPricingCheck[i, j])
                        {
                            sb.Add(BondId[j], double.NaN); 
                        }
                        else
                        {
                            if (j >= nBonds)
                            {
                                sb.Add("Repo", outputSeries[i][j]); 
                            }
                            else
                            {
                                sb.Add(BondId[j], outputSeries[i][j]); 
                            }
                        }
                    }
                    output[dateSeries[i].Date] = sb.Series;
                }

                var result = Frame.FromRows(output);
                
                return result;
            }
            catch (Exception ex)
            {
                Log_.ErrorFormat("Error in BondASWCalc: {0}", ex.Message);
                throw ex;
            }
        }
 public void ShouldGetSpreadSeriesConfigs()
 {
     var config = new SpreadTimeSeriesConfigs("fr", true); 
 }