예제 #1
0
        public void TestTfDeliverableBondCf()
        {
            var startDates    = new[] { new Date(2016, 04, 06), new Date(2016, 04, 06), new Date(2016, 04, 06), };
            var maturityDates = new[] { new Date(2016, 06, 15), new Date(2016, 09, 14), new Date(2016, 12, 13), };
            var files         = new[] { "QbTF1606CfTest.txt", "QbTF1609CfTest.txt", "QbTF1612CfTest.txt" };
            var futuresNames  = new[] { "TF1606", "TF1609", "TF1612" };

            for (var k = 0; k < startDates.Length; ++k)
            {
                var bondPrices = new Dictionary <string, double>();
                var targetConversionFactors = new List <double>();
                var bonds = File.ReadAllLines(@"./Data/BondFuture/" + files[k])
                            .Select(x =>
                {
                    var splits       = x.Split(',');
                    var startDate    = new Date(DateTime.Parse(splits[3]));
                    var maturityDate = new Date(DateTime.Parse(splits[4]));
                    var rate         = Convert.ToDouble(splits[1]);
                    var frequency    = splits[2] == "Annual" ? Frequency.Annual : Frequency.SemiAnnual;
                    targetConversionFactors.Add(Convert.ToDouble(splits[5]));
                    bondPrices[splits[0]] = Convert.ToDouble(splits[6]);
                    return(new Bond(
                               splits[0],
                               startDate,
                               maturityDate,
                               100.0,
                               CurrencyCode.CNY,
                               new FixedCoupon(rate),
                               CalendarImpl.Get("chn_ib"),
                               frequency,
                               Stub.LongEnd,
                               new Act365(),
                               new Act365(),
                               BusinessDayConvention.None,
                               BusinessDayConvention.ModifiedFollowing,
                               null,
                               TradingMarket.ChinaInterBank));
                }).ToArray();

                var bondfuture = new BondFutures(
                    futuresNames[k],
                    startDates[k],
                    maturityDates[k],
                    maturityDates[k],
                    CalendarImpl.Get("chn"),
                    bonds,
                    new Act365()
                    );
                var market = new BondFutureTests().TestMarket("2016-04-06");
                for (var i = 0; i < bonds.Length; ++i)
                {
                    Assert.AreEqual(bondfuture.GetConversionFactor(bonds[i], market), targetConversionFactors[i]);
                }
            }
        }
예제 #2
0
        private Dictionary <string, double> CalcConvertFactors(BondFutures bondFuture, IMarketCondition market)
        {
            var bonds = bondFuture.Deliverables;
            var cfs   = new Dictionary <string, double>();

            foreach (var bond in bonds)
            {
                var cf = bondFuture.GetConversionFactor(bond, market);
                cfs.Add(bond.Id, cf);
            }
            return(cfs);
        }
