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