using YLErp.DBModels.Consts; using YLErp.Modules.CalculationModule; using YLErp.QdpModule; namespace YLErp.Modules.EodModule.SettlementModule.V2 { /// /// 临时存放 /// class EodPositionSettleServiceTemp : EodSettleServiceBaseV2 where TPnl : EodPnl, new() where TRisk : EodTradeRisk, new() where TPosition : EodTradePosition, new() { public EodPositionSettleServiceTemp(EodSettlementContextV2 context) : base(context) { } #region----盈亏分解V1---- //判断是否可以进行盈亏分解计算 private bool CanCalcPnlExplain(OtcTradeBase td) { switch (td.TradeType) { case "远期": case "收益互换": case "自定义交易": return false; default: return true; } } private void CalcPnlExplainV1(trade td, TPnl pnl1, TRisk risk1, double spotPrice1, double riskFreeRate1) { if (!CanCalcPnlExplain(td)) { return; } var preRisk = DbContext.Set().Where(n => n.ValueDate < _context.SettleDate && n.TradeId == td.id) .OrderByDescending(n => n.ValueDate).Select(n => new { n.ValueDate, n.Vol, n.Pv }).FirstOrDefault(); if (preRisk == null) { return; } DateTime date0; double spotPrice0, vol0, riskFreeRate0, PV0, vol1 = risk1.Vol; var hisData = DbContext.TradeHisData.Where(n => n.TradeId == td.id && n.ValueDate < _context.SettleDate && n.ValueType == ConsTradeField.NoRiskRate) .OrderByDescending(n => n.ValueDate).Select(n => new { n.Value }).FirstOrDefault(); spotPrice0 = _context.GetPreEodPriceProvider().GetPrice(td.UnderlyingCode, td.SettlementType); PV0 = preRisk.Pv; vol0 = preRisk.Vol; date0 = preRisk.ValueDate; riskFreeRate0 = hisData?.Value ?? td.NoRiskRate ?? riskFreeRate1; var sdiff = spotPrice1 - spotPrice0; pnl1.PnLDelta = risk1.Delta * sdiff; pnl1.PnLGamma = risk1.Gamma * sdiff * sdiff / 2; pnl1.PnLVega = risk1.Vega * (risk1.Vol - vol0) * 100; pnl1.PnLTheta = risk1.Theta * (_context.SettleDate - _context.PreSettleDate).TotalDays; pnl1.PnLRho = risk1.Rho * (riskFreeRate1 - riskFreeRate0); //交易在上一交易日使用当前交易日的标的价格计算出的Pv var PV0s1 = CalcPnlExplainV1(td, date0, spotPrice1, vol0, riskFreeRate0); //交易在上一交易日使用当前交易日的波动率计算出的Pv var PV0v1 = CalcPnlExplainV1(td, date0, spotPrice0, vol1, riskFreeRate0); //交易在上一交易日使用当前交易日的标的价格和波动率计算出的Pv var PV0s1v1 = CalcPnlExplainV1(td, date0, spotPrice1, vol1, riskFreeRate0); pnl1.PnLPrice = PV0s1 - PV0; pnl1.PnLVol = PV0v1 - PV0; pnl1.PnLPriceVolCross = PV0s1v1 - PV0 - pnl1.PnLPrice - pnl1.PnLVol; } private static double CalcPnlExplainV1(trade td, DateTime valueDate, double spotPrice, double vol, double riskFreeRate) { var req = new OptionValueCalcRequest(riskFreeRate) { correlations = null,//不计算彩虹等多标的期权暂时不需要 engineName = null, preciseTimeMode = false, //日终一定是false isEodCalc = true, pricingRequest = QdpPricingRequest.PV_ONLY, spotPrices = new[] { spotPrice }, vols = new[] { vol } }; var result = OptionCalculatorV2.GetOptionValueResult(valueDate, td, req, out _); return NumberHelper.Normalize(result.Pv); } #endregion } }