예제 #3
0
        private double CalcPv(BondFutures bondFuture, IMarketCondition market)
        {
            var discountCurve = market.DiscountCurve.Value;
            var dayCount      = bondFuture.DayCount;

            var tree = _interestRateModel.Tree(GetGridTimes(bondFuture, market), 0.0, discountCurve);

            var deliveryTime    = dayCount.CalcDayCountFraction(market.ValuationDate, bondFuture.UnderlyingMaturityDate);
            var indexAtDelivery = tree.IndexAtT(deliveryTime);

            var bonds             = bondFuture.Deliverables;
            var ais               = bonds.Select(x => x.GetAccruedInterest(bondFuture.UnderlyingMaturityDate, market, true)).ToArray();
            var conversionFactors = bonds.Select(x => bondFuture.GetConversionFactor(x, market)).ToArray();

            var zeroSpreads =
                bonds.Select((bond, i) => BondPricingFunctions.ZeroSpread(bond, market)
                             ).ToArray();

            var nNodesAtDelivery = tree.TrinomialTree.Branchings[indexAtDelivery].Size;

            var futurePricesAtDelivery = new double[nNodesAtDelivery];

            for (var j = 0; j < nNodesAtDelivery; ++j)
            {
                var simulationRate = tree.ShortRate(indexAtDelivery, j);
                var bondPrices     = bonds
                                     .Select((x, i) =>
                {
                    var cfs    = x.GetCashflows(market).Where(cf => cf.PaymentDate > bondFuture.UnderlyingMaturityDate).ToArray();
                    var bPrice = 0.0;
                    foreach (var cf in cfs)
                    {
                        var T    = dayCount.CalcDayCountFraction(market.ValuationDate, cf.PaymentDate);
                        var P    = tree.DiscountBond(deliveryTime, T, simulationRate);
                        var rate = discountCurve.Compound.CalcRateFromDf(P, T - deliveryTime);
                        var df   = 1.0 / discountCurve.Compound.CalcCompoundRate(T - deliveryTime, rate + zeroSpreads[i]);
                        bPrice  += cf.PaymentAmount * df;
                    }
                    return(bPrice);
                }).ToArray();

                var futurePricesAtNodes = bondPrices
                                          .Select((price, k) => price - ais[k])
                                          .Select((cleanPrice, k) => cleanPrice / conversionFactors[k]).ToList();
                futurePricesAtDelivery[j] = futurePricesAtNodes.Min();
            }

            return(tree.ReverseInduction(null, null, indexAtDelivery, futurePricesAtDelivery, false)[0][0]);
        }
예제 #4
0
        //only used if we switch from CTD model to basket model
        private double CalcDv01(BondFutures bondFuture, IMarketCondition market)
        {
            var discountCurve = market.DiscountCurve.Value;
            var dayCount      = bondFuture.DayCount;

            var tree = _interestRateModel.Tree(GetGridTimes(bondFuture, market), 0.0, discountCurve);

            var deliveryTime = dayCount.CalcDayCountFraction(market.ValuationDate, bondFuture.UnderlyingMaturityDate);

            var bonds             = bondFuture.Deliverables;
            var ais               = bonds.Select(x => x.GetAccruedInterest(bondFuture.UnderlyingMaturityDate, market, true)).ToArray();
            var conversionFactors = bonds.Select(x => bondFuture.GetConversionFactor(x, market)).ToArray();

            var zeroSpreads =
                bonds.Select((bond, i) =>
                             BondPricingFunctions.ZeroSpread(bond, market)
                             ).ToArray();

            var simulationRate = tree.ShortRate(0, 0);
            var bondPrices     = bonds
                                 .Select((x, i) =>
            {
                var cfs    = x.GetCashflows(market).Where(cf => cf.PaymentDate > bondFuture.UnderlyingMaturityDate).ToArray();
                var bPrice = 0.0;
                foreach (var cf in cfs)
                {
                    var T    = dayCount.CalcDayCountFraction(market.ValuationDate, cf.PaymentDate);
                    var P    = tree.DiscountBond(deliveryTime, T, simulationRate);
                    var rate = discountCurve.Compound.CalcRateFromDf(P, T - deliveryTime);
                    var df   = 1.0 / discountCurve.Compound.CalcCompoundRate(T - deliveryTime, rate + zeroSpreads[i]);
                    bPrice  += cf.PaymentAmount * df;
                }
                return(bPrice);
            }).ToArray();

            var futurePrices = bondPrices
                               .Select((price, k) => price - ais[k])
                               .Select((cleanPrice, k) => cleanPrice / conversionFactors[k]).ToList();

            var futurePrice  = futurePrices.Min();
            var index        = futurePrices.FirstIndexOf(x => (x - futurePrice).IsAlmostZero());
            var ctdBond      = bonds[index];
            var ctdBondPrice = market.MktQuote.Value[ctdBond.Id];

            return
                (new BondEngine().Calculate(ctdBond, market, PricingRequest.Dv01).Dv01);
        }
