using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos; using Qdp.Foundation.Implementations; using Qdp.Pricing.Base.Utilities; using System.Runtime.CompilerServices; using YLErp.BLL; using YLErp.BLL.Calculation; using YLErp.QdpModule; namespace YLErp.Modules.CalculationModule { /// /// 交易计算帮助类 /// public static class TradeCalcHelper { /// /// [交易员角度]根据交易方向判断了结金额是否需要加符号 /// 开仓费不适用 -- 开仓费是客户方向 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetBuySellSign(string buySell) { switch (buySell) { case "卖出": case "融券卖出": case "多头平仓": case "空头开仓": return -1; default: return 1; } } /// /// [交易员角度]根据交易方向判断了结金额是否需要加符号 /// 开仓费不适用 -- 开仓费是客户方向 /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetSign(string buySell) { return GetBuySellSign(buySell); } /// /// 远期计算(从交易员角度计算) /// public static void CalcForwardValue(OtcTrade trade, double spotPrice, out double pv, out double pnl) { //1.结算报告,期权价格 / 单价: 现价 - 交割价格 //2.持仓市值: 期权价格* 持仓数量 //3.持仓盈亏: 持仓市值 - 持仓数量比率 * 开仓总费用 pv = pnl = 0; if (trade.Notional <= 1e-7) { return; } var priceChange = 0d; if (trade.OptionType == "看涨") { priceChange = spotPrice - (trade?.Strike ?? 0); } else if (trade.OptionType == "看跌") { priceChange = (trade?.Strike ?? 0) - spotPrice; } //以交易员角度 if (trade.BuySell == "卖出") { priceChange = -priceChange; } pv = priceChange * trade.Notional; pnl = pv + (trade.OriginalNotional > 0 && trade.TradePrice >= 0 ? trade.TradePrice.Value * trade.Notional / trade.OriginalNotional.Value : 0); } /// /// 对冲交易 根据结构类型 买卖方向 看涨看跌 获取持仓long short /// public static string GetHedgeLongShort(string TradeType, string BuySell) { switch (TradeType) { case "信用债": case "商品期货": case "场内期权": return BuySell.Contains("多头") ? "long" : "short"; case "股票": default: return "long"; } } /// /// 根据期权交易获取QDP Trade /// public static TradeBase GetQdpTrade(trade tr, DateTime? valueDate = null, string fixings = null) { if (!valueDate.HasValue) { valueDate = valuedateBLL.ValueDate; } TradeBase tempTrade = null; var sysRiskRate = valuedateBLL.RiskFreeRate / 100; OptionTradeParamRequest getRequest() { return new OptionTradeParamRequest(sysRiskRate) { tradeId = tr.TradeNumber, fixings = null, hasNightMarket = false, maturityShift = 0, ParamOverride = null, preciseTimeMode = false, timeToMaturityDays = double.NaN, volSurfaceNames = null }; } switch (tr.TradeType) { case "自定义交易": { tempTrade = new ManualTrade(tr.id.ToString(), new Date(tr.TradeDate.Value.Date), new Date(tr.StartDate ?? valueDate.Value), new Date(tr.MaturityDate ?? valueDate.Value), QdpConverter.ConvertTradeType(tr.BuySell), tr.Notional, 0); break; } case "收益互换": { tempTrade = new SwapTrade(tr.id.ToString(), new Date(tr.TradeDate.Value.Date), new Date(tr.StartDate ?? valueDate.Value), new Date(tr.MaturityDate ?? valueDate.Value), QdpConverter.ConvertTradeType(tr.BuySell), tr.Notional, tr.SpotPrice ?? 0); break; } case "亚式期权": { var request = getRequest(); request.fixings = fixings.TrimToNull() ?? AsianOptionFixingService.GetFixingString(valueDate.Value, tr); tempTrade = QdpTradeBuilder.GetAsianOptionTrade(tr, tr.trade_asian_option, request); break; } case "彩虹期权": tempTrade = QdpTradeBuilder.GetRainbowOptionTrade(tr, tr.trade_rainbow_option, getRequest()); break; case "合成价差期权": tempTrade = QdpTradeBuilder.GetSSpreadOptionTrade(tr, getRequest()); break; case "香草期权": tempTrade = QdpTradeBuilder.GetVanillaOptionTrade(tr, getRequest(), false); break; case "Risky期权": tempTrade = QdpTradeBuilder.GetVanillaOptionTrade(tr, getRequest(), false); break; case "障碍期权": tempTrade = QdpTradeBuilder.GetBarrierOptionTrade(tr, tr.trade_barrier_option, getRequest()); break; case "二元期权": tempTrade = QdpTradeBuilder.GetBinaryOptionTrade(tr, tr.trade_binary_option, getRequest()); break; case "双鲨期权": tempTrade = QdpTradeBuilder.GetDoubleSharkFinOptionTrade(tr, tr.trade_double_sharkfin_option, getRequest()); break; case "凤凰期权": tempTrade = QdpTradeBuilder.GetAutocallOptionTrade(tr, tr.trade_autocall, getRequest()); break; case "雪球期权": tempTrade = QdpTradeBuilder.GetSnowballOptionTrade(tr, tr.trade_snowball, getRequest()); break; case "区间累积期权": tempTrade = QdpTradeBuilder.GetRangeAccrualTrade(tr, tr.trade_rangeaccrual, getRequest()); break; case "气囊结构": tempTrade = QdpTradeBuilder.GetAirbagOptionTrade(tr, tr.trade_airbag, getRequest()); break; case "累计期权": { var req = getRequest(); req.happenedObservations = ObservationDataService.QueryDatas(tr.id, valueDate.Value); tempTrade = QdpTradeBuilder.GetAccumulatorOptionTrade(tr, tr.trade_accumulator_option, req); } break; case "收益增强结构": tempTrade = QdpTradeBuilder.GetUnderlyingEnhanceTrade(tr, tr.trade_underlying_enhance, getRequest()); break; case "现金流交易": tempTrade = QdpTradeBuilder.GetCashFlowTrade(tr, tr.trade_cashflow, getRequest()); break; } return tempTrade; } /// /// 根据valuedate配置判断是否使用收盘价进行结算 /// public static bool UseClosePrice() { return ConsGlobal.SettlePriceMode.UseClosePrice(valuedateBLL.SystemDate.EodSettlePriceMode); } /// /// 根据valuedate配置获取收盘结算价类型 /// public static SettlementTypeEnum GetSettlementType() { return ConsGlobal.SettlePriceMode.GetSettlementType(valuedateBLL.SystemDate.EodSettlePriceMode); } /// /// /// public static string GetTradeStatus(trade trade, trade_cash tradeCash) { if (tradeCash.Action == "系统操作-平仓费" && (tradeCash.UnwindType == "部分平仓" || tradeCash.UnwindType == "全部平仓")) { return "已平仓"; } if (tradeCash.Action == "系统操作-行权费" && tradeCash.ExerciseWay == "到期行权" && tradeCash.UnwindType == "到期") { return "已到期"; } if ((tradeCash.Action == "系统操作-平仓费" && tradeCash.UnwindType == "部分行权") || tradeCash.Action == "系统操作-行权费") { return "已行权"; } return trade.TradeStatus; } /// /// 以交易员角度计算盈亏 /// /// 交易方向 /// 交易总额 /// 平仓比例 /// 平仓收支 public static double CalcWinLoss(string tradeType, string buySell, double tradePrice, double tcUnwindPercent, double tcAmount) { int costSign = 1; //收入计为1,支出计为-1 if (tradeType != "远期") { switch (buySell) { case "卖出": case "融券卖出": case "多头平仓": case "空头开仓": break; default: costSign = -1; break; } } return tcAmount + tradePrice * tcUnwindPercent * costSign; } /// /// 计算单笔交易或多笔交易实现盈亏 /// /// /// /// /// /// public static double CalcChildTradeSumWinLoss(trade td, trade_cash tc, bool IsUsePremiumRate = false, int CountRatio = 0) { using (var db = DbContextFactory.GetYLDbContext()) { double TcTradePrice = 0; if (td.IsGroup == 1) { var childTradeCashs = db.trade_cash.Where(x => x.ParentTradeCashId == tc.id).ToList(); var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList(); var childTrades = db.trade.Where(x => childTradeIds.Contains(x.id)).ToList(); childTradeCashs.ForEach(x => { var trade = childTrades.FirstOrDefault(y => y.id == x.TradeId); TcTradePrice += (x.UnwindPercentRate * trade?.TradePrice * (trade?.BuySell == "买入" ? -1 : 1)) ?? 0; }); return tc.Amount + TcTradePrice; } else { if (IsUsePremiumRate) { return (tc.Amount + (td.BuySell == "卖出" ? 1 : -1) * ((tc?.UnwindTradeAmount ?? 0) * CountRatio / td.OriginalNotional) * td.TradePrice) ?? 0; } return (tc.Amount + (td.BuySell == "卖出" ? 1 : -1) * (tc?.UnwindPercentRate ?? 0) * td?.TradePrice) ?? 0; } } } /// /// 计算TTM /// public static double CalculateTTMDays(DateTime from, DateTime to, int varietyid, bool precisionOfMinute, DateTime? serverDateTime = null) { var dayCount = valuedateBLL.TradeDayCount.ToDayCountImpl(); var variety = DataCacheProvider.GetVarietyDataSource().GetData(varietyid); if (serverDateTime == null) { serverDateTime = DateTime.Now; } return QdpHelper.CalculateTTMDays(from, to, valuedateBLL.ValueDate, serverDateTime.Value, dayCount, variety != null && variety.HasNightMarket, precisionOfMinute); } /// /// 计算TTM /// public static double CalculateTTMDaysForXiangYu(DateTime from, DateTime to, int varietyid, bool precisionOfMinute, DateTime? serverDateTime = null) { var dayCount = valuedateBLL.TradeDayCount.ToDayCountImpl(); var variety = DataCacheProvider.GetVarietyDataSource().GetData(varietyid); if (serverDateTime == null) { serverDateTime = DateTime.Now; } return QdpHelper.CalculateTTMDaysForXiangYu(from, to, valuedateBLL.ValueDate, serverDateTime.Value, dayCount, variety != null && variety.HasNightMarket, precisionOfMinute); } /// /// 传入OTC买卖方向判断是否买入方向 /// public static bool IsBuy(string buySell) { return buySell == "Buy" || buySell == "买入" || string.IsNullOrWhiteSpace(buySell); } /// /// 用于计算成交数量(虚拟),如果countRatio传入的是1,就可以用来计算成交份额 /// public static double GetTradeAmountV(OtcTradeBase trade, int? countRatio = null) { return InnerGetTradeAmountV(trade, null, countRatio); } /// /// 用于计算成交数量(虚拟),如果countRatio传入的是1,就可以用来计算成交份额 /// public static double GetTradeAmountV(OtcTradeBase trade, double notional, int? countRatio = null) { return InnerGetTradeAmountV(trade, notional, countRatio); } /// /// 用于计算成交数量(实际),如果countRatio传入的是1,就可以用来计算成交份额 /// public static double GetTradeAmount(OtcTradeBase trade, double notional, int? countRatio = null) { return InnerGetTradeAmount(trade, notional, countRatio); } /// /// /// private static double InnerGetTradeAmountV(OtcTradeBase trade, double? notional, int? countRatio) { if (trade is null) { throw new ArgumentNullException(nameof(trade)); } var CountRatio = countRatio ?? trade.CountRatio ?? 0; if (CountRatio < 1) { CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode)?.CountRatio ?? 1; } if (trade.TradeType == "累计期权") { return (notional ?? trade.OriginalNotional ?? 0) / CountRatio; } if (!notional.HasValue) { var SpotPrice = trade.SpotPrice ?? 0; if (Math.Abs(SpotPrice) > 0) { return (trade.OriginalStockEqvNotional ?? 0) / Math.Abs(SpotPrice) / CountRatio; } } var annRate = (trade.ParticipationRate ?? 1) * (trade.AnnualizeFactor ?? 1); if (annRate < 1e-8) { annRate = 1; } return (notional ?? trade.OriginalNotional ?? 0) / annRate / CountRatio; } /// /// /// private static double InnerGetTradeAmount(OtcTradeBase trade, double? notional, int? countRatio) { if (trade is null) { throw new ArgumentNullException(nameof(trade)); } var CountRatio = countRatio ?? trade.CountRatio ?? 0; if (CountRatio < 1) { CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode)?.CountRatio ?? 1; } if (trade.TradeType == "累计期权") { return (notional ?? trade.OriginalNotional ?? 0) / CountRatio; } if (!notional.HasValue) { var SpotPrice = trade.SpotPrice ?? 0; if (Math.Abs(SpotPrice) > 0) { return (trade.OriginalStockEqvNotional ?? 0) / Math.Abs(SpotPrice) / CountRatio; } } var annRate = (trade.ParticipationRate ?? 1) * (trade.AnnualizeFactor ?? 1); if (annRate < 1e-8) { annRate = 1; } return (notional ?? trade.OriginalNotional ?? 0) * annRate / CountRatio; } } }