private BondSpreadResult ComputeCloseFutureBondSpread(BondAnalytics.Country eCountry, Future f, long Freq,
          Dictionary<DateTime, double> liborInterestCurveDict, Dictionary<DateTime, double> oisInterestCurveDict)
        {
            try
            {
                if (liborInterestCurveDict == null || oisInterestCurveDict == null)
                    return null;

                var floas = BondAnalytics.SolveZSpread(eCountry, f.Delivery, f.BondPriceClose,
                    DateTime.MinValue,
                    DateTime.MinValue,
                    f.Maturity, f.Coupon, Freq,
                    liborInterestCurveDict.Keys.ToArray(),
                    liborInterestCurveDict.Values.ToArray(), new List<DateTime>());
                var foisoas = BondAnalytics.SolveZSpread(eCountry, f.Delivery, f.BondPriceClose,
                    DateTime.MinValue,
                    DateTime.MinValue,
                    f.Maturity, f.Coupon, Freq,
                    oisInterestCurveDict.Keys.ToArray(),
                    oisInterestCurveDict.Values.ToArray(), new List<DateTime>());

                floas = (floas == -1.0) ? double.NaN : -1 * floas * 10000;
                foisoas = (foisoas == -1.0) ? double.NaN : -1 * foisoas * 10000;
                var isFront = GetCTDFlagForBond(f.Contract) == CTDFlag.Front;
                var isBack = GetCTDFlagForBond(f.Contract) == CTDFlag.Back;


                return new BondSpreadResult
                {
                    Ticker = f.Contract,
                    Coupon = f.Coupon,
                    IssueDate = f.IssueDate,
                    EffectiveDate = f.Delivery,
                    Maturity = f.Maturity,
                    LOAS = floas,
                    OISOAS = foisoas,
                    FwdLOASFront = isFront ? floas : double.NaN,
                    FwdLOASBack = isBack ? floas : double.NaN,
                    FwdOISOASFront = isFront ? foisoas : double.NaN,
                    FwdOISOASBack = isBack ? foisoas : double.NaN,
                    Price = f.ClosePrice,
                    BondPriceUsed = f.BondPriceClose,
                    CtdBondCusipUsed = f.CTDReuters,
                    InstrumentType = InstrumentType.BondFuture,                    
                    Series = f.Header,
                    IsLive = false,
                };
            }
            catch (Exception e)
            {
                Log.Error(string.Format("Failed to compute future spread for {0}", f.Contract), e);
                return null;                
            }
           
        }
        public void EnrichFuture(Future futures, Dictionary<DateTime, double> oisCurveLive, Dictionary<DateTime, double> liborCurveLive,
                                Dictionary<DateTime, double> oisCurve, Dictionary<DateTime, double> liborCurve,
                                BondSpreadCalculator bondSpreadCalculator)
        {
            // can throw exceptions



            // default country to US
            var eCountry = BondAnalytics.Country.US;

            // obtain delivery date
            futures.Delivery = EnrichDeliveryDate(futures);
            RealTimeBondData bondData;
            // go to the calculator cache to obtain bond prices.
            bondSpreadCalculator.GetBondPrices().TryGetValue(futures.RTTicker, out bondData);
            futures.LivePrice = double.NaN;
            if (bondData != null)
            {
                futures.LivePrice = (bondData.Bid + bondData.Ask)/2;
                futures.LivePriceTimeUtc = bondData.UtcTime;
            }
            double closePrice;
            if (!histPriceCache.TryGetValue(futures.RTTicker, out closePrice))
            {
                //**** only fetch closes from symmetry service for front and back month contract in order to reduce hammering the service too much
                // this logic could be removed when closes have migrated to carbon
                var futureDateCode = FutureContractCode(futures.Contract);
                if (futureDateCode == _futureBuilder.FrontTicker || futureDateCode == _futureBuilder.BackTicker)
                {
                    //var histPriceObj = bondServiceModel.GetHistoryPrice(futures.Contract + " Comdty", _futureBuilder.AsOfDate, "Close");
                    //closePrice = histPriceObj != null ? histPriceObj.Price : double.NaN;
                    closePrice = bondServiceModel.GetCarbonHistoryPrice(futures.Contract + " Comdty", _futureBuilder.AsOfDate);
                    if (!double.IsNaN(closePrice))
                        histPriceCache[futures.RTTicker] = closePrice;
                }
                else
                {
                    // not front and back contract, skip close
                    Log.InfoFormat("close price skipped for future {0}", futures.Contract);
                    closePrice = double.NaN;
                }
                
            }
            else
                closePrice = histPriceCache[futures.RTTicker];
            
            futures.ClosePrice = closePrice;
                     
            
            // get CTD static data
            RealTimeBondData ctdData=null;
            if (!string.IsNullOrEmpty(futures.CTDRic))
                bondSpreadCalculator.GetBondPrices().TryGetValue(futures.CTDRic, out ctdData);
            else
                Log.ErrorFormat("no CTD ric found for future {0}, please ensure its setup in the BSServiceClient tool", futures.Contract);


            
            // either get from carbon or override
            var ctdRecord = FetchSavedCTDFromMongo(futures.Contract);

            // validation check
            // if no ctd override and carbon data, we cannot proceed further
            if ((ctdData == null || string.IsNullOrEmpty(ctdData.BKGD_REF)) &&
                (ctdRecord == null || string.IsNullOrEmpty(ctdRecord.CTDCusip)))
            {
                Log.ErrorFormat("no ctd override and carbon data, we cannot proceed further for {0}", futures.Contract);
                return;
            }


            futures.CTDReuters =(ctdRecord == null || string.IsNullOrEmpty(ctdRecord.CTDCusip)) ? ctdData.BKGD_REF.TrimEnd('=') : ctdRecord.CTDCusip.TrimEnd('=');
            BondStatic ctdStatic;
            if (futureStaticCache.ContainsKey(futures.CTDReuters))
                ctdStatic = futureStaticCache[futures.CTDReuters];
            else
            {
                ctdStatic = bondServiceModel.GetSingleSecurityMetadata(futures.CTDReuters);
                futureStaticCache[futures.CTDReuters] = ctdStatic;
            }
            futures.CTD = ctdStatic.MLP;
            futures.IssueDate = DateTime.FromOADate(ctdStatic.IssueDate);
            futures.Maturity = DateTime.FromOADate(ctdStatic.Maturity);
            futures.Coupon = ctdStatic.Coupon;

            // beware that the delivery date used to compute conversion factor is from the long dated future, therefore we need to roll back 3 days for short dated futures
            var deliveryDateUsedForConvFactor = (futures.IsShortLong == ShortLongFuture.ShortDated) ? bondServiceModel.RollDate(futures.Delivery, -3, DateUnit.Bd , 
                                                                                                    BusinessDayConvention.Following, "USNY").ContinueWith(a => a.Result.ToDateTime()).Result
                                                                                                    : futures.Delivery;
            futures.ConvFator = BondAnalytics.CalcBondCF(futures.Coupon, futures.IssueDate, DateTime.MinValue, futures.Maturity, deliveryDateUsedForConvFactor, futures.Header, 0.0);

            // ctd bond
            if (double.IsNaN(futures.LivePrice))
            {
                futures.BondPriceLive = double.NaN;
                futures.FwdYieldLive = double.NaN;
            }
            else
            {
                futures.BondPriceLive = futures.LivePrice * futures.ConvFator;
                futures.FwdYieldLive = BondAnalytics.SolveYield(eCountry, futures.Delivery, futures.BondPriceLive, DateTime.MinValue, DateTime.MinValue, futures.Maturity, futures.Coupon, 6).First();                
            }
                    
            futures.BondPriceClose = futures.ClosePrice*futures.ConvFator;                    
            futures.FwdYieldClose = BondAnalytics.SolveYield(eCountry, futures.Delivery, futures.BondPriceClose, DateTime.MinValue,DateTime.MinValue, futures.Maturity, futures.Coupon, 6).First();

            if (liborCurveLive != null)
            {
                Log.DebugFormat("deliver{0} mat{1} oiscurve{2} libor{3}", futures.Delivery, futures.Maturity, oisCurve.Keys.Select(d => d.ToString("yyyy-MM-dd")).ToArray().JoinStrings(";"), liborCurveLive.Keys.Select(d => d.ToString("yyyy-MM-dd")).ToArray().JoinStrings(";"));
                futures.LMMSLive = BondAnalytics.CalcMMS(futures.Delivery, futures.Maturity, BondAnalytics.DayCountType.I30360, 6, 3, oisCurve.Keys.ToArray(),oisCurve.Values.ToArray(),
                                                    liborCurveLive.Keys.ToArray(), liborCurveLive.Values.ToArray(), null, null, null, null, null, null, DateTime.MinValue);
            }
            futures.LMMSClose = BondAnalytics.CalcMMS(futures.Delivery, futures.Maturity, BondAnalytics.DayCountType.I30360, 6, 3, oisCurve.Keys.ToArray(), oisCurve.Values.ToArray(),
                                                    liborCurve.Keys.ToArray(), liborCurve.Values.ToArray(), null, null, null, null, null, null, DateTime.MinValue);
            if (oisCurveLive != null)
                futures.OISMMSLive = BondAnalytics.CalcMMS(futures.Delivery, futures.Maturity, BondAnalytics.DayCountType.I30360, 12, 12, oisCurve.Keys.ToArray(), oisCurve.Values.ToArray(),
                                                    oisCurveLive.Keys.ToArray(), oisCurveLive.Values.ToArray(), null, null, null, null, null, null, DateTime.MinValue);
            futures.OISMMSClose = BondAnalytics.CalcMMS(futures.Delivery, futures.Maturity, BondAnalytics.DayCountType.I30360, 12, 12, oisCurve.Keys.ToArray(), oisCurve.Values.ToArray(),
                                                    oisCurve.Keys.ToArray(), oisCurve.Values.ToArray(), null, null, null, null, null, null, DateTime.MinValue);

            futures.CanComputeSpread = true;
             
            
        }
        private DateTime EnrichDeliveryDate(Future futures)
        {
            ValididateFutureContract(futures);
            
            var futureDateCode = FutureContractCode(futures.Contract);

            if (futures.Header == "TU" || futures.Header == "FV")
            {
                if (futureDateCode == _futureBuilder.PrevFrontTicker)
                    return _futureBuilder.PrevFrontRollShort;
                if (futureDateCode == _futureBuilder.FrontTicker)
                    return _futureBuilder.FrontRollShort;
                if (futureDateCode == _futureBuilder.BackTicker)
                    return _futureBuilder.BackRollShort;
                if (futureDateCode == _futureBuilder.Back2Ticker)
                    return _futureBuilder.Back2RollShort;
            }
            else if (futures.Header == "TY" || futures.Header == "US" || futures.Header == "WN")
            {
                if (futureDateCode == _futureBuilder.PrevFrontTicker)
                    return _futureBuilder.PrevFrontRollLong;
                if (futureDateCode == _futureBuilder.FrontTicker)
                    return _futureBuilder.FrontRollLong;
                if (futureDateCode == _futureBuilder.BackTicker)
                    return _futureBuilder.BackRollLong;
                if (futureDateCode == _futureBuilder.Back2Ticker)
                    return _futureBuilder.Back2RollLong;
            }

            return DateTime.MinValue;
        }
        private void ValididateFutureContract(Future futures)
        {
            var futureDateCode = FutureContractCode(futures.Contract);
            
            if(futureDateCode != _futureBuilder.PrevFrontTicker
                && futureDateCode != _futureBuilder.FrontTicker
                && futureDateCode != _futureBuilder.BackTicker
                && futureDateCode != _futureBuilder.Back2Ticker)                
                throw new Exception("Invalid Future contract");       

        }
Example #5
0
 protected bool Equals(Future other)
 {
     return string.Equals(Contract, other.Contract) && string.Equals(RTTicker, other.RTTicker) && string.Equals(CTD, other.CTD) && string.Equals(CTDRic, other.CTDRic);
 }