예제 #5
0
        private Dictionary <string, Dictionary <string, RateRecord> > CalcMktFuturePrice(BondFutures bondFuture, IMarketCondition market)
        {
            var psDict       = new Dictionary <string, Dictionary <string, RateRecord> >();
            var fundingCurve = market.RiskfreeCurve.HasValue
                                ? market.RiskfreeCurve.Value
                                : YieldCurve.GetConstRateCurve(market.DiscountCurve.Value, 0.0);
            var reinvestmentCurve = market.DiscountCurve.HasValue
                                ? market.DiscountCurve.Value
                                : YieldCurve.GetConstRateCurve(market.RiskfreeCurve.Value, 0.0);

            var bonds  = bondFuture.Deliverables;
            var length = bonds.Length;

            var aiAtStart = bonds.Select(x => x.GetAccruedInterest(market.ValuationDate, market, false)).ToArray();
            var aiAtEnd   = bonds.Select(x => x.GetAccruedInterest(bondFuture.UnderlyingMaturityDate, market, false)).ToArray();
            var cf        = bonds.Select(x => bondFuture.GetConversionFactor(x, market)).ToArray();

            var coupons                      = new double[length];
            var timeWeightedCoupon           = new double[length];
            var couponsAccruedByReinvestment = new double[length];

            for (var i = 0; i < length; ++i)
            {
                var bond      = bonds[i];
                var cashflows = bond.GetCashflows(market, false).Where(x => x.PaymentDate > market.ValuationDate && x.PaymentDate <= bondFuture.UnderlyingMaturityDate).ToArray();
                if (cashflows.Any())
                {
                    coupons[i]                      = cashflows.Sum(x => x.PaymentAmount);
                    timeWeightedCoupon[i]           = cashflows.Sum(x => x.PaymentAmount * bondFuture.DayCount.CalcDayCountFraction(x.PaymentDate, bondFuture.UnderlyingMaturityDate));
                    couponsAccruedByReinvestment[i] = cashflows.Sum(x => x.PaymentAmount * (reinvestmentCurve.GetCompoundedRate2(x.PaymentDate, bondFuture.UnderlyingMaturityDate) - 1.0));
                }
                else
                {
                    coupons[i]                      = 0.0;
                    timeWeightedCoupon[i]           = 0.0;
                    couponsAccruedByReinvestment[i] = 0.0;
                }
            }

            var interestIncome = bonds.Select((x, i) => aiAtEnd[i] - aiAtStart[i] + coupons[i] + couponsAccruedByReinvestment[i]).ToArray();
            //var interestIncome = bonds.Select((x, i) => aiAtEnd[i] - aiAtStart[i] + coupons[i]).ToArray();

            var dirtyPrice       = new double[length];
            var cleanPrice       = new double[length];
            var ytm              = new double[length];
            var modifiedDuration = new double[length];

            var bondEngine = new BondEngine();

            for (var i = 0; i < length; ++i)
            {
                var bResult = bondEngine.Calculate(bonds[i], market, PricingRequest.Ytm | PricingRequest.ModifiedDuration);
                dirtyPrice[i] = bResult.DirtyPrice;
                cleanPrice[i] = bResult.CleanPrice;
                ytm[i]        = bResult.Ytm;
            }

            var interestCostRate = fundingCurve.GetCompoundedRate2(market.ValuationDate, bondFuture.UnderlyingMaturityDate) - 1.0;
            var interestCost     = dirtyPrice.Select(x => x * interestCostRate).ToArray();

            var futurePrice  = new double[length];
            var irr          = new double[length];
            var basis        = new double[length];
            var pnl          = new double[length];
            var netBasis     = new double[length];
            var invoicePrice = new double[length];
            var margin       = new double[length];
            var spread       = new double[length];

            var fundingRate = fundingCurve.GetSpotRate(0.0);

            var compoundedRate = fundingCurve.GetCompoundedRate2(market.ValuationDate, bondFuture.UnderlyingMaturityDate);
            var bondPricesCompounedByFunding = bonds.Select((x, i) => dirtyPrice[i] * compoundedRate).ToArray();

            for (var i = 0; i < bonds.Length; ++i)
            {
                futurePrice[i] = (bondPricesCompounedByFunding[i] - aiAtEnd[i] - coupons[i]) / cf[i];

                var newMarket =
                    market.UpdateCondition(
                        new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote,
                                                                                                           market.MktQuote.Value.UpdateKey(bondFuture.Id, Tuple.Create(PriceQuoteType.Dirty, futurePrice[i]))));

                var yieldPricer = new BondFuturesYieldPricer(bondFuture, newMarket);
                var tmpResult   = yieldPricer.CalcEquation("FromFuturesPriceAndBondPrice");

                invoicePrice[i] = tmpResult["InvoicePrice"][bonds[i].Id].Rate;
                margin[i]       = tmpResult["Margin"][bonds[i].Id].Rate;

                basis[i]    = tmpResult["Basis"][bonds[i].Id].Rate;
                pnl[i]      = tmpResult["PnL"][bonds[i].Id].Rate;
                netBasis[i] = tmpResult["NetBasis"][bonds[i].Id].Rate;

                irr[i]    = tmpResult["Irr"][bonds[i].Id].Rate;
                spread[i] = irr[i] - fundingRate;
            }

            psDict["FuturesPrice"] = futurePrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["BondDirtyPrice"] = dirtyPrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["BondCleanPrice"] = cleanPrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["BondYieldToMaturity"] = ytm.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["ConversionFactor"] = cf.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["AiStart"] = aiAtStart.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["AiEnd"] = aiAtEnd.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["Coupon"] = coupons.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["InterestIncome"] = interestIncome.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["InterestCost"] = interestCost.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["PnL"] = pnl.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["InvoicePrice"] = invoicePrice.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["Margin"] = margin.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["Spread"] = spread.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["Irr"] = irr.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["Basis"] = basis.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["NetBasis"] = netBasis.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["ModifiedDuration"] = modifiedDuration.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);
            psDict["TimeWeightedCoupon"] = timeWeightedCoupon.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                Rate = x
            })).ToDictionary(x => x.Item1, x => x.Item2);

            return(psDict);
        }
