using BaseOUDAL; using YLErp.BLL; using YLErp.BLL.Calculation; using YLErp.Enums; using YLErp.Modules.DataProviderModule; using YLErp.QdpModule; namespace YLErp.Modules.TradeModule { /// /// 交易确认书规则服务 /// public class TradeConfirmRuleService : YLBaseService { public TradeConfirmRuleService(OptUserInfo userInfo) : base(userInfo) { } public TradeConfirmRuleService(YLBaseService baseService) : base(baseService) { } public trade_confirm_rule saveTradeConfirmRule(trade_confirm_rule req, int optId, string optName) { trade_confirm_rule tradeConfirmRule; var isAddNew = req.id == 0; if (isAddNew) { var tradeExists = DbContext.trade_confirm_rule.Where(x => x.Name == req.Name); if (tradeExists.Any()) { return null; } DbContext.trade_confirm_rule.Add(tradeConfirmRule = new trade_confirm_rule()); } else { tradeConfirmRule = DbContext.trade_confirm_rule.Find(req.id); } DbContext.Entry(tradeConfirmRule).CurrentValues.SetValues(req); tradeConfirmRule.OptId = optId; tradeConfirmRule.OptName = optName; tradeConfirmRule.OptDate = DateTime.Now; DbContext.SaveChanges(); return tradeConfirmRule; } public SearchListResult SearchTradeConfirmRuleList(trade_confirm_ruleReq req) { var query = from source in DbContext.trade_confirm_rule select source; if (!string.IsNullOrEmpty(req.Name)) { query = query.Where(x => x.Name.Contains(req.Name)); } if (!string.IsNullOrEmpty(req.TargetType)) { query = query.Where(x => x.TargetType == req.TargetType); } if (!string.IsNullOrEmpty(req.ScopeType)) { query = query.Where(x => x.ScopeType == req.ScopeType); } if (!string.IsNullOrEmpty(req.TimeType)) { query = query.Where(x => x.TimeType == req.TimeType); } if (!string.IsNullOrEmpty(req.OptName)) { query = query.Where(x => x.Name.Contains(req.OptName)); } if (string.IsNullOrEmpty(req.sidx)) { req.sidx = "id"; req.sord = "desc"; } return query.ToSearchList(req); } /// /// 交易确认时验证各交易确认规则是否满足,不满足时给出不满足的规则名 /// public string checkTradeConfirmRule(trade trade, int userId) { var trades = new List(); //结构化交易确认时,需要把未确认的子交易delta/deltacash/gamma加和一起参与判断,名义本金则按照主交易进行判断 if (trade.TradeType == "结构化交易") { trades = DbContext.trade.Where(x => x.ParentTradeId == trade.id && ConsTrade.UnConfirmTradeStatusList.Contains(x.TradeStatus)).ToList(); } else { trades.Add(trade); } var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource(); var error = string.Empty; if (DbContext.trade_confirm_rule.Any(x => x.ValidState != "InValid")) { var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades( valueDate: valuedateBLL.ValueDate, tradeList: trades, calcScenario: CalcScenarioEnum.Default, priceProvider: underlyingPrice, pricingRequest: QdpPricingRequest.BASIC_GREEKS, isUseTradeVol: PS.Config.IsTradeVol, canUseManual: true); //统计范围为交易员的验证逻辑 var traderRules = DbContext.trade_confirm_rule.Where(x => x.ValidState != "InValid" && x.ScopeType == LimitScopeTypeEnum.交易员.ToString()).ToList(); foreach (var rule in traderRules) { //名义本金按照主交易计算 var tradesOtherStockEqvNotional = DbContext.trade.Where(x => x.ValidState != "InValid" && x.TraderId == trade.TraderId && (ConsTrade.NeedMarginTradeStatusList.Contains(x.TradeStatus) || x.TradeStatus == "审批中") && x.ParentTradeId == 0); //其他指标按照子交易计算 var tradesOther = DbContext.trade.Where(x => x.ValidState != "InValid" && x.TraderId == trade.TraderId && (ConsTrade.NeedMarginTradeStatusList.Contains(x.TradeStatus) || x.TradeStatus == "审批中") && x.TradeType != "结构化交易"); if (rule.TimeType == LimitTimeTypeEnum.每交易日.ToString()) { tradesOtherStockEqvNotional = tradesOtherStockEqvNotional.Where(x => x.TradeDate == trade.TradeDate); tradesOther = tradesOther.Where(x => x.TradeDate == trade.TradeDate); } var tradeIds = tradesOther.Select(x => x.id).ToList(); var realTimeTradeRisks = DbContext.realtime_trade_risk.Where(x => tradeIds.Contains(x.TradeId ?? 0) && x.VolType == "持仓").ToList(); switch (rule.TargetType) { case "DeltaCash": var allDeltaCash = realTimeTradeRisks.Sum(x => x.DeltaCash ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.DeltaCash); if (allDeltaCash > rule.UpLimit || allDeltaCash < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.TraderName, rule.TargetType, rule.DownLimit, rule.UpLimit, allDeltaCash.ToString("F2")); } break; case "Delta": var allDelta = realTimeTradeRisks.Sum(x => x.Delta ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.Delta); if (allDelta > rule.UpLimit || allDelta < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.TraderName, rule.TargetType, rule.DownLimit, rule.UpLimit, allDelta.ToString("F2")); } break; case "Gamma": var allGamma = realTimeTradeRisks.Sum(x => x.Gamma ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.Gamma); if (allGamma > rule.UpLimit || allGamma < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.TraderName, rule.TargetType, rule.DownLimit, rule.UpLimit, allGamma.ToString("F2")); } break; case "名义本金": var allStockEqvNotional = (tradesOtherStockEqvNotional.Any() ? tradesOtherStockEqvNotional.Sum(x => x.StockEqvNotional) : 0) + trade.StockEqvNotional; if (allStockEqvNotional > rule.UpLimit || allStockEqvNotional < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.TraderName, rule.TargetType, rule.DownLimit, rule.UpLimit, allStockEqvNotional.ToString("F2")); } break; } if (!string.IsNullOrEmpty(error)) { return error; } } //统计范围为客户的验证逻辑 var clientRules = DbContext.trade_confirm_rule.Where(x => x.ValidState != "InValid" && x.ScopeType == LimitScopeTypeEnum.客户.ToString()).ToList(); foreach (var rule in clientRules) { //名义本金按照主交易计算 var tradesOtherStockEqvNotional = DbContext.trade.Where(x => x.ValidState != "InValid" && x.ClientId == trade.ClientId && (ConsTrade.NeedMarginTradeStatusList.Contains(x.TradeStatus) || x.TradeStatus == "审批中") && x.ParentTradeId == 0); //其他指标按照子交易计算 var tradesOther = DbContext.trade.Where(x => x.ValidState != "InValid" && x.ClientId == trade.ClientId && (ConsTrade.NeedMarginTradeStatusList.Contains(x.TradeStatus) || x.TradeStatus == "审批中")); if (rule.TimeType == LimitTimeTypeEnum.每交易日.ToString()) { tradesOtherStockEqvNotional = tradesOtherStockEqvNotional.Where(x => x.TradeDate == trade.TradeDate); tradesOther = tradesOther.Where(x => x.TradeDate == trade.TradeDate); } var tradeIds = tradesOther.Select(x => x.id).ToList(); var realTimeTradeRisks = DbContext.realtime_trade_risk.Where(x => tradeIds.Contains(x.TradeId ?? 0) && x.VolType == "持仓").ToList(); switch (rule.TargetType) { case "DeltaCash": var allDeltaCash = realTimeTradeRisks.Sum(x => x.DeltaCash ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.DeltaCash); if (allDeltaCash > rule.UpLimit || allDeltaCash < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.ClientName, rule.TargetType, rule.DownLimit, rule.UpLimit, allDeltaCash.ToString("F2")); } break; case "Delta": var allDelta = realTimeTradeRisks.Sum(x => x.Delta ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.Delta); if (allDelta > rule.UpLimit || allDelta < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.ClientName, rule.TargetType, rule.DownLimit, rule.UpLimit, allDelta.ToString("F2")); } break; case "Gamma": var allGamma = realTimeTradeRisks.Sum(x => x.Gamma ?? 0) + tradeRiskResult.Results.Sum(x => x.ValueResult.Gamma); if (allGamma > rule.UpLimit || allGamma < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.ClientName, rule.TargetType, rule.DownLimit, rule.UpLimit, allGamma.ToString("F2")); } break; case "名义本金": var allStockEqvNotional = (tradesOtherStockEqvNotional.Any() ? tradesOtherStockEqvNotional.Sum(x => x.StockEqvNotional) : 0) + trade.StockEqvNotional; if (allStockEqvNotional > rule.UpLimit || allStockEqvNotional < rule.DownLimit) { return string.Format(" {0}: {1}/{2}/{3}/下限{4},上限{5},实际值{6}", rule.Name, rule.TimeType, trade.ClientName, rule.TargetType, rule.DownLimit, rule.UpLimit, allStockEqvNotional.ToString("F2")); } break; } if (!string.IsNullOrEmpty(error)) { return error; } } //统计范围为单笔交易的验证逻辑 var tradeRules = DbContext.trade_confirm_rule.Where(x => x.ValidState != "InValid" && x.ScopeType == LimitScopeTypeEnum.单笔交易.ToString()).ToList(); foreach (var rule in tradeRules) { switch (rule.TargetType) { case "DeltaCash": var deltaCash = tradeRiskResult.Results.Sum(x => x.ValueResult.DeltaCash); if (deltaCash > rule.UpLimit || deltaCash < rule.DownLimit) { return string.Format(" {0}: 每笔交易/{1}/下限{2},上限{3},实际值{4}", rule.Name, rule.TargetType, rule.DownLimit, rule.UpLimit, deltaCash.ToString("F2")); } break; case "Delta": var delta = tradeRiskResult.Results.Sum(x => x.ValueResult.Delta); if (delta > rule.UpLimit || delta < rule.DownLimit) { return string.Format(" {0}: 每笔交易/{1}/下限{2},上限{3},实际值{4}", rule.Name, rule.TargetType, rule.DownLimit, rule.UpLimit, delta.ToString("F2")); } break; case "Gamma": var gamma = tradeRiskResult.Results.Sum(x => x.ValueResult.Gamma); if (gamma > rule.UpLimit || gamma < rule.DownLimit) { return string.Format(" {0}: 每笔交易/{1}/下限{2},上限{3},实际值{4}", rule.Name, rule.TargetType, rule.DownLimit, rule.UpLimit, gamma.ToString("F2")); } break; case "名义本金": var stockEqvNotional = trade.StockEqvNotional; if (stockEqvNotional > rule.UpLimit || stockEqvNotional < rule.DownLimit) { return string.Format(" {0}: 每笔交易/{1}/下限{2},上限{3},实际值{4}", rule.Name, rule.TargetType, rule.DownLimit, rule.UpLimit, stockEqvNotional.ToString("F2")); } break; case "互换价格偏离比例": var sportPrice = trade.SpotPrice??0; var valueDate = valuedateBLL.ValueDate; var basePrice = EodPriceQueryService.UnderlyingCodePrice(trade.UnderlyingCode, valueDate); var pricePercent = Math.Abs((sportPrice / basePrice) - 1); if (pricePercent < rule.DownLimit|| pricePercent > rule.UpLimit) { return string.Format(" {0}: 每笔交易/{1}/下限{2},上限{3},实际值{4}", rule.Name, rule.TargetType, rule.DownLimit, rule.UpLimit, pricePercent.ToString("F2")); } break; } if (!string.IsNullOrEmpty(error)) { return error; } } } return error; } } public class trade_confirm_ruleReq : BaseSearchReq { public int? id { get; set; } /// /// 限额名称 /// public string Name { get; set; } /// /// 限额指标 /// public string TargetType { get; set; } /// /// 统计范围 /// public string ScopeType { get; set; } /// /// 标的资产 /// public string UnderlyingIds { get; set; } /// /// 统计时间 /// public string TimeType { get; set; } /// /// 限额上限 /// public double? UpLimit { get; set; } /// /// 限额下限 /// public double? DownLimit { get; set; } /// /// 状态 /// public string ValidState { get; set; } /// /// 操作人 /// public int? OptId { get; set; } /// /// 操作人 /// public string OptName { get; set; } /// /// 操作时间 /// public DateTime? OptDate { get; set; } } }