public HoldingPeriodEngine() { _bondEngine = new BondEngineCn(new BondYieldPricerCn()); _roundCleanPrice = true; }
public override IPricingResult Calculate(BondFutures bondFuture, IMarketCondition market, PricingRequest request) { var beginValuation = DateTime.Now; var pricingRequest = CheckParameterCondition(bondFuture, market, request); //if (result.IsRequested(PricingRequest.Dv01)) //{ // result.Dv01 = CalcDv01(bondFuture, market); //} var result = new PricingResult(market.ValuationDate, pricingRequest); //if (result.IsRequested(PricingRequest.Pv)) //{ // result.Pv = CalcPv(bondFuture, market); //} if (result.IsRequested(PricingRequest.DirtyPrice)) { result.DirtyPrice = market.MktQuote.Value.Where(x => x.Key == bondFuture.Id).Select(x => x.Value.Item2).First() * bondFuture.Notional / 100; } if (result.IsRequested(PricingRequest.ConvertFactors)) { result.ConvertFactors = CalcConvertFactors(bondFuture, market); } if (result.IsRequested(PricingRequest.Irr) || result.IsRequested(PricingRequest.Pv01) || result.IsRequested(PricingRequest.KeyRateDv01) || result.IsRequested(PricingRequest.ZeroSpread) || result.IsRequested(PricingRequest.ZeroSpreadDelta) || result.IsRequested(PricingRequest.UnderlyingPv) || result.IsRequested(PricingRequest.Basis) || result.IsRequested(PricingRequest.Convexity) || result.IsRequested(PricingRequest.Ytm) || result.IsRequested(PricingRequest.CheapestToDeliver) || result.IsRequested(PricingRequest.ModifiedDuration) || result.IsRequested(PricingRequest.MacDuration) ) { //TODO: wierd update logic, why bother? var mktQuote = market.MktQuote.Value.Keys.Where(quoteKey => !quoteKey.Contains(bondFuture.Id + "_")).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]); var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote)); var yieldPricer = new BondFuturesYieldPricer(bondFuture, updateMarket); //calculate convert factors if (!result.ConvertFactors.Any()) { result.ConvertFactors = CalcConvertFactors(bondFuture, market); } var convertFactors = result.ConvertFactors; //calculate IRR result.ProductSpecific = yieldPricer.CalcEquation("FromFuturesPriceAndBondPrice"); //calculate pv01 var maxIrr = result.ProductSpecific["Irr"].Values.Select(x => x.Rate).Max(); var ctdBondId = result.ProductSpecific["Irr"].First(x => x.Value.Rate == maxIrr).Key; var ctdBond = bondFuture.Deliverables.First(x => x.Id == ctdBondId); var cf = convertFactors[ctdBondId]; var scaling = bondFuture.Notional / (100.0 * cf); var engine = new BondEngineCn(); result.CheapestToDeliver = ctdBondId; //two risks here are CTD risk, not bond futures risk var resultCTD = engine.Calculate(ctdBond, market, PricingRequest.All); result.ZeroSpread = resultCTD.ZeroSpread; result.UnderlyingPv = resultCTD.Pv * scaling; result.Basis = yieldPricer.CalcFutureCtdBasis(ctdBond, cf); result.Ytm = resultCTD.Ytm; result.MacDuration = resultCTD.MacDuration; result.ModifiedDuration = resultCTD.ModifiedDuration; result.Convexity = resultCTD.Convexity; result.DollarConvexity = resultCTD.DollarConvexity * scaling; // 1% price impact result.DollarModifiedDuration = resultCTD.DollarModifiedDuration * scaling; // same order of magnitutude of CTD dollar modifiedDuration, good for pnl attribution //convert to bond futures risk result.Pv01 = resultCTD.Pv01 * scaling; // underlying pv01 is foreach (var kvp in resultCTD.KeyRateDv01) { foreach (var risk in kvp.Value) { risk.Risk *= scaling; } } result.KeyRateDv01 = resultCTD.KeyRateDv01; result.ZeroSpreadDelta = resultCTD.ZeroSpreadDelta * scaling; } if (result.IsRequested(PricingRequest.FairQuote)) { var mktQuote = market.MktQuote.Value.Keys.Where(quoteKey => !quoteKey.Equals(bondFuture.Id)).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]); var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote)); var yieldPricer = new BondFuturesYieldPricer(bondFuture, updateMarket); result.ProductSpecific = yieldPricer.CalcEquation("FromBondPriceAndIrr"); } if (result.IsRequested(PricingRequest.MktQuote)) { result.ProductSpecific = CalcMktFuturePrice(bondFuture, market); } if (result.IsRequested(PricingRequest.UnderlyingFairQuote)) { var mktQuote = market.MktQuote.Value.Keys.Where(quoteKey => quoteKey.Contains(bondFuture.Id)).ToDictionary(quoteKey => quoteKey, quoteKey => market.MktQuote.Value[quoteKey]); var updateMarket = market.UpdateCondition(new UpdateMktConditionPack <Dictionary <string, Tuple <PriceQuoteType, double> > >(x => x.MktQuote, mktQuote)); var yieldPricer = new BondFuturesYieldPricer(bondFuture, updateMarket); result.ProductSpecific = yieldPricer.CalcEquation("FromFuturesPriceAndIrr"); } var endValuation = DateTime.Now; result.CalcTimeInMilliSecond = (endValuation - beginValuation).TotalMilliseconds; return(result); }