//-----------------------------------------------------------------------------------
        // 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;

            }
        }