using CsvHelper; using DocumentFormat.OpenXml.Bibliography; using DocumentFormat.OpenXml.Drawing; using DocumentFormat.OpenXml.Drawing.Charts; using DocumentFormat.OpenXml.Spreadsheet; using iTextSharp.text.pdf.security; using NPOI.SS.Formula.Functions; using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Math.EC.Multiplier; using Qdp.Pricing.Base.Implementations; using System.IO; using System.Security.Cryptography.Xml; using YLErp.Abstract; using YLErp.Abstract.DataProviders; using YLErp.BLL.Calculation; using YLErp.BLL.MarginCalculation; using YLErp.Cache; using YLErp.Commons; using YLErp.DataBase; using YLErp.DBModels; using YLErp.DBModels.Enums; using YLErp.DBModels.Helpers; using YLErp.Helpers; using YLErp.Model; using YLErp.Model.Enum; using YLErp.Model.HengTaiModel; using YLErp.Models; using YLErp.Modules; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.EodModule; using YLErp.Modules.EodModule.QueryModule; using YLErp.Modules.SwapModule; using YLErp.Modules.TradeDalModule; using YLErp.QdpModule; namespace YLErp.BLL.Eod { public class RealtimePnlCalc { public static bool IsListOld = true; protected static object _RefrshLock = new object(); private static IYLCache _yLCache; private static IKafkaProduce kafkaProduceHelper; ///系统参数 protected static valuedate _SystemDate = null; ///当前计算日期 protected static DateTime _ValueDate = DateTime.MinValue; ///最后交易日 protected static DateTime _LastSettleDate = DateTime.MinValue; ///最后结算日日终持仓信息 protected static List _LastTradePositionList = new List(); // protected static List _TradeAllList; protected static List _TradeSwapList; protected static DateTime _TradeLastUpdateTime; static IYcLogger _logger = LogFactory.GetLogger("RealtimePnlCalc"); /// 设置为false时 节假日当天 protected static bool IsFirstHoliday = true; public static void InitCache(IYLCache yLCache) { _yLCache = yLCache; } public static void InitKafka(IKafkaProduce kafkaProduce) { kafkaProduceHelper = kafkaProduce; } /// /// 刷新当日静态数据 /// public static void RestInitData() { //刷新系统日期 valuedateBLL.ResetValueDate(); var isReload = false; if (_ValueDate == DateTime.MinValue || _ValueDate != valuedateBLL.ValueDate) { isReload = true; _SystemDate = valuedateBLL.SystemDate; _ValueDate = _SystemDate.ValueDate; } InitLastTradePosition(isReload); //增量初始化交易信息 InitTradeList(); } /// /// 初始化最后结算日结算信息 /// private static void InitLastTradePosition(bool isReload) { if (isReload) { //获取昨日持仓 _LastSettleDate = EodOperationBase.GetLastSettlementDate(_ValueDate, true); //获取昨日持仓 _LastTradePositionList = new EodSettlementService(OptUserInfo.SystemUser).GetEodTradePosition(_LastSettleDate).ToList(); } } /// /// 初始化交易信息 /// private static void InitTradeList() { using (var db = new YLContext()) { //获取停牌信息 var suspensionUnderlyingIdList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable() .Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList(); //昨日持仓交易 var tradeIds = _LastTradePositionList.Where(t => 0 != t.TradeId).Select(t => t.TradeId).ToList(); //初始化待交易交易列表 _TradeAllList = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= _ValueDate && ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)).ToList(); //有效的交易 //if (PS.Config.IsGuoJun) //{ // _TradeAllList = _TradeAllList.Where(x=>x.TradeType!="收益互换").ToList(); //} if (_TradeAllList != null && _TradeAllList.Any()) { var allTradeIds = _TradeAllList.Select(d => d.id).Distinct().ToList(); var metaList = db.TradeMeta.AsNoTracking().Where(d => allTradeIds.Contains(d.TradeId)).ToList(); _TradeAllList.ForEach(p => { p.MetaDic = metaList.Where(x => x.TradeId == p.id).ToDictionary(g => g.MetaKey, g => g.MetaValue); }); } _TradeSwapList = _TradeAllList.Where(x => x.TradeType == "收益互换").ToList(); _TradeAllList = _TradeAllList.Where(x => x.TradeType != "收益互换").ToList(); } } /// /// 计算实时持仓并返回结果 /// public static List RealtimePosition(OptUserInfo optUser) { if (optUser is null) { throw new ArgumentNullException(nameof(optUser)); } lock (_RefrshLock) { using (var db = new YLContext()) { RestInitData(); #region 获取昨日持仓 标的当前价格 当前持仓以及当日行权交易 并计算Risk信息 //标的 var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource(); //获取待计算交列表 var tradeList = _TradeAllList; var tradeIdList = tradeList.Select(t => t.id).ToList(); //设置option info tradeBLL.SetFieldsByTradeType(tradeList); //OTC 交易 var otcTradeList = tradeList.Where(t => !ConsTrade.TradeTypesForHedge.Contains(t.TradeType)).ToList(); new TradeDalService(optUser).SetSubTradeList(otcTradeList); //OTC持仓交易 //过滤结构化交易,不参与计算预付金逻辑 var positionTradeList = otcTradeList.Where(t => ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus) && t.TradeType != "结构化交易").ToList(); //还未了结的交易 var liveTradeList = otcTradeList.Where(t => ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus)).ToList(); //预付金计算 var req = new RunMarginCalculationReq(optUser) { tradeList = positionTradeList, settleDate = _ValueDate, PriceProvider = underlyingPrice, hasOptionInfo = true }; var tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false)); //试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理) List tradeSpansOtherSide = new List(); if (MarginDefault.IsMarginCalcNeedSpecial(_ValueDate)) { //试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理) tradeSpansOtherSide = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: true)); } //根据交易预付金合计客户预付金计入client_span var calcClientMarginReq = new CalcClientMarginReq(optUser) { settleDate = _ValueDate, tradeSpans = tradeSpans, tradeSpansOtherSide = tradeSpansOtherSide, SpanType = ClientSpan.SpanType_RealTime }; tradeSpans = MarginDefault.CalcClientMargin(calcClientMarginReq); if (PS.Config.Company == Configuration.CompanyEnum.渤海) { //预付金计算 tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false)); } //实时计算rsik var volTypes = new List { "持仓" }; if (PS.Config.Is国投) { volTypes.Add("开仓"); } var riskList = RealTimeRiskCalc(_ValueDate, liveTradeList, underlyingPrice, volTypes); #endregion #region 平仓费行权费 交易预付金计算 昨日持仓对冲交易过滤 var unWindTradeCashAction = new List { ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_期权费 }; //获取平仓到期交易的trade_cash; var tradeCashList = db.trade_cash.Where(t => tradeIdList.Contains(t.TradeId) && unWindTradeCashAction.Contains(t.Action) && t.ValidState != "InValid" && !t.IsDeleted).ToList(); //实时结果对象类 var realtimePositionList = new List(); //旧持仓对冲交易 var lastHedgingPositionList = _LastTradePositionList.Where(t => ConsTrade.TradeTypesForHedge.Contains(t.TradeType)).ToList(); #endregion #region 处理昨日持仓今日为未交易股票 商品期货 //2021-02-02 实时持仓服务不再计算对冲交易,统一从 trade_Position 获取; ////对冲 交易 //var hedgeTradeList = db.ExchangeTrade.Where(t => t.IsValid && t.TradeDate <= _ValueDate && t.TradeDate > _LastSettleDate).ToList(); //var hedgePnlCalc = GetRealTimeHedgePnlCalc(_ValueDate, volType: "交易", optUser: optUser); //var hedgePnl = hedgePnlCalc.Calculate(hedgeTradeList, lastHedgingPositionList); //if (hedgePnl != null && hedgePnl.Any()) //{ // foreach (var t in hedgePnl) // { // var realtimePosition = new intraday_trade_position // { // ValueDate = _ValueDate, // BookId = t.BookId, // TradeType = t.TradeType, // //ClientId = t.ClientId, // PositionType = t.PositionType, // UnderlyingCode = t.UnderlyingCode, // BuySell = t.BuySell, // Cost = Convert.ToDouble(t.Cost), // Notional = Convert.ToDouble(t.Notional), // Amount = Convert.ToDouble(t.Notional), // LastPv = t.LastPv, // Pv = t.Pv, // DailyPnL = t.DailyPnL, // TotalPnL = Convert.ToDouble(t.TotalPnl), // PositionPnL = Convert.ToDouble(t.TotalPnl), // ActualPv = Convert.ToDouble(t.Pv), // ActualLastPv = Convert.ToDouble(t.LastPv), // ActualDailyPnL = Convert.ToDouble(t.DailyPnL), // ActualTotalPnL = Convert.ToDouble(t.TotalPnl), // RealizedPnL = Convert.ToDouble(t.RealizedPnL), // TradeStatus = "确认成交", // OptDate = DateTime.Now, // OptId = optUser.UserId, // OptName = optUser.UserName, // ParentTradeId = 0 // }; // realtimePositionList.Add(realtimePosition); // } //} #endregion #region 当日持仓期权交易 已行权已到期期权交易 以及当日对冲交易计算持仓 var tradeIds = otcTradeList.Select(x => x.id).ToArray(); var positionRealizedTradeCashs = db.trade_cash.Where(x => (x.Action == "系统操作-票息" || x.Action == "系统操作-互换") && x.ValidState != "InValid" && x.ValueDate <= _ValueDate && tradeIds.Contains(x.id) && !x.IsLastAction).ToList(); //循环交易 OTC交易 otcTradeList.ForEach(t => { var Pv = 0.0; //当日pv var RoundedPv = 0.0; var LastPv = 0.0; //昨日pv var Quantity = 0.0; //数量 var RealizedPnL = 0.0;//已归因盈亏 var DailyPnl = 0.0; //当日盈亏 var UnRealizedPnL = 0.0;//未归因盈亏 var TotalPnL = 0.0; //总盈亏 var PositionPnL = 0.0; //持仓盈亏 var RoundedPositionPnL = 0.0; var NotionalPrincipal = 0.0; var ActualPv = 0.0; //当日实际pv var ActualLastPv = 0.0; //昨日实际pv var ActualDailyPnl = 0.0; //当日实际浮动盈亏 var ActualTotalPnL = 0.0; //实际总盈亏 //部分平仓计算 var tempTradeCashList = tradeCashList.Where(a => a.TradeId == t.id); //已实现 var RealizeProfitAndloss = tempTradeCashList.Any() ? tempTradeCashList.Sum(a => a.Amount) : 0.0; //预付金 var tradeSpan = tradeSpans.FirstOrDefault(a => a.TradeId == t.id); if (ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus)) { if (riskList.Any(a => a.TradeId == t.id)) { var valueResult = riskList.FirstOrDefault(a => a.TradeId == t.id); //最新pv Pv = valueResult.Pv ?? 0; RoundedPv = valueResult.RoundedPv ?? 0; PositionPnL = valueResult.PositionPnl ?? 0.0; RoundedPositionPnL = valueResult.RoundedPositionPnl ?? 0.0; } else { Pv = 0.0; RoundedPv = 0.0; } //var valueResult = holdRisResult.ContainsKey(t.id) ? holdRisResult[t.id] : null; //if (valueResult == null) continue; var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id); //if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition); //昨日pv LastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv); //ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.ActualPv ?? 0.0); //总持仓量 Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount; //归因盈亏 RealizedPnL = lastEodPosition != null ? 0 : ((t.TradeSinglePrice ?? 0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell) * (-1)); //未归因盈亏 UnRealizedPnL = Pv - LastPv; //估值盈亏 DailyPnl = RealizedPnL + UnRealizedPnL; //名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额 NotionalPrincipal = t.OriginalStockEqvNotional > 0 ? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0) : TradeHelper.GetStockEqvNotional((t.SpotPrice ?? 0.0) * t.Notional, t.ParticipationRate, t.AnnualizeFactor); //根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv var callPutFlag = "Call".Equals(t.CallPut); var unSpotPrice = underlyingPrice.GetPrice(t.UnderlyingCode); var StrikeFlag = unSpotPrice > (t.IsMoneynessOptionData ? (t.Strike * t.SpotPrice) : (t.Strike ?? 0.0)); //实值pv计算 ActualPv = 0.0; if (callPutFlag == StrikeFlag) { var Strike = t.IsMoneynessOptionData ? ((t.Strike ?? 0.0) * t.SpotPrice ?? 0.0) : t.Strike ?? 0.0; var SpotPrice = (t.SpotPrice ?? 0); if (SpotPrice > 0) { ActualPv = t.StockEqvNotional * Math.Max((unSpotPrice - Strike) * (callPutFlag ? 1 : -1), 0) / SpotPrice * TradeCalcHelper.GetSign(t.BuySell); } } //实值浮动盈亏 //ActualDailyPnl = ActualPv - ActualLastPv; //实值总盈亏 //ActualTotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.ActualTotalPnL ?? 0.0) + ActualDailyPnl; //总盈亏 TotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.TotalPnL) + DailyPnl; //PositionPnL = Pv + RealizeProfitAndloss; } else if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)) {//已执行 已平仓 已到期的交易计算持仓信息 var tradeCash = tradeCashList.FirstOrDefault(a => a.TradeId == t.id && a.Action != ClientCashInCashOut.系统操作_期权费); Pv = ActualPv = tradeCash == null ? 0.0 : tradeCash.Amount; RoundedPv = Pv; var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id); //if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition); //昨日pv LastPv = ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv); //总持仓量 Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount; //归因盈亏 RealizedPnL = Pv; //未归因盈亏 UnRealizedPnL = -LastPv; //估值盈亏 DailyPnl = RealizedPnL + UnRealizedPnL; //名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额 NotionalPrincipal = t.OriginalStockEqvNotional > 0 ? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0) : TradeHelper.GetStockEqvNotional((t.SpotPrice ?? 0.0) * t.Notional, t.ParticipationRate, t.AnnualizeFactor); //根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv //实值pv计算 ActualDailyPnl = ActualPv - ActualLastPv; //总盈亏 ActualTotalPnL = TotalPnL = Pv - ((t.TradeSinglePrice ?? 0.0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell)); PositionPnL = RealizeProfitAndloss; RoundedPositionPnL = RealizeProfitAndloss; } if (double.IsNaN(NotionalPrincipal)) { NotionalPrincipal = 0; } var Margin = tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value; realtimePositionList.Add( new intraday_trade_position { TradeId = t.id, TradeNumber = t.TradeNumber, ValueDate = _ValueDate, BookId = t.AssetId, TradeType = t.TradeType, ClientId = t.ClientId, UnderlyingCode = t.UnderlyingCode, BuySell = t.BuySell, Cost = (t.OriginalNotional > 0 ? t.TradePrice * t.Notional / t.OriginalNotional : t.TradePrice) ?? 0, Notional = NotionalPrincipal, Amount = Quantity, LastPv = (decimal)LastPv, Pv = (decimal)Pv, RoundedPv = (decimal)RoundedPv, DailyPnL = (decimal)DailyPnl, RealizedPnL = RealizedPnL, TotalPnL = TotalPnL, PositionPnL = PositionPnL, RoundedPositionPnl = RoundedPositionPnL, ActualPv = ActualPv, ActualLastPv = ActualLastPv, ActualDailyPnL = ActualDailyPnl, ActualTotalPnL = ActualTotalPnL, Margin = Margin, PositionRelizedAmount = positionRealizedTradeCashs.Where(x => x.TradeId == t.id).Sum(x => x.Amount), TradeStatus = t.TradeStatus, OptDate = DateTime.Now, OptId = optUser.UserId, OptName = optUser.UserName, ParentTradeId = t.ParentTradeId, //收益互换 应缴预付金 初始预付金 盈亏 SwapInitMargin = 0, SwapWinLoss = 0, SwapUnMargin = 0 }); }); #endregion //删除过期和无效的交易 var intradayTradeIds = db.intraday_trade_position.Where(t => t.TradeId > 0).Select(t => t.TradeId).ToList(); var inValidTradeIds = db.trade.Where(t => intradayTradeIds.Contains(t.id) && t.ValidState == "InValid").Select(t => t.id).ToList(); var removePosition = db.intraday_trade_position.Where(t => t.ValueDate != _ValueDate || inValidTradeIds.Contains(t.TradeId)); if (removePosition.Any()) { db.intraday_trade_position.RemoveRange(removePosition); db.SaveChanges(); } //插入数据库还未有过的数据(根据TradeId,ValueDate筛选) var intradayTradeIdsExist = db.intraday_trade_position.Where(x => x.ValueDate == _ValueDate).Select(x => x.TradeId).ToList(); var realtimePositionListInsert = realtimePositionList.Where(x => !intradayTradeIdsExist.Contains(x.TradeId)); MySqlBulkExtensions.BulkInsert(db, realtimePositionListInsert); //根据TradeId,ValueDate更新已经存在的数据 var tradeids = realtimePositionList.Select(t => t.TradeId).ToList(); var intradayTradePositions = db.intraday_trade_position.Where(x => tradeids.Contains(x.TradeId) && x.ValueDate == _ValueDate).ToList(); for (var i = 0; i < intradayTradePositions.Count; i++) { var intradayTradePosition = realtimePositionList.FirstOrDefault(x => x.TradeId == intradayTradePositions[i].TradeId)?.Clone(); intradayTradePosition.id = intradayTradePositions[i].id; db.Entry(intradayTradePositions[i]).CurrentValues.SetValues(intradayTradePosition); } //删除不该存在的场外交易,例如到期日被修改到了今天之前的某一天 var intradayTradePositionDelete = db.intraday_trade_position.Where(x => !tradeids.Contains(x.TradeId) && x.TradeId > 0).ToList(); if (intradayTradePositionDelete.Any()) { db.intraday_trade_position.RemoveRange(intradayTradePositionDelete); } db.SaveChanges(); return realtimePositionList; } } } /// /// 计算实时持仓并返回结果 /// public static List RealtimeSwapPosition(OptUserInfo optUser) { string bondCalcTopic = Environment.GetEnvironmentVariable("KafkaConfig_ReqCalcBondTopic"); bool.TryParse(Environment.GetEnvironmentVariable("KafkaConfig_EnableCalcBongd"), out bool enableCalcBongd); if (optUser is null) { throw new ArgumentNullException(nameof(optUser)); } RestInitData(); lock (_RefrshLock) { using (var db = new YLContext()) { #region 获取当前持仓 标的当前价格 当前未簿记流水 并计算Risk信息 //标的 var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource(); //获取待计算交列表 var tradeList = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= _ValueDate//有效的交易 && (ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)) && t.TradeType == "收益互换").ToList(); //OTC持仓交易 var tradeIdList = tradeList.Select(t => t.id).ToList(); var positions = db.swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && !x.IsInitial && x.PosiQuantity > 0&&!x.Invalid).ToList(); var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成).ToList(); using var bondDb = new BondOmsDBContext(); var clientPositions = bondDb.client_position.AsEnumerable(); var eodSwaps = db.eod_swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && x.PosiDirection > 0).AsEnumerable().GroupBy(p => p.SwapTradeId) .Select(g => g.OrderByDescending(p => p.ValueDate).First()).ToList(); #endregion #region 实时持仓计算 //实时结果对象类 var realtimePositionList = new List(); #endregion #region 当日持仓期权交易 以及当前交易流水计算持仓 var query = from td in tradeList join p in positions on td.id equals p.SwapTradeId select new { td, p }; var positionGroup = query.AsEnumerable().GroupBy(x => new { x.p.UnderlyingCode, x.td.ClientId,x.p.PosiDirection}); var dealSwapFlowIds = new List(); SwapTradeAutoService swapTradeAutoService = new SwapTradeAutoService(optUser); var datenow = DateTime.Now; foreach (var pair in positionGroup) { var client = DataCacheProvider.GetClientDataSource().GetData(pair.Key.ClientId); if (client == null||string.IsNullOrEmpty(pair.Key.UnderlyingCode)) { continue; } var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == pair.Key.ClientId && x.security_id == pair.Key.UnderlyingCode&&x.direction== pair.Key.PosiDirection); var trades = pair.Select(s => s.td).ToList(); var tradeIds = trades.Select(x => x.id); var positionGroupItems = positions.Where(x => tradeIds.Contains(x.SwapTradeId) && x.UnderlyingCode == pair.Key.UnderlyingCode && x.PosiDirection == pair.Key.PosiDirection); var lastEodSwaps = eodSwaps.Where(x => tradeIds.Contains(x.SwapTradeId)).ToList(); var lastPv = lastEodSwaps.Sum(s => s.UnderlyingMarketValue); if (!positionGroupItems.Any()) { continue; } var comminsions = positionGroupItems.Sum(s => s.PosiTradingFeePending); var lastPosi = positionGroupItems.OrderByDescending(x => x.id).First(); var newSwapFlows = swapFlows.Where(x => x.ClientId == pair.Key.ClientId && x.UnderlyingCode == pair.Key.UnderlyingCode).ToList(); var cunrentPositions = positionGroupItems.Sum(x => x.PosiQuantity * (x.PositionType == (int)PositionTypeFlag.Long ? 1 : -1)); var positionType = cunrentPositions > 0 ? PositionTypeFlag.Long : PositionTypeFlag.Short; var posiQty = Math.Abs(cunrentPositions); var multiplier = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? ConsGlobal.bondShowPriceMultiple : 1; // 计算加权平均价格(区分债券和非债券) var weightedPrice = posiQty==0?0: positionGroupItems .Sum(s => { decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? s.PosiGrossPrice * ConsGlobal.bondShowPriceMultiple : s.PosiGrossPrice; return s.PosiQuantity * price; }) / posiQty; var weightedNetPrice = posiQty==0?0: positionGroupItems .Sum(s => { decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? s.PosiNetPrice * ConsGlobal.bondShowPriceMultiple : s.PosiNetPrice; return s.PosiQuantity * price; }) / posiQty; // 替换原代码中的 price 和 netPrice var price = weightedPrice; var netPrice = weightedNetPrice; var totalNotional = positionGroupItems.Sum(s => s.PosiNotionalValue); var um = DataCacheProvider.GetUnderlyingDataSource().GetData(pair.Key.UnderlyingCode); clientPosition = CreateClientPosition(clientPosition, pair.Key.ClientId, pair.Key.UnderlyingCode, netPrice, price, posiQty / 10000, comminsions, positionType == PositionTypeFlag.Long ? 0 : 1, lastPosi.ContractSize, pair.Key.PosiDirection); clientPosition.position_notional_principal = totalNotional; if (pair.Key.PosiDirection==(int)SwapDirectionEnum.支付) { var flowMerges = MergeSwapFlow(newSwapFlows, multiplier); dealSwapFlowIds.AddRange(newSwapFlows.Select(s => s.id)); if (flowMerges.Any()) { MergeSwapPosition(flowMerges, positionType, clientPosition, posiQty); } } clientPosition.update_user = 0; SetClientPositionPrice(clientPosition); clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1) - clientPosition.commission; clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero); clientPosition.today_profit_loss = clientPosition.swap_market_value - lastPv; if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd)//发kafka 获取成交收益率 { BondCalcApi(clientPosition); } if (clientPosition.id == 0 && clientPosition.position_qty > 0) { clientPosition.update_time = DateTime.Now; bondDb.client_position.Add(clientPosition); } else if (clientPosition.id > 0 && (clientPosition.position_qty > 0 || clientPosition.today_profit_loss != 0)) { clientPosition.update_time = DateTime.Now; } bondDb.SaveChanges(); } var sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0"; bondDb.BulkDelete(sql); bondDb.SaveChanges(); var nodealSwapFlows = swapFlows.Where(x => !dealSwapFlowIds.Contains(x.id)); if (nodealSwapFlows.Any()) { var nodealSwapFlowGroup = nodealSwapFlows.AsEnumerable().GroupBy(g => new { g.ClientId, g.UnderlyingCode }); foreach (var swapFlowGroup in nodealSwapFlowGroup) { var client = DataCacheProvider.GetClientDataSource().GetData(swapFlowGroup.Key.ClientId ?? 0); if (client == null) { continue; } var um = DataCacheProvider.GetUnderlyingDataSource().GetData(swapFlowGroup.Key.UnderlyingCode); var multiplier = um!=null&& um.IsBond() ? ConsGlobal.bondShowPriceMultiple : 1; var flowMerges = MergeSwapFlow(swapFlowGroup.ToList(), multiplier); var flowMergeMax = flowMerges.OrderByDescending(s => s.TradingQty).First(); var flowMergeMin = flowMerges.FirstOrDefault(x => x.BsType != flowMergeMax.BsType); var comminsions = flowMerges.Sum(s => s.TradingFee); var qty = flowMergeMax.TradingQty; if (flowMergeMin != null) { qty -= flowMergeMin.TradingQty; } var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == swapFlowGroup.Key.ClientId && x.security_id == swapFlowGroup.Key.UnderlyingCode); clientPosition = CreateClientPosition(clientPosition, swapFlowGroup.Key.ClientId ?? 0, swapFlowGroup.Key.UnderlyingCode, flowMergeMax.TradingAmountNetAvg ?? 0, flowMergeMax.TradingAmountAvg, qty / 10000, comminsions, flowMergeMax.BsType == (int)PositionTypeFlag.Long ? 0 : 1, flowMergeMax.ContractSize, (int)SwapDirectionEnum.支付); clientPosition.position_qty = qty / 10000; clientPosition.update_user = 0; if (clientPosition.id == 0) { clientPosition.update_time = DateTime.Now; bondDb.client_position.Add(clientPosition); } SetClientPositionPrice(clientPosition); clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1); clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero); clientPosition.today_profit_loss = clientPosition.swap_market_value; //发kafka 获取成交收益率 if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd) { CalcBandPrice(clientPosition); } else if (clientPosition.id > 0 && (clientPosition.position_qty > 0 || clientPosition.today_profit_loss != 0)) { clientPosition.update_time = DateTime.Now; } bondDb.SaveChanges(); } } sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0"; bondDb.BulkDelete(sql); bondDb.SaveChanges(); #endregion return realtimePositionList; } } } /// /// 判断是否有新流水 /// /// /// public static bool HasNewFlow(DateTime calcTime) { using (var db = new YLContext()) { return db.swap_flow.Any(x => x.OptTime >= calcTime); } } /// /// 计算RealtimeRisk /// public static void RiskCalc() { lock (_RefrshLock) { using (var db = new YLContext()) { RestInitData(); #region 获取当前持仓 标的当前价格 当前未簿记流水 并计算Risk信息 //标的 var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource(); //获取待计算交列表 var tradeList = _TradeSwapList; //OTC持仓交易 //实时计算rsik var volTypes = new List { "持仓" }; var riskList = RealTimeRiskCalc(_ValueDate, tradeList, underlyingPrice, volTypes); #endregion } } } /// /// DMA预付金计算 /// public static void CalcDMAMargin() { var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl"); var calculateMarginUrl = "/marginAlgorithm/realTimeMarginCalc"; var balanceDate = valuedateBLL.ValueDate; var preSettleDate = BLL.valuedateBLL.GetNonHolidayDefore(balanceDate.AddDays(-1)); CalculateMarginRequest request = new CalculateMarginRequest() { currentDate = balanceDate.ToString("yyyy-MM-dd"), preSettleDate = preSettleDate.ToString("yyyy-MM-dd") }; if (!string.IsNullOrEmpty(baseUrl)) { var httpHelper = new HttpHelper(baseUrl, null); // http 请求 Web项目接口 var result = httpHelper.PostRequestNoAuth(calculateMarginUrl, request).Result; if (result != null && !result.success) { LogFactory.GetLogger("DMA预付金计算").Info("互换DMA预付金计算失败:" + result.message); } } } #region 新互换实时持仓私有方法 private static void BondCalcApi(ClientPosition clientPosition) { var resp = BondCalcHepler.BondCalc(clientPosition.security_id, clientPosition.deal_full_price_avg ?? 0, "DP"); if (resp!=null) { clientPosition.deal_yield_avg = resp.ytm* ConsGlobal.bondPriceMultiple; _yLCache.StringSetWithNoPrefix("TRS-BondFullPrice:" + clientPosition.security_id, resp,TimeSpan.FromHours(1)); } } /// /// 创建持仓 /// /// /// /// /// /// /// /// /// /// private static ClientPosition CreateClientPosition(ClientPosition clientPosition, int clientId, string underlyingCode, decimal price, decimal fullPrice, decimal qty, decimal comminsion, int side,decimal contractsize,int direction) { var underlyingName = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode)?.UnderlyingName; var client = DataCacheProvider.GetClientDataSource().GetData(clientId); if (clientPosition == null) { clientPosition = new ClientPosition() { create_time = DateTime.Now, }; } clientPosition.client_id = clientId; clientPosition.client_name = client?.Name; clientPosition.security_id = underlyingCode; clientPosition.symbol = underlyingName; clientPosition.deal_price_avg = price; clientPosition.deal_full_price_avg = fullPrice; clientPosition.position_qty = qty; clientPosition.commission = comminsion; clientPosition.side = side; clientPosition.create_time = DateTime.Now; clientPosition.client_user_id = 0; clientPosition.position_notional_principal = fullPrice* qty * 10000 * contractsize * ConsGlobal.bondPriceMultiple; clientPosition.direction = direction; return clientPosition; } /// /// 合并互换流水 /// /// /// private static List MergeSwapFlow(List swapFlows, decimal multiplier) { List list = new List(); var newSwapFlowsGroups = swapFlows.GroupBy(g => g.BsType); foreach (var gourpItem in newSwapFlowsGroups) { var swapflow = gourpItem.First(); swap_flow_merge swap_flow_summary = new swap_flow_merge() { OccurTime = swapflow.OccurTime.Value, FundAccount = swapflow.FundAccount, SwapTradeId = swapflow.SwapTradeId, SwapTradeNo = swapflow.SwapTradeNo, UnderlyingCode = swapflow.UnderlyingCode, BsType = swapflow.BsType, TradingQty = gourpItem.Sum(s => s.TradingQty), TradingFeePending = gourpItem.Sum(s => s.TradingFee), DataState = (int)SwapFlowDateStateEnum.等待完成, ContractSize = swapflow.ContractSize, ClientId = swapflow.ClientId, TradingAmount = gourpItem.Sum(s => s.TradingAmount) }; int tradeSide = swap_flow_summary.BsType == (int)EnumDirection.Long ? 1 : -1; swap_flow_summary.FirstFlowTime = swapflow.OptTime; swap_flow_summary.SettleDate = gourpItem.Max(s => s.SettleDate); swap_flow_summary.TradingAmountAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountAvg * s.TradingQty) / swap_flow_summary.TradingQty; swap_flow_summary.TradingAmountAvg = Math.Round(swap_flow_summary.TradingAmountAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; swap_flow_summary.TradingAmountFeeAvg = Math.Round(swap_flow_summary.TradingAmountFeeAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); swap_flow_summary.TradingAmountNetAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountNet * s.TradingQty) / swap_flow_summary.TradingQty; swap_flow_summary.TradingAmountNetAvg = Math.Round(swap_flow_summary.TradingAmountNetAvg ?? 0, ConsGlobal.PriceRound); swap_flow_summary.TradingAmountNetFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountNetAvg : swap_flow_summary.TradingAmountNetAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty; swap_flow_summary.TradingAmountNetFeeAvg = Math.Round(swap_flow_summary.TradingAmountNetFeeAvg ?? 0, ConsGlobal.PriceRound); swap_flow_summary.TradingAmountAvg *= multiplier; swap_flow_summary.TradingAmountFeeAvg *= multiplier; list.Add(swap_flow_summary); } return list.OrderByDescending(o => o.TradingQty).ToList(); } /// /// 流水合并持仓 /// /// /// /// /// private static void MergeSwapPosition(List flowMerges, PositionTypeFlag positionType, ClientPosition clientPosition, decimal posiQty) { var flowMergeSame = flowMerges.FirstOrDefault(x => x.BsType == (int)positionType); var flowMergeNagetive = flowMerges.FirstOrDefault(x => x.BsType != (int)positionType); var sameQty = posiQty; if (flowMergeSame != null) { sameQty += flowMergeSame.TradingQty; } var allPosiQty = sameQty; if (flowMergeNagetive != null) { allPosiQty -= flowMergeNagetive.TradingQty; if (allPosiQty >= 0) { var priceResult = CalcWeightedAverage(clientPosition, flowMergeSame); clientPosition.deal_full_price_avg = priceResult.Item1; } else { clientPosition.deal_full_price_avg = flowMergeNagetive.TradingAmountAvg; } } else { var priceResult = CalcWeightedAverage(clientPosition, flowMergeSame); clientPosition.deal_full_price_avg = priceResult.Item1; } clientPosition.commission = flowMerges.Sum(s => s.TradingFee); clientPosition.position_qty = Math.Abs(allPosiQty/10000); clientPosition.position_notional_principal = Math.Abs(allPosiQty) * clientPosition.deal_full_price_avg * ConsGlobal.bondPriceMultiple; if (allPosiQty < 0) { clientPosition.side = clientPosition.side == 0 ? 1 : 0; } } private static (decimal, decimal) CalcWeightedAverage(ClientPosition clientPosition, swap_flow_merge flowMergeSame) { var originalAmount = (clientPosition.deal_full_price_avg ?? 0) * (clientPosition.position_qty ?? 0); var originalNetAmount = (clientPosition.deal_price_avg ?? 0) * (clientPosition.position_qty ?? 0); if (flowMergeSame == null) { return (clientPosition.deal_full_price_avg ?? 0, clientPosition.deal_price_avg ?? 0); } var sameAmount = flowMergeSame.TradingAmountAvg * flowMergeSame.TradingQty; var sameNetAmount = (flowMergeSame.TradingAmountNetAvg??0) * flowMergeSame.TradingQty; var totalQty = (clientPosition.position_qty ?? 0) + flowMergeSame.TradingQty; if (totalQty == 0) { return (0, 0); } var price = (originalAmount + sameAmount) / totalQty; var priceFee = (originalNetAmount + sameNetAmount) / totalQty; price = Math.Round(price, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); priceFee = Math.Round(priceFee, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); return (price, priceFee); } /// /// 从缓存中拿取债券价格 /// /// private static void SetClientPositionPrice(ClientPosition clientPosition) { if (clientPosition.position_qty <= 0) { return; } try { //TRS-BondDepthMarket:160010.IB-0 var bondPrice = EodPriceQueryService.GetChinaBondPrice(valuedateBLL.ValueDate, clientPosition.security_id); if (bondPrice != null) { clientPosition.full_price_now = bondPrice.dirty_price_close; clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * 10000 * (clientPosition.side == 0 ? 1 : -1) * ConsGlobal.bondPriceMultiple; clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * 10000 * ConsGlobal.bondPriceMultiple * (clientPosition.side == 0 ? 1 : -1); clientPosition.price_now = bondPrice.net_price; clientPosition.yield_now = bondPrice.yield * ConsGlobal.bondPriceMultiple; } else { clientPosition.full_price_now = 100; clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * 10000 * (clientPosition.side == 0 ? 1 : -1) * ConsGlobal.bondPriceMultiple; clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * 10000 * ConsGlobal.bondPriceMultiple * (clientPosition.side == 0 ? 1 : -1); clientPosition.price_now = 100; clientPosition.yield_now = 0.01m; } } catch (Exception ex) { } } /// /// 计算债券价格 /// /// private static void CalcBandPrice(ClientPosition clientPosition) { if (clientPosition.position_qty <= 0 || _yLCache == null) { return; } try { //TRS-BondDepthMarket:160010.IB-0 CalBondResult bondPrice = _yLCache.StringGetWithNoPrefix("TRS-BondFullPrice:" + clientPosition.security_id); if (bondPrice?.dirtyPrice != clientPosition.deal_full_price_avg) { BondCalcApi(clientPosition); } } catch (Exception ex) { } } #endregion /// /// 实时risk计算 /// public static List RealTimeRiskCalc(DateTime valueDate, List tradeList, IPriceProvider priceProvider, List volTypes = null, bool useSave = true, PricingRequest pricingRequest = QdpPricingRequest.BASIC_GREEKS) { // LogFactory.GetLogger().Info("CalcTradeValue Run Time:" + DateTime.Now.ToString()); //获取所有已确认交易信息 using (var db = new YLContext()) { var risks = new List(); if (tradeList == null || !tradeList.Any()) { return risks; } //计算Risk if (volTypes == null || !volTypes.Any()) { volTypes = new List { ConsGlobal.VolType.PositionVol }; } var tradeIds = tradeList.Select(t => t.id).ToList(); var tradeCashList = db.trade_cash.AsNoTracking().Where(t => t.ValidState != "InValid" && !t.IsDeleted && tradeIds.Contains(t.TradeId) && (t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_行权费)).ToList(); foreach (var volType in volTypes) { var resultRisks = new List(); var isUseTradeVol = (volType == "持仓" || volType == "对冲") && PS.Config.IsTradeVol; var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(new CalculateRisksForTradesReq { valueDate = valueDate, tradeList = tradeList, priceProvider = priceProvider, pricingRequest = pricingRequest, volType = volType, isUseTradeVol = isUseTradeVol, addVolRateDic = null, isAddVolPercent = true, isMarginCalc = false, overrideVolsForTrade = null, PreciseTimeMode = true, calcScenario = Enums.CalcScenarioEnum.RealtimePosition, canUseManual = true }); if (tradeRiskResult != null) { var eodForwardMargins = db.eod_forward_margin.Where(x => x.ValueDate == valueDate && tradeIds.Contains(x.TradeId)).ToList(); var forwards = db.trade_forward.Where(n => tradeIds.Contains(n.TradeId)).ToList(); foreach (var result in tradeRiskResult.Results) { try { var tempTradeCashList = tradeCashList.Where(t => t.TradeId == result.Trade.id).ToList(); var pnl = 0.0;// 当日盈亏 var tradePosition = _LastTradePositionList.FirstOrDefault(t => t.TradeId == result.Trade.id); if (tradePosition != null) { pnl = (double.IsNaN(result.ValueResult.Pv) ? 0.0 : (result.ValueResult.Pv)) - Convert.ToDouble(tradePosition.Pv); } else { //var futureCommission = tradeCommissionDict.ContainsKey(result.Trade.id) ? tradeCommissionDict[result.Trade.id] : 0; var isUnOption = ConsTrade.TradeTypesForHedge.Contains(result.Trade.TradeType); var cost = (isUnOption ? (result.Trade.TradePrice ?? 0.0) : (result.Trade.TradeSinglePrice ?? 0)) * result.Trade.Notional; if (result.Trade.TradeType == "远期") { pnl = NumberHelper.Normalize(result.ValueResult.Pv) + cost;// - futureCommission; } else { pnl = NumberHelper.Normalize(result.ValueResult.Pv) + cost * TradeCalcHelper.GetSign(result.Trade.BuySell) * -1;// - futureCommission; } } for (var i = 0; i < result.Underlyings.Length; ++i) { resultRisks.Add(createRisk(result.Trade, valueDate, result.Underlyings[i], null, volType, result.ValueResult, pnl, i, priceProvider.GetPrice(result.Trade.UnderlyingCode), tempTradeCashList, eodForwardMargins, forwards)); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } } } if (useSave) { //删除非交易日当天的实时持仓数据 var sql = $"{nameof(realtime_trade_risk.ValueDate)}!='{valueDate.ToSqlDate()}'"; db.BulkDelete(sql); //插入数据库还未有过的实时持仓服务计算的数据(根据TradeId,VolType,ValueDate筛选) var tradeIdsExist = db.realtime_trade_risk.Where(x => x.VolType == volType && x.ValueDate == valueDate).Select(x => x.TradeId).ToList(); var resultRisksInsert = resultRisks.Where(x => !tradeIdsExist.Contains(x.TradeId)); MySqlBulkExtensions.BulkInsert(db, resultRisksInsert); //根据TradeId,VolType,ValueDate更新已经存在的数据 var tradeids = resultRisks.Select(t => t.TradeId).ToList(); var tradeRisks = db.realtime_trade_risk.Where(x => tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList(); var delTradeRisks= db.realtime_trade_risk.Where(x => !tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList(); db.realtime_trade_risk.RemoveRange(delTradeRisks); for (var i = 0; i < tradeRisks.Count; i++) { var tradeRisk = resultRisks.FirstOrDefault(x => x.TradeId == tradeRisks[i].TradeId)?.Clone(); tradeRisk.id = tradeRisks[i].id; db.Entry(tradeRisks[i]).CurrentValues.SetValues(tradeRisk); } db.SaveChanges(); } if (volType == "持仓") { risks = resultRisks; } } return risks; } } /// /// 刷新RealTimeRisk表对应交易记录和实时持仓信息(适用于OTC场内期权交易) /// public static void RefreshRiskAndIntradayPositionForOtc(List tradeList, OptUserInfo user) { if (tradeList is null) { throw new ArgumentNullException(nameof(tradeList)); } if (user is null) { throw new ArgumentNullException(nameof(user)); } if (tradeList != null && tradeList.Any()) { new TradeDalService(user).SetSubTradeList(tradeList); using (var db = new YLContext()) { RestInitData(); //获取停牌信息 var suspensionUnderlyingIdList = underlying_managerBLL.GetQuery().Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList(); #region 获取昨日持仓 标的当前价格 当前持仓以及当日行权交易 并计算Risk信息 var clientTrades = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= valuedateBLL.ValueDate//有效的交易 && ((ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus) && (t.ExerciseDate >= _ValueDate || (suspensionUnderlyingIdList.Contains(t.UnderlyingId) && !ConsTrade.TradeTypesForHedge.Contains(t.TradeType))) && !ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) //未过期的(包括股票停牌)期权持仓交易 || (t.TradeDate > _LastSettleDate && ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) //最后结算日到当日介于区间的对冲交易 || (t.UnWindDate > _LastSettleDate && t.UnWindDate <= _ValueDate && ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)) //最后结算日到当日区间内平仓到期执行的交易 ) && ConsTrade.TradeTypesForOtcOptions.Contains(t.TradeType)).ToList(); //昨日持仓交易 var tradeIdList = tradeList.Select(t => t.id).ToList(); var underlyingIds = tradeList.Select(t => t.UnderlyingId).Distinct().ToList(); //标的 var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource(); //设置option info tradeBLL.SetFieldsByTradeType(tradeList); //OTC 交易 var otcTradeList = tradeList.Where(t => t.TradeType != "结构化交易" && t.ClientId > 0).ToList(); //预付金计算 //远期不参与计算预付金逻辑 var req = new RunMarginCalculationReq(user) { tradeList = otcTradeList, settleDate = _ValueDate, PriceProvider = underlyingPrice, hasOptionInfo = true }; var tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false)); //试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理) List tradeSpansOtherSide = new List(); if (MarginDefault.IsMarginCalcNeedSpecial(_ValueDate)) { //试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理) tradeSpansOtherSide = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: true)); } //根据交易预付金合计客户预付金计入client_span var req2 = new CalcClientMarginReq(user) { settleDate = _ValueDate, tradeSpans = tradeSpans, tradeSpansOtherSide = tradeSpansOtherSide, SpanType = ClientSpan.SpanType_RealTime }; MarginDefault.CalcClientMargin(req2); //实时计算rsik var volTypes = new List { "持仓" }; if (PS.Config.Is国投) { volTypes.Add("开仓"); } var riskList = RealTimeRiskCalc(_ValueDate, otcTradeList, underlyingPrice, volTypes); #endregion #region 平仓费行权费 交易预付金计算 昨日持仓对冲交易过滤 var unWindTradeCashAction = new List { ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_期权费 }; //获取平仓到期交易的trade_cash; var tradeCashList = db.trade_cash.Where(t => tradeIdList.Contains(t.TradeId) && unWindTradeCashAction.Contains(t.Action) && !t.IsDeleted).ToList(); //实时结果对象类 var realtimePositionList = new List(); #endregion #region 当日持仓期权交易 已行权已到期期权交易 以及当日对冲交易计算持仓 //循环交易 OTC交易 otcTradeList.ForEach(t => { var Pv = 0.0; //当日pv var RoundedPv = 0.0; var LastPv = 0.0; //昨日pv var Quantity = 0.0; //数量 var RealizedPnL = 0.0;//已归因盈亏 var DailyPnl = 0.0; //当日盈亏 var UnRealizedPnL = 0.0;//未归因盈亏 var TotalPnL = 0.0; //总盈亏 var PositionPnL = 0.0; //持仓盈亏 var RoundedPositionPnL = 0.0; var NotionalPrincipal = 0.0; var ActualPv = 0.0; //当日实际pv var ActualLastPv = 0.0; //昨日实际pv var ActualDailyPnl = 0.0; //当日实际浮动盈亏 var ActualTotalPnL = 0.0; //实际总盈亏 //部分平仓计算 var tempTradeCashList = tradeCashList.Where(a => a.TradeId == t.id); //已实现 var RealizeProfitAndloss = (tempTradeCashList.Any() ? tempTradeCashList.Sum(a => a.Amount) : 0.0); //预付金 var tradeSpan = tradeSpans.FirstOrDefault(a => a.TradeId == t.id); //已实现盈亏 var positionRealizedTradeCashs = db.trade_cash.Where(x => (x.Action == "系统操作-票息" || x.Action == "系统操作-互换") && t.ValidState != "InValid" && x.ValueDate <= _ValueDate && (x.TradeId == t.id || x.ParentTradeId == t.id)).ToList(); if (ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus)) { if (riskList.Any(a => a.TradeId == t.id)) { var openValueResult = riskList.FirstOrDefault(a => a.TradeId == t.id && a.VolType == "开仓"); if (PS.Config.Is国投 && openValueResult != null) { Pv = openValueResult.Pv ?? 0; RoundedPv = openValueResult.RoundedPv ?? 0; PositionPnL = openValueResult.PositionPnl ?? 0; RoundedPositionPnL = openValueResult.RoundedPositionPnl ?? 0; } else { var valueResult = riskList.FirstOrDefault(a => a.TradeId == t.id); Pv = valueResult.Pv ?? 0; RoundedPv = valueResult.RoundedPv ?? 0; PositionPnL = valueResult.PositionPnl ?? 0; RoundedPositionPnL = valueResult.RoundedPositionPnl ?? 0; } } else { Pv = 0.0; RoundedPv = 0.0; } //var valueResult = holdRisResult.ContainsKey(t.id) ? holdRisResult[t.id] : null; //if (valueResult == null) continue; var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id); //if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition); //昨日pv LastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv); //ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.ActualPv ?? 0.0); //总持仓量 Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount; //归因盈亏 RealizedPnL = lastEodPosition != null ? 0 : ((t.TradeSinglePrice ?? 0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell) * (-1)); //未归因盈亏 UnRealizedPnL = Pv - LastPv; //估值盈亏 DailyPnl = RealizedPnL + UnRealizedPnL; //名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额 NotionalPrincipal = "Stock".Equals(t.UnderlyingInstrumentType) ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0)); //根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv var callPutFlag = "Call".Equals(t.CallPut); var unSpotPrice = underlyingPrice.GetPrice(t.UnderlyingCode); var StrikeFlag = unSpotPrice > (t.IsMoneynessOptionData ? (t.Strike * t.SpotPrice) : t.Strike ?? 0.0); //实值pv计算 ActualPv = 0.0; if (callPutFlag == StrikeFlag) { var Strike = t.IsMoneynessOptionData ? ((t.Strike ?? 0.0) * t.SpotPrice ?? 0.0) : t.Strike ?? 0.0; var SpotPrice = t.SpotPrice ?? 0; if (SpotPrice > 0) { ActualPv = t.StockEqvNotional * Math.Max((unSpotPrice - Strike) * (callPutFlag ? 1 : -1), 0) / SpotPrice * TradeCalcHelper.GetSign(t.BuySell); } } //实值浮动盈亏 //ActualDailyPnl = ActualPv - ActualLastPv; //实值总盈亏 //ActualTotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.ActualTotalPnL ?? 0.0) + ActualDailyPnl; //总盈亏 TotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.TotalPnL) + DailyPnl; //PositionPnL = Pv + RealizeProfitAndloss; } else if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)) {//已执行 已平仓 已到期的交易计算持仓信息 var tradeCash = tradeCashList.FirstOrDefault(a => a.TradeId == t.id && a.Action != ClientCashInCashOut.系统操作_期权费); Pv = ActualPv = tradeCash == null ? 0.0 : tradeCash.Amount; RoundedPv = Pv; var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id); //if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition); //昨日pv LastPv = ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv); //总持仓量 Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount; //归因盈亏 RealizedPnL = Pv; //未归因盈亏 UnRealizedPnL = -LastPv; //估值盈亏 DailyPnl = RealizedPnL + UnRealizedPnL; //名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额 NotionalPrincipal = "Stock".Equals(t.UnderlyingInstrumentType) ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0)); //根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv //实值pv计算 ActualDailyPnl = ActualPv - ActualLastPv; //总盈亏 ActualTotalPnL = TotalPnL = Pv - ((t.TradeSinglePrice ?? 0.0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell)); TotalPnL = PositionPnL = RoundedPositionPnL = Pv + RealizeProfitAndloss; } var Margin = tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value; //收益互换 应缴预付金 初始预付金 盈亏 var SwapMargin = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value) : 0.0; var SwapInitMargin = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.SwapInitMargin ?? double.NaN) ? 0 : tradeSpan.SwapInitMargin.Value) : 0.0; var SwapWinLoss = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.SwapWinLoss ?? double.NaN) ? 0 : tradeSpan.SwapWinLoss.Value) : 0.0; var SwapUnMargin = 0d; //收益互换子交易 根据父交易预付金 按名义本金比例计算子交易预付金 if (t.TradeType == "收益互换") { //trade_span 追保==0 时 取客户浮亏作为互换可容忍金额 SwapUnMargin = tradeSpan == null || double.IsNaN(tradeSpan.SwapWinLoss ?? double.NaN) ? 0.0 : Math.Max(tradeSpan.Margin == 0 ? tradeSpan.SwapWinLoss.Value : 0.0, 0); //收益互换名义本金 NotionalPrincipal = t.StockEqvNotional; if (t.IsGroup == 2 && tradeSpans.Any(span => span.TradeId == t.ParentTradeId) && otcTradeList.Any(o => o.id == t.ParentTradeId)) { var parentTrade = otcTradeList.Find(o => o.id == t.ParentTradeId); var parentSpan = tradeSpans.Find(span => span.TradeId == t.ParentTradeId); if (parentTrade.StockEqvNotional != 0) { SwapMargin = Margin = (parentSpan.WorstCastClientPayable ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional; SwapInitMargin = (parentSpan.SwapInitMargin ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional; SwapWinLoss = (parentSpan.SwapWinLoss ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional; } } } realtimePositionList.Add( new intraday_trade_position { TradeId = t.id, TradeNumber = t.TradeNumber, ValueDate = _ValueDate, BookId = t.AssetId, TradeType = t.TradeType, ClientId = t.ClientId, UnderlyingCode = t.UnderlyingCode, BuySell = t.BuySell, Cost = (t.OriginalNotional > 0 ? t.TradePrice * t.Notional / t.OriginalNotional : t.TradePrice) ?? 0, Notional = NotionalPrincipal, Amount = Quantity, LastPv = (decimal)LastPv, Pv = (decimal)Pv, RoundedPv = (decimal)RoundedPv, DailyPnL = (decimal)DailyPnl, RealizedPnL = RealizedPnL, TotalPnL = TotalPnL, PositionPnL = PositionPnL, RoundedPositionPnl = RoundedPositionPnL, ActualPv = ActualPv, ActualLastPv = ActualLastPv, ActualDailyPnL = ActualDailyPnl, ActualTotalPnL = ActualTotalPnL, Margin = Margin, PositionRelizedAmount = positionRealizedTradeCashs.Sum(x => x.Amount), TradeStatus = t.TradeStatus, OptDate = DateTime.Now, OptId = user.UserId, OptName = user.UserName, ParentTradeId = t.ParentTradeId, //收益互换 应缴预付金 初始预付金 盈亏 SwapInitMargin = SwapInitMargin, SwapWinLoss = SwapWinLoss, SwapUnMargin = SwapUnMargin }); }); #endregion //对冲唯一标识 //var hedgeUniqueCodeList = realtimePositionList.Where(t => trade.TradeTypesForHedge.Contains(t.TradeType)).Select(t => t.HedgeUniqueCode).ToList(); var removePosition = db.intraday_trade_position.Where(t => t.ValueDate == _ValueDate && (tradeIdList.Contains(t.TradeId))); if (removePosition.Any()) { db.intraday_trade_position.RemoveRange(removePosition); } db.intraday_trade_position.AddRange(realtimePositionList); //if (removePosition != null) MySqlBulkExtensions.BulkDelete(db, removePosition); //MySqlBulkExtensions.BulkInsert(db, realtimePositionList); db.SaveChanges(); } } } /// /// 实时风险计算模型转换 /// private static realtime_trade_risk createRisk(trade tradeObj, DateTime valueDate, underlying_manager udm, Variety variety, string volType, TradeValueResult optionValueResult, double pnl, int i, double underlyingPrice, List tradeCashList, List eodForwardMargins, List forwards) { //todo:感觉这个表应该加上计算时使用的期末价格 if (udm == null) { udm = new underlying_manager(); } var result = new realtime_trade_risk { ValueDate = valueDate, TradeId = tradeObj.id, Exposure = udm.UnderlyingCode, VolType = volType, BookId = tradeObj.AssetId + "", ClientId = tradeObj.ClientId, Pv = NumberExtensions.Norm(optionValueResult.Pv), RoundedPv = NumberExtensions.Norm(optionValueResult.RoundedPv), Theta = NumberExtensions.Norm(optionValueResult.Theta), Rho = NumberExtensions.Norm(optionValueResult.Rho), DdeltaDt = NumberExtensions.Norm(optionValueResult.DDeltaDt), DdeltaDvol = NumberExtensions.Norm(optionValueResult.DDeltaDVol), DvegaDt = NumberExtensions.Norm(optionValueResult.DVegaDt), DvegaDvol = NumberExtensions.Norm(optionValueResult.DVegaDVol), Vol = NumberExtensions.Norm(optionValueResult.Vol), Pnl = pnl, OptId = 1, OptName = "管理员", OptDate = DateTime.Now, Delta = NumberExtensions.Norm(optionValueResult.GetDelta(i)), Gamma = NumberExtensions.Norm(optionValueResult.GetGamma(i)), Vega = NumberExtensions.Norm(optionValueResult.GetVega(i)), DeltaCash = NumberExtensions.Norm(optionValueResult.GetDeltaCash(i)), GammaCash = NumberExtensions.Norm(optionValueResult.GetGammaCash(i)), VegaCash = NumberExtensions.Norm(optionValueResult.VegaCash), UnderlyingPrice = optionValueResult.SpotPrice, }; result.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(result.Delta ?? 0, variety, udm); var pvShift = tradeObj.TradeType == "雪球期权" && tradeObj.trade_snowball.PrepaymentUsed ? -tradeObj.Notional * (tradeObj.SpotPrice ?? 0) * (tradeObj.trade_snowball.PrepaymentRatio ?? 0) * (tradeObj.BuySell == "卖出" ? -1 : 1) : 0; if (tradeObj.TradeType == "收益互换") { result.PositionPnl = optionValueResult.Pv; result.RoundedPositionPnl = optionValueResult.RoundedPv; } else { result.PositionPnl = EodOperationBase.GetPositionPnl((result.Pv ?? 0.0) + pvShift, tradeObj.TradePrice ?? 0.0, tradeObj.Notional, tradeObj.OriginalNotional ?? 0, tradeObj.BuySell); result.RoundedPositionPnl = EodOperationBase.GetPositionPnl((result.RoundedPv ?? 0.0) + pvShift, tradeObj.TradePrice ?? 0.0, tradeObj.Notional, tradeObj.OriginalNotional ?? 0, tradeObj.BuySell); } result.RealizedPnl = optionValueResult.ExtendInfo.RealPnl; if (tradeObj.TradeType == "远期") { using (var db = new YLContext()) { var marginCost = eodForwardMargins.Where(x => x.TradeId == tradeObj.id) .Select(n => (double?)n.MarginCost).FirstOrDefault() ?? 0; var forward = forwards.FirstOrDefault(n => n.TradeId == tradeObj.id); var unwindTradeCashList = tradeCashList.Where(t => t.TradeId == tradeObj.id && t.ValidState != "InValid" && !t.IsDeleted && t.Action != ClientCashInCashOut.系统操作_期权费 && t.ValueDate == valueDate).ToList(); //开仓费用 + 平仓费用 var positionCost = forward.OpenCommission * (tradeObj.Lots ?? 0) + unwindTradeCashList.Sum(a => (a.UnwindPrice ?? 0) * a.UnwindNotional.Value / tradeObj.OriginalNotional.Value * (tradeObj.Lots ?? 0)); //平仓比例 double unwindRatio = unwindTradeCashList.Any() ? unwindTradeCashList.Sum(a => a.UnwindNotional.Value) / tradeObj.OriginalNotional.Value : 0; //持仓比例 double positionRatio = 1 - unwindRatio; //实现盈亏 = (交易已平仓) 开仓总费用 * 平仓比例 + 平仓总费用 //实现盈亏 = (交易未平仓) 0 double totalFee = unwindTradeCashList.Any() ? (tradeObj.TradePrice ?? 0) * unwindRatio + unwindTradeCashList.Sum(a => a.Amount) : 0; //持仓市值 = 交易员视角的合约总价值(远期合约价值+开仓费用+平仓费用)-交易员视角的已实现盈亏 result.Pv = result.Pv.Value; result.RoundedPv = result.RoundedPv.Value; //持仓盈亏 = 持仓市值+开仓总费用 * 持仓比例 result.PositionPnl = result.Pv.Value + (tradeObj.TradePrice ?? 0) * positionRatio + marginCost; result.RoundedPositionPnl = result.RoundedPv + (tradeObj.TradePrice ?? 0) * positionRatio + marginCost; result.RealizedPnl = totalFee; result.Pnl += marginCost; } } double? nowPrice = 0; if (!string.IsNullOrWhiteSpace(tradeObj.UnderlyingCode)) { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(tradeObj.UnderlyingCode); if (underlying == null) { throw new Exception($"未找到标的:{tradeObj.UnderlyingCode}"); } else { nowPrice = underlying.Price; } } result.CreditExposure = EodPositionRisksQueryService.ExposureCalc(tradeObj, nowPrice ?? 0, BLL.valuedateBLL.ValueDate); if (result.UnderlyingPrice == null) { result.UnderlyingPrice = underlyingPrice; } if (tradeCashList != null && tradeCashList.Any() && tradeObj.TradeType != "远期") { tradeCashList.ForEach(t => { result.RealizedPnl += t.Amount - ((tradeObj.TradePrice ?? 0.0) * (t.UnwindPercentRate ?? 0.0) * TradeCalcHelper.GetSign(tradeObj.BuySell)); }); } return result; } /// /// 计算客户实时资金 /// public static List GetRealTimeClientBanlance(List clientIdList, DateTime? startDate = null) { if (null == clientIdList || !clientIdList.Any()) { return null; } if (!startDate.HasValue) { startDate = DateTime.MinValue; } var cashSwapActions = new List() { ClientCashInCashOut.系统操作_应付预付金, ClientCashInCashOut.系统操作_预付金返息, ClientCashInCashOut.系统操作_期权费 }; using (var db = DbContextFactory.GetYLDbContext()) using (var db2 = DbContextFactory.GetClientDbContext(null)) { //获取系统参数 var systemDate = valuedateBLL.SystemDate; //系统交易日 var valueDate = systemDate.ValueDate; //客户信息 var clientList = db2.client.Where(t => clientIdList.Contains(t.id)).ToList(); var clientIds = clientList.Select(t => t.id).ToList(); var clientparentId = clientList.Select(t => t.ParentId).ToList(); //获取客户预付金(实时计算更新) var clientSpans = db.client_span.Where(t => t.ValueDate == valueDate && t.SpanType == ClientSpan.SpanType_RealTime); //获取客户昨日资金结算信息 var clientBanlances = new List(); var lastSettletDate = DateTime.MinValue; var query = db.ClientBalanceDaily.Where( t => t.BalanceDate < valueDate && t.BalanceDate.HasValue); if (query.Any()) { lastSettletDate = query.Max(t => t.BalanceDate).Value; clientBanlances = db.ClientBalanceDaily.Where(t => t.BalanceDate == lastSettletDate && clientIds.Contains(t.ClientId)).ToList(); } //获取实时持仓 var positionList = db.intraday_trade_position .Where(t => t.ValueDate == valueDate && clientIds.Contains(t.ClientId)).ToList(); var tradeIds = positionList.Where(t => t.TradeId != 0).Select(t => t.TradeId).ToList(); var positionTrades = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList(); var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成 && x.OccurTime == valueDate).ToList(); ; //获取当日所有出入金记录 var newValuedate = valueDate.AddDays(1); var lastSettletDateAddOne = lastSettletDate.AddDays(1); //var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认 || (t.Direction == "出金" && ClientCashInCashOut.outCashCals.Contains(t.State))) && clientIds.Contains(t.ClientId ?? 0)) var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) join trade in db.trade on cash.TradeId equals trade.id into trade from td in trade.DefaultIfEmpty() where td.TradeType != "收益互换" select cash; var ClientCashSwapList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0)) join trade in db.trade.Where(x => x.TradeType == "收益互换") on cash.TradeId equals trade.id select cash; //获取客户所有现存(抵押状态)抵押品信息 var clientProductList = db.clientcashincashout_product.Where(t => (t.Status == Clientcashincashout_productStatusEnum.抵押.ToString() && t.OptStatus == ClientCashInCashOut.已确认 || t.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && t.OptStatus != ClientCashInCashOut.已确认 || t.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && t.OptStatus == ClientCashInCashOut.已确认 && t.BackDate >= newValuedate) && clientIds.Contains(t.ClientId) && t.HappenDate < newValuedate).ToList(); var productUnderlyingIds = clientProductList.Select(t => t.UnderlyingId ?? 0).ToHashSet(); var umList = DataCacheProvider.GetUnderlyingDataSource(); var eodPriceProvider = EodPriceProviderFactory.Get(valueDate).GetPriceProvider(TradeCalcHelper.GetSettlementType()); var allTradeList = db.trade.Where(t => t.ValidState != "InValid" && t.TradeDate <= valueDate && clientIdList.Contains(t.ClientId) && ConsTrade.TradeStatusAfterConfirmed .Contains(t.TradeStatus) && t.ParentTradeId == 0 ).ToList(); var finishedTradeCash = from tc in db.trade_cash join td in db.trade on tc.TradeId equals td.id where (tc.ValueDate >= startDate && tc.ValueDate <= valueDate && tc.HappenedDate == null || tc.HappenedDate >= startDate && tc.HappenedDate <= valueDate) && tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted && (tc.Action == ClientCashInCashOut.系统操作_平仓费 || tc.Action == ClientCashInCashOut.系统操作_行权费 || tc.Action == ClientCashInCashOut.系统操作_票息 || tc.Action == ClientCashInCashOut.系统操作_互换 || tc.Action == ClientCashInCashOut.人工操作_其他) && td.IsGroup != 1 select tc; var finishedTradeNotionalList = finishedTradeCash.ToList(); var finishedTradeNotionalDic = finishedTradeNotionalList.GroupBy(tc => tc.TradeId).ToDictionary(g => g.Key, g => g.Sum(tc => tc.Action == ClientCashInCashOut.系统操作_平仓费 ? (tc.UnwindNotional ?? 0) : tc.Notional)); //所有当日待结算的trade_cash记录(当日为应付日的冻结资金) //var payDateTradeIds = db.trade.Where(t => t.TradeDate != valuedate && t.PremiumPayDate == valuedate).Select(t => t.id).ToList(); //var tradeCashList = db.trade_cash.Where(t => payDateTradeIds.Contains(t.TradeId ?? 0) && t.Status == TradeCashStatusEnum.冻结).ToList(); //获取当日所有执行的交易 交易日为当前交易日或者行权日为当前交易日 var positionTradeList = db.trade.Where(t => clientIds.Contains(t.ClientId)) .Where(t => t.TradeType != "场内期权") .Where(t => t.ValidState != "InValid") //有效的交易 .Where(t => (t.TradeDate > lastSettletDate && t.TradeDate <= valueDate) && ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)) //最后结算日到当日成交的交易 .Where(t => GlobalDicionary.SupportTradeTypes.Contains(t.TradeType)); //当日成交 var todayTradeList = positionTradeList.Where(t => t.TradeDate == valueDate).ToList(); var todayTradesAfterConfirmed = db.trade.Where(t => clientIds.Contains(t.ClientId)) .Where(t => t.TradeType != "场内期权") .Where(t => t.ValidState != "InValid") .Where(t => (t.TradeDate == valueDate) && ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus)) .Where(t => (GlobalDicionary.SupportTradeTypes.Contains(t.TradeType) || t.TradeType == "结构化交易") && t.ParentTradeId == 0); //positionTradeList.Where(t => t.TradeDate == valuedate || (unWindTradeStatus.Contains(t.TradeStatus) && t.UnWindDate==valuedate)).ToList(); var creditList = new List(); //获取所有客户授信 creditList = db.credit.Where(t => clientIds.Contains(t.ClientId ?? 0) && t.ProcessStatus == "已审批" && (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate)).ToList(); var clients = DataCacheProvider.GetClientDataSource().AsQueryable().ToList(); var parentexit = clients.Where(c => clientparentId.Contains(c.id)).ToList(); if (creditList.Count() == 0 && parentexit != null) { creditList = db.credit.Where(t => clientparentId.Contains(t.ClientId ?? 0) && t.ProcessStatus == "已审批" && (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate)).ToList(); } //获取所有资信等级 var creditRatingList = db2.credit_rating.Where(t => t.ValidState != "InValid").ToList(); //获取冻结资金信息 var clientFrozenFunds = new ClientFrozenFundsService(OptUserInfo.SystemUser).GetDatas(valueDate, clientIdList); //预付金比率 var marginRation = systemDate.MarginRatio ?? 0.15; //最大可提取预付金上限比率 var marginMaxRation = marginRation + 0.02; DateTime? UpdateDate = null; var ClientBanlanceList = new List(); //客户盘中结算 clientList.ForEach(client => { //当日应付冻结权利金 var FreezePremium = 0.0; //冻结出金 var FrozenOutFund = 0.0; //冻结抵押品赎回 var FrozenRedeemFunds = 0.0; var OptionPremium = 0.0; var OptionPremiumSwap = 0.0; //平仓行权收益 var SettlementBalance = 0.0; //平仓收益 var UnwindBalance = 0.0; //行权收益 var ExerciseBalance = 0.0; //互换收益 var SwapBalance = 0.0; //当日应收冻结权利金 var ReceivablesPremium = 0.0; //当日资金净出入 var NetFund = 0.0; //其他收支 var OtherFund = 0.0; //票息 var Coupon = 0.0; //当日入金 var InFund = 0.0; //当日出金 var OutFund = 0.0; //其他收入 var InFundOther = 0.0; //其他支出 var OutFundOther = 0.0; //账户资金 var AmountFund = 0.0; //前日账户资金 var LastDayRemainFund = 0.0; //今日可用资金 var AvailableAmount = 0.0; //授信额度 var lineOfCredit = 0.0; //交易总数 var totalTradeCount = 0; //交易笔数(当日成交) var todayTradeCount = 0; //交易总额 //var TradeTotalFund = 0.0; //卖权交易数 var sellCount = 0; //名义本金(卖出) var SellNotionalPrincipal = 0.0; //买权交易数 var buyCount = 0; //名义本金(买入) var BuyNotionalPrincipal = 0.0; //名义本金总额 var totalNotionalPrincipal = 0.0; //当日交易名义本金 var todayNotionalPrincipal = 0.0; //持仓笔数 var PositionCount = 0; //持仓市值 var PositionPv = 0.0; var RoundedPositionPv = 0.0; //空头持仓市值 var SellPv = 0.0; //客户持仓交易预付金总和,客户买入为正,客户卖出为负 double PrepaymentAmount = 0.0; //当日盈亏 var DaliyPnl = 0.0; //持仓盈亏 var PositionPnl = 0.0; var RoundedPositionPnl = 0.0; //期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的 var ClientSellPositionPnl = 0.0; //抵押品 //应付预付金(要么为负要么为零) //最新概念:负数代表客户应缴预付金,正数代表客户应收预付金 var PayableMargin = 0.0; //互换占用预付金 var SwapPayableMargin = 0.0; //互换容忍金额 var SwapUnMargin = 0.0; //互换追保金额 var SwapMargin = 0d; //双向预付金 var TwoSideMargin = 0.0; //当日新增应付预付金 var TodayNewMargin = 0.0; //潜在行权盈余 var PotentialSurpluses = 0.0; //预付金余额 var MarginBalance = 0.0; //追保金额 var Margin = 0.0; //可取预付金 //可取预付金为预付金余额 - 应缴预付金(上浮2%) var AdvisableMargin = 0.0; //授信是否可用于期权费 var IsTradeCredit = true; //实现盈亏 var WinLoss = 0.0; //持仓期权费净额(客户角度卖出为负,买入为正) var PositionPremiumNetCash = 0.0; //权利金冻结:当日该客户所有持仓的卖出期权权利金 var SellTradePrice = 0.0; // 期初持仓交易净额 var LastDayPositionPremiumNetCash = 0.0; //可用名义本金规模 double? AvailableStockEqvNotional = null; //当前互换流水费用 decimal curSwapFee = 0; //获取客户授信 var credits = creditList?.Where(a => a.ClientId == client.id || a.ClientId == client.ParentId); if (credits.Any()) { lineOfCredit = credits.Sum(t => t.Credit ?? 0); AvailableStockEqvNotional = creditList.Sum(O => O.StockEqvNotional) ?? 0; } else { lineOfCredit = 0.0; AvailableStockEqvNotional = null; } var creditRatingId = 0; var clientRatingQuery = from cr in db2.Client_Rating.Where(x => !x.IsDeleted && x.ProcessStatus == "已审批") where cr.RatingStartDate <= valueDate && cr.RatingDeadLine >= valueDate && cr.ClientId == client.id orderby cr.RatingDeadLine descending orderby cr.ProcessOptDate descending select cr.CreditRatingId; if (clientRatingQuery.Any()) { creditRatingId = clientRatingQuery.FirstOrDefault(); } //资信等级授信额度 var creditRating = creditRatingList?.FirstOrDefault(a => a.id == creditRatingId); var clientBanlance = clientBanlances.FirstOrDefault(a => a.ClientId == client.id); AmountFund = clientBanlance == null ? 0.0 : clientBanlance.ToDayRemainFund ?? 0.0; //上日资金余额 LastDayRemainFund = AmountFund; //昨日抵押品总价值 var lastGuaranteesTotalAmount = clientBanlance == null ? 0.0 : clientBanlance.TodayRemianFundProduct ?? 0.0; //资金净流入 + 权利金收支 + 期权费收支 var clientCashSwap = ClientCashSwapList.Where(a => a.ClientId == client.id).ToList(); if (clientCashSwap.Any()) { if (clientCashSwap.Any(a => a.Direction == "应收" && cashSwapActions.Contains(a.Action))) { OptionPremiumSwap = clientCashSwap.Where(a => a.Direction == "应收" && cashSwapActions.Contains(a.Action)).Sum(a => a.Money ?? 0.0); } if (clientCashSwap.Any(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_平仓费 || a.Action == ClientCashInCashOut.系统操作_互换))) { SwapBalance = clientCashSwap.Where(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_平仓费 || a.Action == ClientCashInCashOut.系统操作_互换)).Sum(a => a.Money ?? 0.0); } } curSwapFee = swapFlows.Where(x => x.ClientId == client.id).Sum(s => s.TradingFee); OptionPremiumSwap += Convert.ToDouble(curSwapFee); var clientCash = ClientCashList.Where(a => a.ClientId == client.id).ToList(); if (clientCash.Any()) { if (clientCash.Any(a => a.Direction == "应收" && a.Action == ClientCashInCashOut.系统操作_期权费)) { OptionPremium = clientCash .Where(a => a.Direction == "应收" && a.Action == ClientCashInCashOut.系统操作_期权费) .Sum(a => a.Money ?? 0.0); } if (clientCash.Any(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_行权费 || a.Action == ClientCashInCashOut.系统操作_平仓费))) { var settlementCashList = clientCash.Where(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_行权费 || a.Action == ClientCashInCashOut.系统操作_平仓费)); SettlementBalance = settlementCashList.Sum(a => a.Money ?? 0.0); UnwindBalance = settlementCashList.Where(x => x.Action == ClientCashInCashOut.系统操作_平仓费).Sum(a => a.Money ?? 0.0); ExerciseBalance = settlementCashList.Where(x => x.Action == ClientCashInCashOut.系统操作_行权费).Sum(a => a.Money ?? 0.0); } if (clientCash.Any(a => a.Action == ClientCashInCashOut.系统操作_票息)) { Coupon = clientCash .Where(a => a.Action == ClientCashInCashOut.系统操作_票息) .Sum(a => a.Money ?? 0.0); } #region 计算实现盈亏 var todayFinishedTrades = allTradeList.Where(t => finishedTradeNotionalDic.Select(d => d.Key).Contains(t.id) && t.ClientId == client.id).ToList(); var todayFinishedTradeCash = from tc in finishedTradeCash join td in db.trade on tc.TradeId equals td.id where td.IsGroup != 1 group tc by td.ClientId into g select new { ClientId = g.Key, amountSum = g.Sum(n => n.Amount) }; WinLoss = todayFinishedTrades.Sum(t => t.TradeType != "远期" ? (TradeCalcHelper.GetSign(t.BuySell) * (t.TradeSinglePrice ?? 0) * finishedTradeNotionalDic[t.id]) : (-(t.TradePrice ?? 0) * (finishedTradeNotionalDic[t.id] / (t.OriginalNotional ?? 0)))) //远期开仓总费用所占比重 - (todayFinishedTradeCash.FirstOrDefault(x => x.ClientId == client.id)?.amountSum ?? 0); #endregion if (clientCash.Any(a => a.Direction == "入金" || a.Direction == "出金")) { var inFunds = clientCash.Where(a => a.Direction == "入金").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList(); inFunds.ForEach(x => { new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj); if (rateObj == null) { throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}"); } InFund += x.Money * rateObj.Rate; }); var outFunds = clientCash.Where(a => a.Direction == "出金").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList(); outFunds.ForEach(x => { new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj); if (rateObj == null) { throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}"); } OutFund += x.Money * rateObj.Rate; }); NetFund = InFund - OutFund; } if (clientCash.Any(a => a.Direction == "其他收入" || a.Direction == "其他支出")) { var inFundOthers = clientCash.Where(a => a.Direction == "其他收入").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList(); inFundOthers.ForEach(x => { new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj); if (rateObj == null) { throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}"); } InFundOther += x.Money * rateObj.Rate; }); var outFundOthers = clientCash.Where(a => a.Direction == "其他支出").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList(); outFundOthers.ForEach(x => { new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj); if (rateObj == null) { throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}"); } OutFundOther += x.Money * rateObj.Rate; }); OtherFund = InFundOther + OutFundOther; } } //抵押品资金价值 var tempClientProductList = clientProductList.Where(a => a.ClientId == client.id).ToList(); var GuaranteesTotalAmount = 0.0; if (tempClientProductList.Any()) { foreach (var t in tempClientProductList) { var um = umList.GetData(t.UnderlyingId ?? 0); if (um != null) { if (!eodPriceProvider.TryGetPrice(um.UnderlyingCode, out var price_cp)) { price_cp = umList.GetPrice(um.UnderlyingCode); } GuaranteesTotalAmount += (t.ProductAmount ?? 0) * (t.Rate ?? 0.0) * price_cp; } } } //持仓 //潜在行权盈余 PotentialSurpluses = 0.0; var clientPositionList = positionList.Where(a => a.ClientId == client.id && ConsTrade.NeedMarginTradeStatusList.Contains(a.TradeStatus)) .ToList(); //持仓笔数 var clientPositionTrades = positionTrades.Where(t => t.ClientId == client.id && ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)); PositionCount = clientPositionTrades.Count(t => t.ParentTradeId == 0) + clientPositionTrades.Where(t => t.ParentTradeId > 0) .AsEnumerable() .GroupBy(t => t.ParentTradeId).Count(); //应付预付金 SellNotionalPrincipal = 0.0; BuyNotionalPrincipal = 0.0; totalNotionalPrincipal = 0.0; UpdateDate = null; if (PositionCount > 0) { UpdateDate = clientPositionList.Max(a => a.OptDate); if (valuedate.PotentialSurplusCalcMode_ActualPv.Equals(systemDate .PotentialSurplusCalcMode)) { PotentialSurpluses = clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.ActualPv) * (-1); //潜在行权收益等于实值额 } else { PotentialSurpluses = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.Pv) * (-1)); //潜在行权收益等于实值额 } PositionPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.Pv)); RoundedPositionPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.RoundedPv)); SellPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Where(x => x.BuySell == "买入").Sum(a => a.Pv)); //客户持仓交易预付金总和,客户买入为正,客户卖出为负 PrepaymentAmount = positionTrades.Sum(x => x.StockEqvNotional * (x.trade_snowball?.PrepaymentRatio ?? 0) * (x.BuySell == "卖出" ? 1 : -1)); DaliyPnl = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.DailyPnL)); PositionPnl = clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.PositionPnL); RoundedPositionPnl = clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.RoundedPositionPnl); #region 期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的, 结构化交易需要将两条腿的空头Pnl合计 var parentIds = clientPositionList.Where(x => x.TradeType == "结构化交易").Select(x => x.TradeId).ToList(); var parentPositionPnlList = from t in clientPositionList.Where(x => parentIds.Contains(x.ParentTradeId)) group t by new { t.ParentTradeId } into g select new { parentTradeId = g.Key.ParentTradeId, ClientSellPositionPnl = Math.Max(g.Sum(n => n.BuySell == "买入" ? -n.PositionPnL : 0), 0) }; var parentPositionPnlTotal = parentPositionPnlList.Sum(x => x.ClientSellPositionPnl); var singlePositionPnlTotal = clientPositionList.Where(x => x.TradeType != "结构化交易" && x.ParentTradeId == 0).Sum(n => n.BuySell == "买入" ? Math.Max(-n.PositionPnL, 0) : 0); ClientSellPositionPnl = parentPositionPnlTotal + singlePositionPnlTotal; #endregion } //获取tradespan 追保金额 = (当日资金余额 - 维持预付金) + 授信额度 var clientSpan = clientSpans.FirstOrDefault(t => t.ClientId == client.id); PayableMargin = clientSpan == null || clientSpan.WorstCastClientPayable == null ? 0.0 : clientSpan.WorstCastClientPayable.Value; TwoSideMargin = clientSpan == null || clientSpan.WorstCastClientPayable == null ? 0.0 : clientSpan.WorstCastClientPayable.Value; SwapPayableMargin = clientSpan == null || clientSpan.SwapWorstCastClientPayable == null ? 0.0 : clientSpan.SwapWorstCastClientPayable.Value; SwapUnMargin = clientSpan == null || clientSpan.SwapUnMargin == null ? 0.0 : clientSpan.SwapUnMargin.Value; //存量交易持仓名义本金规模 AvailableStockEqvNotional -= allTradeList.Where(O => O.ClientId == client.id && ConsTrade.PositionTradeStatusList.Contains(O.TradeStatus) && O.ParentTradeId == 0).Sum(O => (double?)O.StockEqvNotional) ?? 0; //交易数量 var clientAllTradeList = allTradeList.Where(t => t.ClientId == client.id).ToList(); if (clientAllTradeList.Count > 0) { //名义本金取 客户买入(交易员为卖出)的客户 SellNotionalPrincipal = clientAllTradeList.Sum(a => (a.OriginalStockEqvNotional > 0 ? (a.OriginalStockEqvNotional ?? 0.0) : ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0))) * ("买入".Equals(a.BuySell) ? 1 : 0)); BuyNotionalPrincipal = clientAllTradeList.Sum(a => (a.OriginalStockEqvNotional > 0 ? (a.OriginalStockEqvNotional ?? 0.0) : ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0))) * ("卖出".Equals(a.BuySell) ? 1 : 0)); totalNotionalPrincipal = SellNotionalPrincipal + BuyNotionalPrincipal; buyCount = clientAllTradeList.Where(p => p.BuySell == "卖出").Count(); sellCount = clientAllTradeList.Where(p => p.BuySell == "买入").Count(); totalTradeCount = buyCount + sellCount; } //当日成交 新增交易 var todayClientTradeList = todayTradeList.Where(a => a.ClientId == client.id).ToList(); var addNewTradeIds = todayClientTradeList.Select(a => a.id).ToList(); if (addNewTradeIds.Count > 0 && clientPositionList.Where(x => x.ParentTradeId == 0).Any(a => addNewTradeIds.Contains(a.TradeId))) { //当日新增预付金 TodayNewMargin = clientPositionList.Where(x => x.ParentTradeId == 0).Sum(a => (a.Margin) * (a.BuySell == "买入" ? -1 : 0)); } var todayClientTradesAfterConfirmed = todayTradesAfterConfirmed.Where(a => a.ClientId == client.id).ToList(); //交易笔数 todayTradeCount = todayClientTradesAfterConfirmed.Count; todayNotionalPrincipal = todayClientTradesAfterConfirmed.Sum(a => (a.OriginalStockEqvNotional > 0 ? (a.OriginalStockEqvNotional ?? 0.0) : ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0)))); //应付冻结权利金 var clientFrozenFund = clientFrozenFunds[client.id]; FreezePremium = clientFrozenFund.FrozenPayableOptionMoney; ReceivablesPremium = clientFrozenFund.FrozenReceivableOptionMoney; FrozenOutFund = clientFrozenFund.OutFunds; FrozenRedeemFunds = clientFrozenFund.RedeemFunds; //冻结预付金(绝对值) var FrozenMarginMoney = clientFrozenFund.FrozenMarginMoney; //var tempTrades = positionTrade.Where(a => a.ClientId == client.id && trade.NeedMarginTradeStatusList.Contains(a.TradeStatus) && a.PremiumPayDate > valueDate).ToList(); //if (tempTrades.Any()) //{ // //应付冻结权利金 // if (tempTrades.Where(a => a.BuySell == "卖出").Any()) // { // FreezePremium = tempTrades.Where(a => a.BuySell == "卖出").Sum(a => a.TradePrice ?? 0.0); // } // //应收冻结权利金 // if (tempTrades.Where(a => a.BuySell == "买入").Any()) // { // ReceivablesPremium = tempTrades.Where(a => a.BuySell == "买入").Sum(a => a.TradePrice ?? 0.0); // } //} //当前账号资金 AmountFund = AmountFund + NetFund + OtherFund + Coupon + SwapBalance + OptionPremium + OptionPremiumSwap + SettlementBalance; //当日可用资金 账户总资金 - 应付冻结权利金 - 冻结出金 - 冻结抵押品赎回 + 应收冻结权利金 - 应付预付金 - 冻结预付金 AvailableAmount = AmountFund - FreezePremium - FrozenOutFund - FrozenRedeemFunds + ReceivablesPremium + PayableMargin - FrozenMarginMoney; //预付金余额 MarginBalance = AmountFund - FreezePremium - FrozenOutFund - FrozenRedeemFunds + ReceivablesPremium + GuaranteesTotalAmount; //判断潜在行权盈余是否计入预付金余额 if ((systemDate.IsPotentialSurplusUseMargin ?? 0) == 1) { MarginBalance += PotentialSurpluses; AvailableAmount += PotentialSurpluses; } ////追保金额 //Margin = Math.Max(PayableMargin - MarginBalance, 0); // 除收益互换预付金资金占用后剩余资金 var marginBalanceSurplus = 0d; //计算追保金额 //是否期权费授信 if ((client.IsTradeCredit ?? 0) == 1) { IsTradeCredit = true; //授信是否可用于互换 if (client.creditCanApplySwap) { ///期权费授信可以支付权利金 则预付金余额未0时 资金从 互换剔除互换容忍金额 Margin = Math.Min(MarginBalance + lineOfCredit + (PayableMargin - SwapUnMargin), 0); } else { //互换最大可用资金 marginBalanceSurplus = Math.Max(Math.Min(Math.Max(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0); //收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度) SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnMargin), 0); //计算期权追保 Margin = Math.Min(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0) + SwapMargin; } } else { IsTradeCredit = false; //授信是否可用于互换 if (client.creditCanApplySwap) { //期权费授信不可以支付权力金时 Margin = Math.Min(Math.Max(MarginBalance, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0) + Math.Min(MarginBalance, 0); } else { //互换最大可用资金 marginBalanceSurplus = Math.Max(Math.Min(Math.Max(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0); //收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度) SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnMargin), 0) + Math.Min(marginBalanceSurplus + OptionPremiumSwap, 0); //计算期权追保 Margin = Math.Min(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0) + Math.Min(MarginBalance - OptionPremiumSwap, 0) + SwapMargin; } } //可取预付金为预付金余额 - 应缴预付金(上浮 + 0.02) AdvisableMargin = Math.Max(MarginBalance + PayableMargin * marginMaxRation / marginRation, 0); LastDayPositionPremiumNetCash = clientBanlance == null ? 0.0 : clientBanlance.PositionPremiumNetCash ?? 0.0; PositionPremiumNetCash = clientPositionList.Sum(t => t.Cost * (-TradeCalcHelper.GetSign(t.BuySell))); SellTradePrice = clientPositionList.Where(x => x.BuySell == "买入").Sum(t => (t.Cost)); #region 新交易权利金, 新交易预付金,新交易初保,额外追保,总追保金额 var todayNewClientPostionList = clientPositionList .Where(a => addNewTradeIds.Contains(a.TradeId)).ToList(); #endregion ClientBanlanceList.Add(new ClientSettleBalance { ValueDate = valueDate, ClientId = client.id, FreezePremium = FreezePremium, FrozenOutFund = FrozenOutFund, FrozenRedeemFunds = FrozenRedeemFunds, ReceivablesPremium = ReceivablesPremium, NetFund = NetFund, OtherFund = OtherFund, AmountFund = AmountFund, LastDayRemainFund = LastDayRemainFund, LastDayRemainFundWithProduct = LastDayRemainFund + lastGuaranteesTotalAmount, AvailableAmount = AvailableAmount, CreditRating = creditRating == null ? "" : creditRating.CreditName, TotalCredit = lineOfCredit, //CreditUsed = lineOfCredit > 0 ? Math.Max(-AvailableAmount / lineOfCredit, 0.0) : 0.0, TradeCount = todayTradeCount, SellNotionalPrincipal = SellNotionalPrincipal, BuyNotionalPrincipal = BuyNotionalPrincipal, PositionCount = PositionCount, PayableMargin = PayableMargin, TwoSideMargin = TwoSideMargin, PotentialSurpluses = PotentialSurpluses, MarginBalance = MarginBalance, Margin = Margin, AdvisableMargin = AdvisableMargin, UpdateDate = UpdateDate, IsTradeCredit = IsTradeCredit, OptionPremium = OptionPremium, OptionPremiumSwap = OptionPremiumSwap, SwapPayableMargin = SwapPayableMargin, SwapUnMargin = SwapUnMargin, SettlementBalance = SettlementBalance, UnwindBalance = UnwindBalance, ExerciseBalance = ExerciseBalance, SwapBalance = SwapBalance, Coupon = Coupon, TodayNewMargin = TodayNewMargin, GuaranteesTotalAmount = GuaranteesTotalAmount, PositionPv = PositionPv * (-1), //客户方向取反 RoundedPositionPv = RoundedPositionPv * (-1), SellPv = SellPv * (-1), PrepaymentAmount = PrepaymentAmount, DaliyPnl = DaliyPnl * (-1), PositionPnl = PositionPnl * (-1), RoundedPositionPnl = RoundedPositionPnl * (-1), ClientSellPositionPnl = ClientSellPositionPnl, LastGuaranteesTotalAmount = lastGuaranteesTotalAmount, CashInCashOutProductChange = GuaranteesTotalAmount - lastGuaranteesTotalAmount, TotalTradeCount = totalTradeCount, SellCount = sellCount, BuyCount = buyCount, TotalNotionalPrincipal = totalNotionalPrincipal, TodayNotionalPrincipal = todayNotionalPrincipal, PositionPremiumNetCash = PositionPremiumNetCash, SellTradePrice = SellTradePrice, LastDayPositionPremiumNetCash = LastDayPositionPremiumNetCash, WinLoss = WinLoss, AvailableStockEqvNotional = AvailableStockEqvNotional ?? 0, }); }); return ClientBanlanceList; } } public static bool TradeCanBeConfirm(int clientId, trade trade, out string errorMsg) { errorMsg = ""; if (trade.TradeType == "现金流交易" || (trade.TradeType == "结构化交易" && trade.UnderlyingCode == null)) { return true; } var clientBalances = GetRealTimeClientBanlance(new List { clientId }); if (clientBalances == null || clientBalances.Count <= 0) { errorMsg = "客户实时资金错误!"; return false; } if (trade.Warning) { new TradeDalService(OptUserInfo.SystemUser).RollbackToBeforeSettle(trade, valuedateBLL.ValueDate); } if (trade.IsOption() || trade.TradeType == "结构化交易" || trade.TradeType == "自定义交易") { //交易为买入 即:客户为卖出 if (EnumTradeBuySell.Buy.Equals(trade.BuySell)) { var clientBalance = clientBalances[0]; using (var db = new YLContext()) { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId); if (underlying == null) { errorMsg = "未找到标的信息"; return false; } if (trade.ExerciseDate.Value.Date >= valuedateBLL.ValueDate.Date) { var tradePrice = trade.TradePrice * (-TradeCalcHelper.GetSign(trade.BuySell)); var margin = trade.InitialMargin ?? 0; var endMoney = margin + tradePrice; var AvailableAmount = Math.Max(clientBalance.AvailableAmount + clientBalance.TotalCredit, 0); if (AvailableAmount < endMoney) { errorMsg = $"当前交易应付预付金:{margin:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。"; return false; } } return true; } } else//交易为卖出 即:客户为买入 { var clientBalance = clientBalances[0]; var tradePrice = trade.TradePrice; var AvailableAmount = clientBalance.AvailablePremium(); var endMoney = tradePrice; if (AvailableAmount >= tradePrice) { return true; } else { errorMsg = $"当前交易应付预付金:{0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。"; return false; } } } else if (trade.TradeType == "收益互换") { var clientBalance = clientBalances[0]; using (var db = new YLContext()) { var tradePrice = trade.TradePrice * (-TradeCalcHelper.GetSign(trade.BuySell)); var AvailableAmount = clientBalance.AvailablePremium(); if (AvailableAmount < tradePrice && tradePrice > 0) { var endMoney = tradePrice; errorMsg = $"当前交易应付预付金:{0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。"; return false; } else { if (trade.StructureType != "多空组合") { var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId); if (underlying == null) { errorMsg = "未找到标的信息"; return false; } } if (trade.ExerciseDate.Value.Date >= valuedateBLL.ValueDate.Date) { var margin = trade.InitialMargin ?? 0; var endMoney = margin + tradePrice; AvailableAmount = Math.Max(clientBalance.AvailableAmount + clientBalance.TotalCredit, 0); if (AvailableAmount < margin + tradePrice) { errorMsg = $"当前交易应付预付金:{trade.InitialMargin ?? 0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额,交易费用:{tradePrice ?? 0:F3}"; return false; } } return true; } } } else if (trade.TradeType == "远期") { using (var db = new YLContext()) { var forwardTrade = db.trade_forward.FirstOrDefault(x => x.TradeId == trade.id); if (forwardTrade != null) { //远期验资,验证客户余额>= 开仓总费用 var clientBalance = clientBalances[0]; var totalOpenCommission = trade.TradePrice ?? 0; var AvailableAmount = clientBalance.AvailablePremium(); if (AvailableAmount >= totalOpenCommission || totalOpenCommission < 0) { return true; } else { errorMsg = $"当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},应付预付金:{clientBalance.PayableMargin:F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付开仓总金额:{totalOpenCommission:F3}"; return false; } } else { errorMsg = "客户远期交易数据未找到!"; return false; } } } else { errorMsg = "非期权交易,无需检查!"; return false; } } /// /// 实时计算收益互换实时持仓 /// /// /// public static intraday_trade_position RealTimeSwapCalc(trade td, YLContext db, List swapFlows) { intraday_trade_position posi = new intraday_trade_position(); var position = db.swap_position.FirstOrDefault(x => x.SwapTradeId == td.id && x.PosiDirection > 0 && x.IsInitial); if (position == null) { return null; } var swapFlowItems = swapFlows.Where(x => x.ClientId == td.ClientId && x.UnderlyingCode == position.UnderlyingCode); return posi; } public static ClientBalanceForTrsResponse GetClientBalance(int clientId) { if (_yLCache!=null) { return _yLCache.StringGet("ClientBalance:" + clientId); } return null; } } }