using YLErp.Modules.CalculationModule; using YLErp.Modules.CalculationModule.Abstract; using YLErp.Modules.DataProviderModule; namespace YLErp.Modules.TradeRiskCalcModule { /// /// 实时场内持仓计算服务(用于API) /// public class ExchangePositionCalcService { readonly DateTime _valueDate; readonly IExchangeTradeCommissionCalc _commissionCalc; public ExchangePositionCalcService(DateTime valueDate, IExchangeTradeCommissionCalc commissionCalc) { _valueDate = valueDate.Date; _commissionCalc = commissionCalc ?? throw new ArgumentNullException(nameof(commissionCalc)); } /// /// 计算对冲交易Pnl信息 /// /// 当日对冲交易数据 /// 上日持仓数据 public IEnumerable Calculate(IEnumerable newHedgeTrades , IEnumerable eodPositions, ExchangeOptionPriceProvider exchangeOptionPriceProvider) { if (newHedgeTrades == null && eodPositions == null) { return Enumerable.Empty(); } var resultDic = new Dictionary(); var exchangeOptionSource = DataCacheProvider.GetExchangeListOptionDataSource(); //----------------------------------------- // 处理昨日持仓 //----------------------------------------- if (eodPositions != null) { foreach (var eod in eodPositions) { if (eod.TradeType == "场内期权") { var exchangeOption = exchangeOptionSource.GetData(eod.ExchangeOptionCode); //剔除已到期场内期权持仓 if (exchangeOption == null || exchangeOption.MaturityDate < _valueDate) { continue; } } var uniqueCode = GetUniqueCode(eod.BookId, eod.TradeType, eod.UnderlyingCode, eod.ExchangeOptionCode); if (!resultDic.TryGetValue(uniqueCode, out var result)) { resultDic[uniqueCode] = result = new ExchangePositionItem() { //合成唯一标记 BookId = eod.BookId, TradeType = eod.TradeType, UnderlyingCode = eod.UnderlyingCode, ExchangeOptionCode = eod.ExchangeOptionCode, BookName = null, ExchangeId = null, LastPriceTime = null }; } //合并汇总 result.Commission += eod.Commission; result.PositionProfit += eod.TotalPnL; if (Math.Abs(eod.Amount) > 0) { if ("short" == eod.PositionType) { result.Volume_Short += eod.Amount; //因为TotalPnL已经包括了Cost所以用PV result.PositionCost_Short += eod.Pv; } else { result.Volume_Long += eod.Amount; result.PositionCost_Long += eod.Pv; } } } } //----------------------------------------- // 处理当日交易 //----------------------------------------- if (newHedgeTrades != null && newHedgeTrades.Any()) { //对冲交易手续费计算 var tradeCommissionDict = _commissionCalc.GetTradeCommission(newHedgeTrades); foreach (var newTrade in newHedgeTrades) { //手续费 var commission = tradeCommissionDict.GetTradeCommission(newTrade.id); //对冲唯一编码(簿记账户ID_结构类型_持仓类型_合约代码) var uniqueCode = GetUniqueCode(newTrade.AssetBookId, newTrade.TradeType, newTrade.UnderlyingCode, newTrade.OptionCode); //当日交易数量/成本(根据交易方向取正负号) var volume = newTrade.Notional * TradeCalcHelper.GetSign(newTrade.TradeSide); var cost = newTrade.TradeSinglePrice * volume + commission; //获取是否存在对应uniqueCode的对冲信息 if (!resultDic.TryGetValue(uniqueCode, out var result)) { resultDic[uniqueCode] = result = new ExchangePositionItem() { BookId = newTrade.AssetBookId, TradeType = newTrade.TradeType, UnderlyingCode = newTrade.UnderlyingCode, ExchangeOptionCode = newTrade.OptionCode, BookName = null, ExchangeId = null, LastPriceTime = null }; } //合并汇总 result.Commission += commission; if (newTrade.TradeSide != null && newTrade.TradeSide.Contains("空头")) { result.Volume_Short += volume; result.PositionCost_Short += cost; } else { result.Volume_Long += volume; result.PositionCost_Long += cost; } } } //----------------------------------------- // 计算持仓盈亏 //----------------------------------------- var underlyingSource = DataCacheProvider.GetUnderlyingDataSource(); var assetBookSource = DataCacheProvider.GetAssetUnitDataSource(); if (exchangeOptionPriceProvider == null) { exchangeOptionPriceProvider = new ExchangeOptionPriceProvider(); } foreach (var result in resultDic.Values) { var um = underlyingSource.GetData(result.UnderlyingCode); result.ExchangeId = um.MarketCode; var hasPrice = false; if (result.TradeType == "场内期权") { if (exchangeOptionPriceProvider.TryGetPriceModel(result.ExchangeOptionCode, out var model)) { hasPrice = true; result.LastPrice = model.Price; result.LastPriceTime = model.PriceTime?.ToString("yyyy-MM-dd'T'HH:mm:ss.fff"); } } else if (um != null) { hasPrice = true; result.LastPrice = um.Price ?? 0; result.LastPriceTime = um.LastUpdateTime?.ToString("yyyy-MM-dd'T'HH:mm:ss.fff"); } if (hasPrice) { var longProfit = result.LastPrice * result.Volume_Long - result.PositionCost_Long; var shortProfit = result.LastPrice * result.Volume_Short - result.PositionCost_Short; result.PositionProfit += longProfit + shortProfit; } result.BookName = assetBookSource.GetData(result.BookId)?.Name; } return resultDic.Values; } /// /// 根据对冲账号 簿记账户I 结构类型 买卖方向 标的代码 场内期权代码 编制对冲唯一编码 /// private static string GetUniqueCode(int BookId, string TradeType, string UnderlyingCode, string ExchangeOptionCode = null) { return $"{BookId}_{TradeType}_{("场内期权".Equals(TradeType) ? ExchangeOptionCode : UnderlyingCode)}"; } } /// /// 场内持仓计算单项结果 /// public class ExchangePositionItem { /// /// [unique]簿记ID /// public int BookId { get; set; } /// /// 簿记账户 /// public string BookName { get; set; } /// /// [unique]交易类型 /// public string TradeType { get; set; } /// /// [unique]标的代码 /// public string UnderlyingCode { get; set; } /// /// [unique]场内期权代码 /// public string ExchangeOptionCode { get; set; } /// /// 持仓数量 /// public double Volume => Volume_Long + Volume_Short; /// /// 手续费 /// public double Commission { get; set; } /// /// 持仓成本 /// public double PositionCost => PositionCost_Long + PositionCost_Short; /// /// 最新价 /// public double LastPrice { get; set; } /// /// 最新价更新时间(格式:yyyy-MM-ddTHH:mm:ss.fff) /// public string LastPriceTime { get; set; } /// /// 持仓盈亏 /// public double PositionProfit { get; set; } /// /// 交易所ID /// public string ExchangeId { get; set; } /// /// 多头持仓成本(使用了正号处理) /// public double Volume_Long { get; set; } /// /// 空头持仓成本(使用了负号处理) /// public double Volume_Short { get; set; } /// /// 多头持仓成本(使用了正号处理) /// public double PositionCost_Long { get; set; } /// /// 空头持仓成本(使用了负号处理) /// public double PositionCost_Short { get; set; } public override string ToString() { return $"{BookName}--{UnderlyingCode}--{Volume}--{LastPrice}--{PositionProfit}--{PositionCost}"; } } /// /// 场内持仓计算结果 /// public class ExchangePositionCalcResult { /// /// 当前结算日 /// public DateTime ValueDate { get; set; } /// /// 上个结算日 /// public DateTime LastDate { get; set; } /// /// 结果数据集合 /// public IEnumerable Items { get; set; } /// /// 开始运行时间 /// public DateTime StartTime { get; } /// /// 结束运行时间 /// public DateTime EndTime { get; } = DateTime.Now; public ExchangePositionCalcResult(DateTime startTime) { StartTime = startTime; } } }