public override ResetStrikeOption GenerateInstrument() { var startDate = TradeInfo.StartDate.ToDate(); var calendar = TradeInfo.Calendar.ToCalendarImpl(); var strikefixingDate = TradeInfo.StrikeFixingDate.ToDate(); TradeUtil.GenerateOptionDates(TradeInfo, out Date[] exerciseDates, out Date[] obsDates, out DayGap settlementGap);
public static Dictionary <string, PnLResultBase> DoPnLExplain(string[] tradeIds, PrebuiltQdpMarket t0Mkt, PrebuiltQdpMarket t1Mkt, PrebuiltQdpMarket t0MktDateRolledFwd, PrebuiltQdpMarket t0MktRolldownForBond, PrebuiltQdpMarket t0MktPriceNow = null, PrebuiltQdpMarket t0MktPriceVolNow = null, PrebuiltQdpMarket t0MktVolNow = null) { //TODO: add the following for more exotic product where rate/price interplay is more pronounced //resultRateNow, resultPriceRateNow, resultVolRateNow, resultPriceVolRateNow var useRevalPnLFramework = (t0MktPriceNow != null && t0MktVolNow != null && t0MktPriceVolNow != null); //use reval for pnl attribution //PnL = PriceImpact + VolImpact + PriceVolCrossImpact + Unexplained var ret = new Dictionary <string, PnLResultBase>(); var tMarketName = t0Mkt.MarketName; var t1MarketName = t1Mkt.MarketName; var t0Vals = new Dictionary <string, IPricingResult>(); var t0ValsRolledForward = new Dictionary <string, IPricingResult>(); var t1Vals = new Dictionary <string, IPricingResult>(); var t0ValsPriceNow = new Dictionary <string, IPricingResult>(); var t0RolldownPriceForBond = new Dictionary <string, IPricingResult>(); var t0ValsVolNow = new Dictionary <string, IPricingResult>(); var t0ValsPriceVolNow = new Dictionary <string, IPricingResult>(); //use minimium price request to make it faster #region requests var pricingRequest = PricingRequest.Pv | PricingRequest.Cashflow | PricingRequest.DirtyPrice | PricingRequest.KeyRateDv01 | PricingRequest.DollarDuration | PricingRequest.DollarConvexity | PricingRequest.Delta | PricingRequest.Gamma | PricingRequest.Vega | PricingRequest.Theta | PricingRequest.Rho | PricingRequest.DVegaDvol | //one high order risk PricingRequest.ZeroSpread | PricingRequest.ZeroSpreadDelta | PricingRequest.AiEod | PricingRequest.Basis | PricingRequest.CheapestToDeliver | PricingRequest.Ytm | PricingRequest.UnderlyingPv | PricingRequest.Carry; #endregion requests foreach (var tradeId in tradeIds) { t0Vals[tradeId] = xl_ValueTrade(tradeId, t0Mkt, pricingRequest); var t1Request = PricingRequest.Pv | PricingRequest.DirtyPrice | PricingRequest.ZeroSpread | PricingRequest.AiEod | PricingRequest.Ytm | PricingRequest.Basis | PricingRequest.Cashflow; t1Vals[tradeId] = xl_ValueTrade(tradeId, t1Mkt, t1Request); t0ValsRolledForward[tradeId] = xl_ValueTrade(tradeId, t0MktDateRolledFwd, PricingRequest.Pv | PricingRequest.DirtyPrice | PricingRequest.UnderlyingPv); //reval framework for better pnl attribution if (useRevalPnLFramework) { t0ValsPriceNow[tradeId] = xl_ValueTrade(tradeId, t0MktPriceNow, PricingRequest.Pv); t0ValsVolNow[tradeId] = xl_ValueTrade(tradeId, t0MktVolNow, PricingRequest.Pv); t0ValsPriceVolNow[tradeId] = xl_ValueTrade(tradeId, t0MktPriceVolNow, PricingRequest.Pv); t0RolldownPriceForBond[tradeId] = xl_ValueTrade(tradeId, t0MktRolldownForBond, PricingRequest.Pv | PricingRequest.ZeroSpread); } } //For old interface: //var tCurves = GetXlMarket(tMarketName).MarketInfo.YieldCurveDefinitions.Select(x => x.Name) // .Select(x => t0Mkt.GetData<CurveData>(x).YieldCurve).ToDictionary(x => x.Name, x => x); //var t1Curves = GetXlMarket(t1MarketName).MarketInfo.YieldCurveDefinitions.Select(x => x.Name) // .Select(x => t1Mkt.GetData<CurveData>(x).YieldCurve).ToDictionary(x => x.Name, x => x); var tCurves = t0Mkt.YieldCurves; var t1Curves = t1Mkt.YieldCurves; var curveMoveScaling = 1e4; foreach (var tradeId in tradeIds) { var t1cf = (t1Vals[tradeId].Cashflows != null) ? t1Vals[tradeId].Cashflows.Where(x => x.PaymentDate <= t1Mkt.ReferenceDate && x.PaymentDate > t0Mkt.ReferenceDate).Sum(x => x.PaymentAmount) : 0.0; var tradeInfo = GetTrade(tradeId); if (tradeInfo is InterestRateSwapInfo || tradeInfo is BondInfoBase || tradeInfo is BondFuturesInfo) { //PnL using bond discounted cash flows //curve risk is between T0_{prime} and T1 var _tPv = t0Vals[tradeId].Pv; var _t1Pv = t1Vals[tradeId].Pv; var _tPvRecalib = t0ValsRolledForward[tradeId].Pv; var curvePnL = new Dictionary <string, CurveRisk[]>(); foreach (var curveRiskse in t0Vals[tradeId].KeyRateDv01) { var tCurve = tCurves[curveRiskse.Key]; var t1Curve = t1Curves[curveRiskse.Key]; curvePnL[curveRiskse.Key] = curveRiskse.Value.Select(x => new CurveRisk( x.Tenor, x.Risk * (t1Curve[x.Tenor] - tCurve[x.Tenor]) * curveMoveScaling )).ToArray(); } //include raw t1 curve risks in result foreach (var curveRisks in t0Vals[tradeId].KeyRateDv01) { curvePnL[curveRisks.Key + "KeyRateDv01"] = curveRisks.Value; } var pnLCurve = new CommonPnLResult(_tPv, _t1Pv, _tPvRecalib - _tPv, t1cf, curvePnL); ret[tradeId] = pnLCurve; } if (tradeInfo is InterestRateSwapInfo) { var swap = tradeInfo as InterestRateSwapInfo; //carry & roll down var rollDown = t0ValsRolledForward[tradeId].Pv - t0Vals[tradeId].Pv; var carry = t0Vals[tradeId].Carry; var pnlTime = rollDown + carry; var commonPnl = ret[tradeId]; var pnlPv01 = ret.ContainsKey(tradeId) && ret[tradeId].YieldCurvePnL.Count > 0 ? ret[tradeId].YieldCurvePnL.First().Value.Sum(x => x.Risk) : 0.0; var pnl = new SwapPnLResult(commonPnl.TPv, commonPnl.T1Pv, pnlTime: pnlTime, t1Cf: t1cf, pnlPv01: pnlPv01, pnlCarry: carry, pnlRolldown: rollDown); ret[tradeId + "durationConvexity"] = pnl; } if (tradeInfo is BondInfoBase) { var bond = tradeInfo as BondInfoBase; var tPv = t0Vals[tradeId].DirtyPrice; var t1Pv = t1Vals[tradeId].DirtyPrice; var tPvRecalib = t0ValsRolledForward[tradeId].DirtyPrice; //bond market PnL var pnlPv01 = ret.ContainsKey(tradeId) && ret[tradeId].YieldCurvePnL.Count > 0 ? ret[tradeId].YieldCurvePnL.First().Value.Sum(x => x.Risk) : 0.0; //bond specific pnl var tZSpread = t0Vals[tradeId].ZeroSpread; var t1ZSpread = t1Vals[tradeId].ZeroSpread; var tZSpreadDelta = t0Vals[tradeId].ZeroSpreadDelta; var zSpreadPnl = tZSpreadDelta * (t1ZSpread - tZSpread) * curveMoveScaling; var pnlCarry = t1Vals[tradeId].Ai - t0Vals[tradeId].Ai; //bond roll down effect: cashflow less, but benefit from still curve, note that zspread also changes due to rolling down the curve var pnlRolldown = t0RolldownPriceForBond[tradeId].Pv - t0Vals[tradeId].Pv + tZSpreadDelta * (t0RolldownPriceForBond[tradeId].ZeroSpread - tZSpread) * curveMoveScaling; var pnlTime = pnlCarry + pnlRolldown; //duration pnl is not used in book level pnl explain var pnlDuration = t0Vals[tradeId].ModifiedDuration * (t1Vals[tradeId].Ytm - t0Vals[tradeId].Ytm) * bond.Notional; var pnlConverixy = 0.5 * Math.Pow(t1Vals[tradeId].Ytm - t0Vals[tradeId].Ytm, 2.0) * t0Vals[tradeId].DollarConvexity / 100.0; var explainedPriceImpact = pnlPv01 + zSpreadPnl + pnlConverixy + pnlTime; var pnl = new BondPnLResult(tPv, t1Pv, pnlTime: pnlTime, t1Cf: t1cf, pnlPv01: pnlPv01, pnlZspread: zSpreadPnl, pnlCarry: pnlCarry, pnlRolldown: pnlRolldown, pnlDuration: pnlDuration, pnlConvexity: pnlConverixy); ret[tradeId + "durationConvexity"] = pnl; } if (tradeInfo is BondFuturesInfo) { var tPv = t0Vals[tradeId].DirtyPrice; var t1Pv = t1Vals[tradeId].DirtyPrice; //curve pnl var pnlPv01 = ret.ContainsKey(tradeId) && ret[tradeId].YieldCurvePnL.Count > 0 ? ret[tradeId].YieldCurvePnL.First().Value.Sum(x => x.Risk) : 0.0; //zspread pnl from CTD, converted to future equivalen t var zspreadT0 = t0Vals[tradeId].ZeroSpread; var zspreadT1 = t1Vals[tradeId].ZeroSpread; var zspreadPnl = (zspreadT1 - zspreadT0) * curveMoveScaling * t0Vals[tradeId].ZeroSpreadDelta; //basis pnl from CTD/cf - Future var basisT0 = t0Vals[tradeId].Basis; var basisT1 = t1Vals[tradeId].Basis; var bondFut = XlManager.GetTrade(tradeId) as BondFuturesInfo; var futPosScaling = 1.0 / 100.0 * bondFut.Notional; var basisPnL = (basisT1 - basisT0) * futPosScaling; //convexity pnl from CTD var ctdId = t0Vals[tradeId].CheapestToDeliver; var pnlConvexity = 0.0; var bondMktData = t0Mkt.BondPrices[ctdId]; if (bondMktData != null) { var ctdCleanPriceT0 = bondMktData.CleanPrice; var ctdInfo = bondFut.DeliverableBondInfos.Where(x => x.BondId == ctdId).First(); var ctdResultT0 = XlUdf.BondEngineCalc(ctdId, t0Mkt.ReferenceDate.ToString(), PriceQuoteType.Clean, ctdCleanPriceT0, PricingRequest.DirtyPrice, fixedBond: ctdInfo) as PricingResult; pnlConvexity = 0.5 * Math.Pow(t1Vals[tradeId].Ytm - t0Vals[tradeId].Ytm, 2.0) * t0Vals[tradeId].DollarConvexity / 100.0; } //time pnl from CTD var timePnL = t0ValsRolledForward[tradeId].UnderlyingPv - t0Vals[tradeId].UnderlyingPv; var pnl = new BondFuturesPnLResult(tPv, t1Pv, pnlPv01: pnlPv01, pnlZspread: zspreadPnl, pnlBasis: basisPnL, pnlTime: timePnL, pnlConvexity: pnlConvexity, curveRisks: null); ret[tradeId] = pnl; } if (tradeInfo is VanillaOptionInfo || tradeInfo is BinaryOptionInfo || GetTrade(tradeId) is BarrierOptionInfo || tradeInfo is AsianOptionInfo) { OptionValuationParameters valuationParameters = null; Date exerciseDate = null; double strike = 0.0; var trade = tradeInfo as OptionInfoBase; valuationParameters = trade.ValuationParamter; TradeUtil.GenerateOptionDates(trade, out Date[] exerciseDates, out Date[] obsDates, out DayGap settlementGap);
public override BinaryOption GenerateInstrument() { var startDate = TradeInfo.StartDate.ToDate(); var maturityDate = TradeInfo.UnderlyingMaturityDate.ToDate(); TradeUtil.GenerateOptionDates(TradeInfo, out Date[] exerciseDates, out Date[] obsDates, out DayGap settlementGap);