예제 #6
0
        public Dictionary <string, Dictionary <string, RateRecord> > CalcEquation(string calcType)
        {
            var psDict            = new Dictionary <string, Dictionary <string, RateRecord> >();
            var fundingCurve      = _market.RiskfreeCurve.HasValue ? _market.RiskfreeCurve.Value : YieldCurve.GetConstRateCurve(_market.DiscountCurve.Value, 0.0);
            var reinvestmentCurve = _market.DiscountCurve.HasValue ? _market.DiscountCurve.Value : YieldCurve.GetConstRateCurve(_market.RiskfreeCurve.Value, 0.0);

            var bonds  = _bondFuture.Deliverables;
            var length = bonds.Length;

            var resultRateRecord = new Dictionary <string, double> [length];

            for (var i = 0; i < length; ++i)
            {
                var resultDic = new Dictionary <string, double>();
                _bond = bonds[i];
                var tfBondId = _bondFuture.Id + "_" + _bond.Id;

                _cleanPriceMktFlg = IsCleandPrice(_bond.Id);

                resultDic["AiStart"]          = _bond.GetAccruedInterest(_market.ValuationDate, _market, false);
                resultDic["AiEnd"]            = _bond.GetAccruedInterest(_bondFuture.UnderlyingMaturityDate, _market, false);
                resultDic["ConversionFactor"] = _bondFuture.GetConversionFactor(_bond, _market);
                resultDic["fundingRate"]      = fundingCurve.GetSpotRate(0.0);

                _cashflows = _bond.GetCashflows(_market, false).Where(x => x.PaymentDate > _market.ValuationDate && x.PaymentDate <= _bondFuture.UnderlyingMaturityDate).ToArray();
                if (_cashflows.Any())
                {
                    resultDic["Coupon"]                       = _cashflows.Sum(x => x.PaymentAmount);
                    resultDic["TimeWeightedCoupon"]           = _cashflows.Sum(x => x.PaymentAmount * _bondFuture.DayCount.CalcDayCountFraction(x.PaymentDate, _bondFuture.UnderlyingMaturityDate));
                    resultDic["couponsAccruedByReinvestment"] = _cashflows.Sum(x => x.PaymentAmount * (reinvestmentCurve.GetCompoundedRate2(x.PaymentDate, _bondFuture.UnderlyingMaturityDate) - 1.0));
                }
                else
                {
                    resultDic["Coupon"]                       = 0.0;
                    resultDic["TimeWeightedCoupon"]           = 0.0;
                    resultDic["couponsAccruedByReinvestment"] = 0.0;
                }
                //Note: what is this interest income for?
                resultDic["InterestIncome"]   = resultDic["AiEnd"] - resultDic["AiStart"]; //  * resultDic["ConversionFactor"];
                resultDic["interestCostRate"] = RepoCostRate();
                resultDic["dt"] = _bondFuture.DayCount.CalcDayCountFraction(_market.ValuationDate, _bondFuture.UnderlyingMaturityDate);

                var    inputValues = new double[3];
                double calcMin     = 0.0;
                double calcMax     = 0.0;
                int    changIndex  = 0;
                FunctionVariable.UnivariateFunction fcn = null;
                switch (calcType)
                {
                case "FromFuturesPriceAndBondPrice":
                    inputValues[0] = FuturePrice();
                    inputValues[1] = double.NaN;
                    inputValues[2] = double.NaN;

                    calcMin    = -500.0;
                    calcMax    = 500.0;
                    changIndex = 2;
                    fcn        = new FunctionVariable.UnivariateFunction(resultDic, IrrEquation, inputValues);
                    break;

                case "FromBondPriceAndIrr":
                    inputValues[0] = double.NaN;
                    inputValues[1] = double.NaN;
                    fcn            = GetCalcEquation(tfBondId, inputValues, resultDic);

                    calcMin    = 1.0;
                    calcMax    = 50000.0;
                    changIndex = 0;
                    //BrentZero2<IUnivariateFunction>.DoSolve(fcn, 0.0, 50000.0, 0);
                    break;

                case "FromFuturesPriceAndIrr":
                    inputValues[0] = FuturePrice();
                    inputValues[1] = double.NaN;
                    fcn            = GetCalcEquation(tfBondId, inputValues, resultDic);

                    calcMin    = 1.0;
                    calcMax    = 50000.0;
                    changIndex = 1;
                    //BrentZero2<IUnivariateFunction>.DoSolve(fcn, calcMin, calcMax, changIndex);
                    break;
                }
                BrentZero2 <IUnivariateFunction> .DoSolve(fcn, calcMin, calcMax, changIndex);

                resultRateRecord[i] = resultDic;
            }

            var resultKeyList = new List <string>()
            {
                "FuturesPrice"
                , "BondDirtyPrice"
                , "BondCleanPrice"
                , "BondYieldToMaturity"
                , "ConversionFactor"
                , "AiStart"
                , "AiEnd"
                , "Coupon"
                , "InterestIncome"
                , "InterestCost"
                , "PnL"
                , "InvoicePrice"
                , "Margin"
                , "Spread"
                , "Irr"
                , "Basis"
                , "NetBasis"
                , "ModifiedDuration"
                , "TimeWeightedCoupon"
            };

            foreach (var resultKey in resultKeyList)
            {
                psDict[resultKey] = resultRateRecord.Select((x, i) => Tuple.Create(bonds[i].Id, new RateRecord {
                    Rate = x[resultKey]
                })).ToDictionary(x => x.Item1, x => x.Item2);
            }
            return(psDict);
        }