From 5250a37d089b907c90749ddfd449ce9100b687f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=B9=E6=B5=B7?= Date: Mon, 14 Apr 2025 16:31:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E8=AE=BE=E7=BD=AE=E4=BA=92?= =?UTF-8?q?=E6=8D=A2=E5=A4=A9=E6=95=B0&=E5=88=A9=E6=81=AF=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E9=87=8D=E7=BD=AE=E9=A2=91=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YLErp.Core/DBModels/ClientPosition.cs | 2 + .../DBModels/Enums/SwapInterestRule.cs | 14 + .../YLErp.Core/DBModels/EodSwapPosition.cs | 9 +- .../YLErp.Core/DBModels/SwapFloatRate.cs | 23 + Framework/YLErp.Core/DBModels/SwapPosition.cs | 8 + .../YLErp.Core/DBModels/client_marginrate.cs | 5 + .../Model/HengTaiModel/ClientRiskCheckReq.cs | 4 + .../Model/QuotaMonitor_UnderlyingModel.cs | 1 + .../MarginModule/MarginRateSwapService.cs | 5 +- .../Modules/RiskModule/QuotaMonitorService.cs | 597 +++++++++--------- .../Modules/SwapModule/SwapDealService.cs | 105 +-- .../SwapModule/SwapEodPositionService.cs | 8 + .../SwapModule/SwapFloatRateService.cs | 27 + .../Modules/SwapModule/SwapTradeService.cs | 12 +- .../导入模板/互换预付金率导入模板.xlsx | Bin 9787 -> 9787 bytes .../导入模板/浮动利率特殊设置导入模板.xlsx | Bin 8919 -> 9264 bytes .../导入模板/浮动利率默认设置导入模板.xlsx | Bin 8875 -> 9223 bytes .../导出模板/浮动利率特殊设置导出模板.xlsx | Bin 10195 -> 10384 bytes .../导出模板/浮动利率默认设置导出模板.xlsx | Bin 10117 -> 10321 bytes YLErpWeb/Controllers/riskController.cs | 12 - .../MarginRateSwap/MarginRateSwapEdit.cshtml | 34 +- YLErpWeb/Views/SwapFloatRate/Detail.cshtml | 16 + YLErpWeb/Views/SwapFloatRate/Edit.cshtml | 25 + YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml | 16 +- YLErpWeb/Views/SwapTrade2/TradeView.cshtml | 14 +- .../app/marginRate/marginRateSwapList.js | 11 +- .../Scripts/app/swapRate/swapFloatRateEdit.js | 20 +- .../Scripts/app/swapRate/swapFloatRateList.js | 37 +- .../Scripts/app/swaptrade/swapTradeEdit.js | 21 +- 29 files changed, 637 insertions(+), 389 deletions(-) create mode 100644 Framework/YLErp.Core/DBModels/Enums/SwapInterestRule.cs diff --git a/Framework/YLErp.Core/DBModels/ClientPosition.cs b/Framework/YLErp.Core/DBModels/ClientPosition.cs index 115521c7..675358d5 100644 --- a/Framework/YLErp.Core/DBModels/ClientPosition.cs +++ b/Framework/YLErp.Core/DBModels/ClientPosition.cs @@ -114,5 +114,7 @@ namespace YLErp.DBModels /// 收支方向 1:收取:2支付 /// public int direction { get; set; } + [NotMapped] + public bool Current { get; set; } } } diff --git a/Framework/YLErp.Core/DBModels/Enums/SwapInterestRule.cs b/Framework/YLErp.Core/DBModels/Enums/SwapInterestRule.cs new file mode 100644 index 00000000..5125202f --- /dev/null +++ b/Framework/YLErp.Core/DBModels/Enums/SwapInterestRule.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace YLErp.DBModels +{ + public enum SwapInterestRule + { + 前一营业日=-1, + 当前营业日=0, + } +} diff --git a/Framework/YLErp.Core/DBModels/EodSwapPosition.cs b/Framework/YLErp.Core/DBModels/EodSwapPosition.cs index 492f3bf9..97439fe9 100644 --- a/Framework/YLErp.Core/DBModels/EodSwapPosition.cs +++ b/Framework/YLErp.Core/DBModels/EodSwapPosition.cs @@ -421,7 +421,14 @@ namespace YLErp.DBModels /// 虚拟交易费用 /// public decimal VTradingFee { get; set; } - + /// + /// 重置频率(天) + /// + public int? interest_rest_days { get; set; } + /// + /// 利率准则(-1前一营业日,0当前营业日) + /// + public int? interest_rule { get; set; } /// /// 持仓编码 /// diff --git a/Framework/YLErp.Core/DBModels/SwapFloatRate.cs b/Framework/YLErp.Core/DBModels/SwapFloatRate.cs index 9e993053..020cdcfc 100644 --- a/Framework/YLErp.Core/DBModels/SwapFloatRate.cs +++ b/Framework/YLErp.Core/DBModels/SwapFloatRate.cs @@ -96,5 +96,28 @@ namespace YLErp.DBModels [Column("base_underlying_code")] [DataChange] public string BaseUnderlyingCode { get; set; } + + /// + /// 计息方式 0:单利,1:复利 + /// + public int? interest_type { get; set; } + [NotMapped] + public string interest_type_str { get { return interest_type.HasValue ? ((InterestTypeEnum)interest_type.Value).ToString() : ""; } } + /// + /// 是否年化 + /// + public bool? is_annualized { get; set; } + [NotMapped] + public string is_annualized_str { get { return is_annualized == true ? "是" : "否"; } } + /// + /// 重置频率(天) + /// + public int? interest_rest_days { get; set; } + /// + /// 利率准则(-1前一营业日,0当前营业日) + /// + public int? interest_rule { get; set; } + [NotMapped] + public string interest_rule_str { get { return interest_rule.HasValue ? ((SwapInterestRule)interest_rule.Value).ToString() : ""; } } } } diff --git a/Framework/YLErp.Core/DBModels/SwapPosition.cs b/Framework/YLErp.Core/DBModels/SwapPosition.cs index 9eb5ae43..5ba144d3 100644 --- a/Framework/YLErp.Core/DBModels/SwapPosition.cs +++ b/Framework/YLErp.Core/DBModels/SwapPosition.cs @@ -234,6 +234,14 @@ namespace YLErp.DBModels /// public bool Invalid { get; set; } /// + /// 重置频率(天) + /// + public int? interest_rest_days { get; set; } + /// + /// 利率准则(-1前一营业日,0当前营业日) + /// + public int? interest_rule { get; set; } + /// /// 互换观察日集合 /// [NotMapped] diff --git a/Framework/YLErp.Core/DBModels/client_marginrate.cs b/Framework/YLErp.Core/DBModels/client_marginrate.cs index 8bf733b5..4a8ecdba 100644 --- a/Framework/YLErp.Core/DBModels/client_marginrate.cs +++ b/Framework/YLErp.Core/DBModels/client_marginrate.cs @@ -56,6 +56,11 @@ namespace YLErp.DBModels public decimal? LongInitMarginRate { get; set; } [DisplayName("空头初始预付金率")] public decimal? ShortInitMarginRate { get; set; } + + /// + /// 互换默认期限 + /// + public int? SwapEndDays { get; set; } public string GetDataTraceKeyInfo() { return "客户品种预付金率:" + ClientId + Type + VarietyId; diff --git a/YLErpDAL/Model/HengTaiModel/ClientRiskCheckReq.cs b/YLErpDAL/Model/HengTaiModel/ClientRiskCheckReq.cs index 2b2efe42..d6777238 100644 --- a/YLErpDAL/Model/HengTaiModel/ClientRiskCheckReq.cs +++ b/YLErpDAL/Model/HengTaiModel/ClientRiskCheckReq.cs @@ -62,5 +62,9 @@ namespace YLErp.Model.HengTaiModel /// 是否客户端 /// public bool isClient { get; set; } = false; + /// + /// 委托订单id + /// + public long orderId { get; set; } } } diff --git a/YLErpDAL/Model/QuotaMonitor_UnderlyingModel.cs b/YLErpDAL/Model/QuotaMonitor_UnderlyingModel.cs index 5ad717a0..ef399345 100644 --- a/YLErpDAL/Model/QuotaMonitor_UnderlyingModel.cs +++ b/YLErpDAL/Model/QuotaMonitor_UnderlyingModel.cs @@ -12,5 +12,6 @@ namespace YLErp.Model public double StockEqvNotional { get; set; } public int ClientId { get; set; } public int PositionType { get; set; } + public decimal Qty { get; set; } } } diff --git a/YLErpDAL/Modules/MarginModule/MarginRateSwapService.cs b/YLErpDAL/Modules/MarginModule/MarginRateSwapService.cs index 7a41ec13..f00f87cc 100644 --- a/YLErpDAL/Modules/MarginModule/MarginRateSwapService.cs +++ b/YLErpDAL/Modules/MarginModule/MarginRateSwapService.cs @@ -85,8 +85,7 @@ namespace YLErp.Modules.MarginModule InitMarginRate = reader.GetPercent("期初预付金", false) ?? 0, InitMarginRebateRate = reader.GetDecimalPercent("期初预付金利率", false) ?? 0, AddToMarginRebateRate= reader.GetDecimalPercent("追加预付金利率", false) ?? 0, - LongInitMarginRate = reader.GetDecimalPercent("多头期初预付金率", false), - ShortInitMarginRate = reader.GetDecimalPercent("空头期初预付金率", false) + SwapEndDays=reader.GetInt("互换默认期限",true) }; var client = new Client(); marginRate.Type = "普通"; @@ -133,6 +132,7 @@ namespace YLErp.Modules.MarginModule dbMarginRate.AddToMarginRebateRate= marginrate.AddToMarginRebateRate; dbMarginRate.LongInitMarginRate = marginrate.LongInitMarginRate; dbMarginRate.ShortInitMarginRate = marginrate.ShortInitMarginRate; + dbMarginRate.SwapEndDays = marginrate.SwapEndDays; dbMarginRate.OptId = UserId; dbMarginRate.OptName = UserName; dbMarginRate.OptDate = DateTime.Now; @@ -166,6 +166,7 @@ namespace YLErp.Modules.MarginModule dbMarginRate.AddToMarginRebateRate = marginrate.AddToMarginRebateRate; dbMarginRate.LongInitMarginRate = marginrate.LongInitMarginRate; dbMarginRate.ShortInitMarginRate = marginrate.ShortInitMarginRate; + dbMarginRate.SwapEndDays = marginrate.SwapEndDays; dbMarginRate.OptId = UserId; dbMarginRate.OptName = UserName; dbMarginRate.OptDate = DateTime.Now; diff --git a/YLErpDAL/Modules/RiskModule/QuotaMonitorService.cs b/YLErpDAL/Modules/RiskModule/QuotaMonitorService.cs index c0cb89a1..dbbcf203 100644 --- a/YLErpDAL/Modules/RiskModule/QuotaMonitorService.cs +++ b/YLErpDAL/Modules/RiskModule/QuotaMonitorService.cs @@ -1030,15 +1030,7 @@ namespace YLErp.Modules.RiskModule } positionList.AddRange(swapPositionList); } - var hedgeList = CalculateExchangeTrade(); - GuangFaOnExchangeHandleGammaAndTheta(hedgeList); - GetDeltaExposure(positionList, hedgeList, out var optionExposure, out var swapExposure, out var forwardeExposure, out var offExchangeExposure, out var optionNetExposure, out var offExchangeNetExposure); - swap.DeltaExposure = swapExposure; swap.DeltaNetExposure = double.NaN; - GuangFaOnExchangeHandleGammaAndTheta(hedgeList); - var riskDict = GetRiskScale(positionTradeQuery.ToList(), out var offExchangeEquity, out var offExchangeNonEquity, out var swapEquity, out var swapNonEquity, out var forwardEquity, out var forwardNonEquity); - swap.EquityRiskScale = swapEquity; - swap.NonEquityRiskScale = swapNonEquity; var checkPosiList = GetCheckPosiList(); var posiStockEqvNotional = checkPosiList.Sum(s => s.Pv); var underly = new QuotaMonitor_Global() @@ -1123,42 +1115,15 @@ namespace YLErp.Modules.RiskModule /// public List QueryClientFromCalc(QuotaMonitorReq req) { - var query = from risk in DbContext.realtime_trade_risk - join t in DbContext.trade - on risk.TradeId equals t.id - where - risk.VolType == "持仓" && - t.TradeType == "收益互换" && - t.ExerciseDate >= SystemValueDate && - ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) && - t.ValidState != "InValid" - select new - { - t.id, - t.ClientId, - StockEqvNotional = t.ParentTradeId > 0 ? 0 : t.StockEqvNotional, - t.BuySell, - TradePrice = t.TradeType == "结构化交易" ? 0 : t.TradePrice, - InitialMargin = t.TradeType == "结构化交易" ? 0 : t.InitialMargin - }; - if (req.ClientId != 0) - { - query = query.Where(O => req.ClientId == O.ClientId); - } - if (req.ClientNumber != 0) - { - query = query.Where(O => req.ClientNumber == O.ClientId); - } - if (req.TagIds != null && req.TagIds.Count > 0) - { - var tradeTagIdQuery = from tt in DbContext.trade_tag - where req.TagIds.Contains(tt.TagId) - select tt.TradeId; - query = query.Where(p => tradeTagIdQuery.Contains(p.id)); - } - var clientPositionList = query.ToList(); - var positionDict = clientPositionList.GroupBy(O => O.ClientId).ToDictionary(K => K.Key, V => V.ToList()); + using var bondDb = new BondOmsDBContext(); + var clientPositions = bondDb.client_position.Where(x => x.position_qty > 0).AsNoTracking().AsEnumerable(); + var positionDict = clientPositions.GroupBy(O => O.client_id).ToDictionary(K => K.Key, V => V.ToList()); var clientIdList = positionDict.Keys.ToList(); + List clientIds = new List(); + clientIdList.ForEach(item => + { + clientIds.Add(Convert.ToInt32(item.Value)); + }); var setValue = new Action>((obj, settings) => { var temp = settings.Where(O => O.IsValid && O.Status == QuotaSettingApprovalStatus.Valid && (O.QuotaRange == obj.ClientId || O.QuotaRange == 0)); @@ -1173,13 +1138,6 @@ namespace YLErp.Modules.RiskModule obj.Quota_StockEqvNotional_Lower = stockEqvNotionalSettings?.QuotaLowerLimit ?? double.NaN; obj.Quota_StockEqvNotional_wUpper = stockEqvNotionalSettings?.WarningUpperLimit ?? double.NaN; obj.Quota_StockEqvNotional_wLower = stockEqvNotionalSettings?.WarningLowerLimit ?? double.NaN; - - var holdingFundSettings = temp.Where(O => O.QuotaIndex == "产品占用资金限额").FirstOrDefault()?.Clone(); - holdingFundSettings?.ConvertToAbs(obj.ProductScale.GetValueOrDefault()); - obj.Quota_HoldingFund_Upper = holdingFundSettings?.QuotaUpperLimit ?? double.NaN; - obj.Quota_HoldingFund_Lower = holdingFundSettings?.QuotaLowerLimit ?? double.NaN; - obj.Quota_HoldingFund_wUpper = holdingFundSettings?.WarningUpperLimit ?? double.NaN; - obj.Quota_HoldingFund_wLower = holdingFundSettings?.WarningLowerLimit ?? double.NaN; }); var list = new List(); @@ -1194,45 +1152,8 @@ namespace YLErp.Modules.RiskModule .ToList(); var creditExposureDict = new Dictionary(); - if (req.UseCalcCreditExposure) - { - var config = valuedateBLL.SystemDate; - var tradeIds = clientPositionList.Select(O => O.id); - //去除不需要计算信用风险敞口的交易; - tradeIds = tradeIds.Except( - DbContext.TradeMeta.Where(O => - tradeIds.Contains(O.TradeId) && - O.MetaKey == ConsTradeMetaKey.ignoreRiskExposure && - O.MetaValue == "1") - .Select(O => O.TradeId).ToList()); - var tradeList = DbContext.trade.Where(O => tradeIds.Contains(O.id)).ToList(); - new TradeExtendService(UserInfo).SetTradeExtend(tradeList, true); - var ccrService = new CCRService(UserInfo); - var dict = ccrService.CalculationCCR(tradeList, config.RiskExposureJ, config.RiskExposureN); - var cashTypes = new[] { "出金", "入金" }; - var clientCash = - DbContext.ClientCashInCashOut - .Where(O => - clientIdList.Contains(O.ClientId ?? 0) && - cashTypes.Contains(O.Direction)) - .Select(O => new - { - O.ClientId, - cash = O.Money * (O.Direction == "出金" ? 1 : -1) - }) - .ToList(); - foreach (var item in positionDict) - { - var pv = (from ccr in dict - join info in item.Value - on ccr.Key equals info.id - select ccr.Value).Sum(); - // max(0,ccr + 客户总出金-客户总入金) - creditExposureDict[item.Key] = Math.Max(0, pv + (clientCash.Where(O => O.ClientId == item.Key).Sum(O => O.cash) ?? 0)); - } - } var todayClientBalance = new RealTimeClientBanlanceService(OptUserInfo.SystemUser) - .GetBanlances(clientIdList, SystemValueDate); + .GetBanlances(clientIds, SystemValueDate); foreach (var item in todayClientBalance) { var c = new QuotaMonitor_Client(); @@ -1249,15 +1170,6 @@ namespace YLErp.Modules.RiskModule var credits = creditList.Where(O => O.ClientId == item.ClientId && O.StockEqvNotional.IsNormalize()).Select(O => O.StockEqvNotional).ToArray(); c.StockEqvNotionalScale = credits.Any() ? (credits.Sum() ?? double.NaN) : double.NaN; c.AvailableStockEqvNotional = c.StockEqvNotionalScale - c.StockEqvNotional; - if (client.ClientType == ClientTypeEnum.产品.ToString()) - { - c.HoldingFund = positionDict.ContainsKey(client.id) ? positionDict[client.id].Sum(O => O.BuySell == "卖出" ? (O.TradePrice ?? 0) : (O.InitialMargin ?? 0)) : double.NaN; - if (double.TryParse(client.RegisteredCapital, out var productScale)) - { - c.ProductScale = productScale * 10000; - c.HoldingRate = c.HoldingFund / c.ProductScale; - } - } c.CreditExposure = creditExposureDict.ContainsKey(item.ClientId) ? creditExposureDict[item.ClientId] : null; list.Add(c); } @@ -1298,7 +1210,7 @@ namespace YLErp.Modules.RiskModule var result = new List(); req.sidx = "TradeNumber"; req.sord = "asc"; - var predicate = PredicateBuilder.True(); + var predicate = PredicateBuilder.True().And(t => ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) && t.ValidState != "InValid" && t.ExerciseDate >= SystemValueDate); if (!req.TradeNumber.IsNullOrWhiteSpace()) { predicate = predicate.And(O => O.TradeNumber.Contains(req.TradeNumber)); @@ -1344,28 +1256,16 @@ namespace YLErp.Modules.RiskModule var posiQuery = from t in DbContext.trade.Where(predicate) join p in DbContext.swap_position on t.id equals p.SwapTradeId where !p.IsInitial && p.PosiDirection > 0 && !p.Invalid - select p; - var query = from risk in DbContext.realtime_trade_risk - join t in DbContext.trade.Where(predicate) - on risk.TradeId equals t.id - where risk.VolType == "持仓" && t.TradeType == "收益互换" && - ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) && t.ValidState != "InValid" && - t.ExerciseDate >= SystemValueDate - select new QuotaMonitor_TradeDto() - { - trade = t, - ClientId = t.ClientId, - TradeNumber = t.TradeNumber, - ClientName = t.ClientName, - StockEqvNotional = t.StockEqvNotional, - DeltaCash = risk.DeltaCash ?? 0, - GammaCash = risk.GammaCash ?? 0, - Vega = risk.Vega ?? 0, - VegaCash = risk.VegaCash ?? 0, - PnL = (PS.Config.IsPVRounded ? risk.RoundedPositionPnl : risk.PositionPnl) ?? 0 + risk.RealizedPnl - }; + select new QuotaMonitor_TradeDto() + { + trade = t, + ClientId = t.ClientId, + TradeNumber = t.TradeNumber, + ClientName = t.ClientName, + StockEqvNotional = t.StockEqvNotional, + }; - var list = query.ToList(); + var list = posiQuery.ToList(); var setValue = new Action>((obj, settings) => { @@ -1376,41 +1276,6 @@ namespace YLErp.Modules.RiskModule obj.Quota_StockEqvNotional_Lower = stockEqvNotionalSetting?.QuotaLowerLimit ?? double.NaN; obj.Quota_StockEqvNotional_wUpper = stockEqvNotionalSetting?.WarningUpperLimit ?? double.NaN; obj.Quota_StockEqvNotional_wLower = stockEqvNotionalSetting?.WarningLowerLimit ?? double.NaN; - - var deltaCashSetting = temp.Where(O => O.QuotaIndex == "Delta金额").FirstOrDefault()?.Clone(); - deltaCashSetting?.ConvertToAbs(valuedateBLL.SystemDate.BusinessAvailableFunds ?? 0); - obj.Quota_DeltaCash_Upper = deltaCashSetting?.QuotaUpperLimit ?? double.NaN; - obj.Quota_DeltaCash_Lower = deltaCashSetting?.QuotaLowerLimit ?? double.NaN; - obj.Quota_DeltaCash_wUpper = deltaCashSetting?.WarningUpperLimit ?? double.NaN; - obj.Quota_DeltaCash_wLower = deltaCashSetting?.WarningLowerLimit ?? double.NaN; - - var gammaCashSetting = temp.Where(O => O.QuotaIndex == "Gamma金额").FirstOrDefault()?.Clone(); - gammaCashSetting?.ConvertToAbs(valuedateBLL.SystemDate.BusinessAvailableFunds ?? 0); - obj.Quota_GammaCash_Upper = gammaCashSetting?.QuotaUpperLimit ?? double.NaN; - obj.Quota_GammaCash_Lower = gammaCashSetting?.QuotaLowerLimit ?? double.NaN; - obj.Quota_GammaCash_wUpper = gammaCashSetting?.WarningUpperLimit ?? double.NaN; - obj.Quota_GammaCash_wLower = gammaCashSetting?.WarningLowerLimit ?? double.NaN; - - var vegaSetting = temp.Where(O => O.QuotaIndex == "Vega").FirstOrDefault()?.Clone(); - vegaSetting?.ConvertToAbs(valuedateBLL.SystemDate.BusinessAvailableFunds ?? 0); - obj.Quota_Vega_Upper = vegaSetting?.QuotaUpperLimit ?? double.NaN; - obj.Quota_Vega_Lower = vegaSetting?.QuotaLowerLimit ?? double.NaN; - obj.Quota_Vega_wUpper = vegaSetting?.WarningUpperLimit ?? double.NaN; - obj.Quota_Vega_wLower = vegaSetting?.WarningLowerLimit ?? double.NaN; - - var vegaCashSetting = temp.Where(O => O.QuotaIndex == "Vega金额").FirstOrDefault()?.Clone(); - vegaCashSetting?.ConvertToAbs(valuedateBLL.SystemDate.BusinessAvailableFunds ?? 0); - obj.Quota_VegaCash_Upper = vegaCashSetting?.QuotaUpperLimit ?? double.NaN; - obj.Quota_VegaCash_Lower = vegaCashSetting?.QuotaLowerLimit ?? double.NaN; - obj.Quota_VegaCash_wUpper = vegaCashSetting?.WarningUpperLimit ?? double.NaN; - obj.Quota_VegaCash_wLower = vegaCashSetting?.WarningLowerLimit ?? double.NaN; - - var lossSetting = temp.Where(O => O.QuotaIndex == "止损金额").FirstOrDefault()?.Clone(); - obj.Quota_Loss_Upper = lossSetting?.QuotaUpperLimit ?? double.NaN; - obj.Quota_Loss_Lower = lossSetting?.QuotaLowerLimit ?? double.NaN; - obj.Quota_Loss_wUpper = lossSetting?.WarningUpperLimit ?? double.NaN; - obj.Quota_Loss_wLower = lossSetting?.WarningLowerLimit ?? double.NaN; - var swapPercentSetting = temp.Where(O => O.QuotaIndex == "互换价格偏离比例").FirstOrDefault()?.Clone(); obj.Quota_SwapPercent_Upper = swapPercentSetting?.QuotaUpperLimit ?? double.NaN; obj.Quota_SwapPercent_Lower = swapPercentSetting?.QuotaLowerLimit ?? double.NaN; @@ -1424,17 +1289,12 @@ namespace YLErp.Modules.RiskModule foreach (var item in list) { setValue(item, setting); - if (item.trade.TradeType == "收益互换") - { - var sportPrice = item.trade.SpotPrice ?? 0; - var bondPrice = EodPriceQueryService.GetBondPrice(valuedateBLL.ValueDate, item.trade.UnderlyingCode); - var basePrice = bondPrice == null ? 0 : bondPrice.ClosePrice; - var vobp = bondPrice == null ? 0 : Convert.ToDouble(bondPrice.Vobp); - var pricePercent = basePrice == 0 ? 0 : Math.Abs((sportPrice / basePrice) - 1); - item.Quota_SwapPercent = pricePercent; - var stockEqvNotional = posiQuery.Where(s => s.SwapTradeId == item.trade.id).Sum(s => s.PosiNotionalValue); - item.StockEqvNotional = Convert.ToDouble(stockEqvNotional); - } + var sportPrice = item.trade.SpotPrice ?? 0; + var bondPrice = EodPriceQueryService.GetBondPrice(valuedateBLL.ValueDate, item.trade.UnderlyingCode); + var basePrice = bondPrice == null ? 0 : bondPrice.ClosePrice; + var vobp = bondPrice == null ? 0 : Convert.ToDouble(bondPrice.Vobp); + var pricePercent = basePrice == 0 ? 0 : Math.Abs((sportPrice / basePrice) - 1); + item.Quota_SwapPercent = pricePercent; var obj = new QuotaMonitor_Trade(); ObjectHelper.MapValues(obj, item); result.Add(obj); @@ -1448,7 +1308,7 @@ namespace YLErp.Modules.RiskModule Vega = result.Sum(O => O.Vega), VegaCash = result.Sum(O => O.VegaCash), Quota_CCR = result.Sum(O => O.Quota_CCR), - PnL = result.Sum(O => O.PnL) + PnL = result.Sum(O => O.PnL), }; result.Add(total); @@ -2032,23 +1892,19 @@ namespace YLErp.Modules.RiskModule var result = new List(); using var bondDb = new BondOmsDBContext(); var clientPositions = bondDb.client_position.AsNoTracking().AsEnumerable(); - var query = from p in DbContext.swap_position - join t in DbContext.trade - on p.SwapTradeId equals t.id - where - t.TradeType == "收益互换" && - t.ExerciseDate >= SystemValueDate && - ConsTrade.PositionTradeStatusList.Contains(t.TradeStatus) && - t.ValidState != "InValid" && - !p.IsInitial && p.PositionType > 0 - select new QuotaMonitor_UnderlyingModel - { - UnderlyingCode = p.UnderlyingCode, - StockEqvNotional = t.StockEqvNotional, - ClientId = t.ClientId, - PositionType = p.PositionType - }; - var queryGroup = query.ToList().GroupBy(g => g.UnderlyingCode).ToList(); + List underlyingModels = new List(); + foreach (var item in clientPositions) + { + var model = new QuotaMonitor_UnderlyingModel() + { + UnderlyingCode = item.security_id, + StockEqvNotional = Convert.ToDouble(item.position_notional_principal ?? 0), + PositionType = item.side + 1, + Qty = item.position_qty ?? 0, + }; + underlyingModels.Add(model); + } + var queryGroup = underlyingModels.GroupBy(g => g.UnderlyingCode).ToList(); var qutoList = new List(); foreach (var item in queryGroup) { @@ -3565,6 +3421,9 @@ namespace YLErp.Modules.RiskModule if (O.QuotaIndex.Contains("名义本金")) { O.QuotaLowerLimit *= ConsGlobal.quotaMonitorMultiple; + O.QuotaUpperLimit *= ConsGlobal.quotaMonitorMultiple; + O.WarningLowerLimit *= ConsGlobal.quotaMonitorMultiple; + O.WarningUpperLimit *= ConsGlobal.quotaMonitorMultiple; } O.QuotaLowerLimit = O.QuotaLowerLimit.FormatValue(count); O.QuotaUpperLimit = O.QuotaUpperLimit.FormatValue(count); @@ -4275,98 +4134,27 @@ namespace YLErp.Modules.RiskModule { return clientRiskCheckResps; } - var clientPrecheckQuotaSettingList = precheckQuotaSettingList.Where(x => x.QuotaRange == clientRiskCheckReq.clientId && x.QuotaType == QuotaTypeEnum.CLIENT && x.QuotaIndex == "名义本金").ToList(); - var allClientPrecheckQuotaSettingList = precheckQuotaSettingList.Where(x => x.QuotaRange == 0 && x.QuotaType == QuotaTypeEnum.CLIENT && x.QuotaIndex == "名义本金").ToList(); - if (clientPrecheckQuotaSettingList.Count > 0) - { - foreach (var item in allClientPrecheckQuotaSettingList) - { - precheckQuotaSettingList.Remove(item); - } - } var client = DataCacheProvider.GetClientDataSource().GetData(clientRiskCheckReq.clientId); if (client == null) { throw new ServiceException("未找到客户信息"); } using var bondDb = new BondOmsDBContext(); - var clientPositions = bondDb.client_position.AsNoTracking().ToList();//所有持仓 - ClientPosition posi = new ClientPosition(); - posi.commission = clientRiskCheckReq.commission; - posi.side = clientRiskCheckReq.side; - posi.security_id = clientRiskCheckReq.securityId; - posi.full_price_now = clientRiskCheckReq.price * ConsGlobal.bondShowPriceMultiple; - posi.deal_full_price_avg = clientRiskCheckReq.price * ConsGlobal.bondShowPriceMultiple; - posi.client_id = clientRiskCheckReq.clientId; - posi.position_qty = clientRiskCheckReq.qty / 10000; - posi.position_notional_principal = clientRiskCheckReq.qty; - posi.direction = (int)SwapDirectionEnum.支付; - clientPositions.Add(posi); - var umCodes = clientPositions.Select(s => s.security_id).Distinct().ToList(); - umCodes.Add(clientRiskCheckReq.securityId); - umCodes = umCodes.Distinct().ToList(); - var ums = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().Where(x => umCodes.Contains(x.UnderlyingCode)); - List checkPoisiList = new List(); - foreach (var item in clientPositions) - { - var dealDate = DateTime.Parse(clientRiskCheckReq.dealDate); - double lastPrice = 0; - var um = ums.FirstOrDefault(x => x.UnderlyingCode == item.security_id); - CheckQuotaMoitorModel checkQuotaMoitorModel = new CheckQuotaMoitorModel(); - checkQuotaMoitorModel.Qty = (item.position_qty ?? 0) * 10000; ; - checkQuotaMoitorModel.id = item.id; - checkQuotaMoitorModel.Price = (item.deal_full_price_avg ?? 0); - checkQuotaMoitorModel.NowPrice = (item.full_price_now ?? 0); - checkQuotaMoitorModel.ContractSize = um == null ? 1 : Convert.ToDecimal(um.ContractSize); - checkQuotaMoitorModel.Pv = item.position_notional_principal ?? 0; - checkQuotaMoitorModel.Direction = item.direction; - if (item.id == 0) - { - checkQuotaMoitorModel.Pv = checkQuotaMoitorModel.Qty * checkQuotaMoitorModel.ContractSize; - if (client.SwapTradeType == 1) - { - checkQuotaMoitorModel.Pv *= checkQuotaMoitorModel.Price; - } - } - checkQuotaMoitorModel.UnderlyingCode = item.security_id; - checkQuotaMoitorModel.Side = item.side; - checkQuotaMoitorModel.Commision = item.commission ?? 0; - checkQuotaMoitorModel.ClientId = Convert.ToInt32(item.client_id ?? 0); - checkQuotaMoitorModel.Delta = (checkQuotaMoitorModel.Side == 0 ? checkQuotaMoitorModel.Price : -checkQuotaMoitorModel.Price) * checkQuotaMoitorModel.Qty; - if (um != null) - { - checkQuotaMoitorModel.UnderlyingId = um.id; - if (!um.IsBond()) - { - checkQuotaMoitorModel.Pv = checkQuotaMoitorModel.Pv * checkQuotaMoitorModel.Price; - lastPrice = DataCacheProvider.GetUnderlyingDataSource().GetPrice(item.security_id); - } - else - { - checkQuotaMoitorModel.Price *= ConsGlobal.bondPriceMultiple; - checkQuotaMoitorModel.NowPrice *= ConsGlobal.bondPriceMultiple; - var bondPrice = EodPriceQueryService.GetBondPrice(dealDate, item.security_id); - lastPrice = bondPrice != null ? bondPrice.ClosePrice : (um.Price ?? 0) * Convert.ToDouble(ConsGlobal.bondPriceMultiple); - var bond = JsonHelper.Deserialize(um.ExJson); - checkQuotaMoitorModel.Circulation = (bond.IssueSize * 100000000m) ?? 0; - } - } - var ratio = checkQuotaMoitorModel.Side == 0 ? 1 : -1; - var directionRatio = checkQuotaMoitorModel.Direction == (int)SwapDirectionEnum.收取 ? 1 : -1; - checkQuotaMoitorModel.LastPrice = Convert.ToDecimal(lastPrice); - checkQuotaMoitorModel.Pnl = (checkQuotaMoitorModel.NowPrice - checkQuotaMoitorModel.Price) * checkQuotaMoitorModel.Qty; - checkQuotaMoitorModel.Current = checkQuotaMoitorModel.id == 0; - checkPoisiList.Add(checkQuotaMoitorModel); - } + var (clientPositions, clientOrderPositions) = GetClientPositionsAndOrders(bondDb, clientRiskCheckReq.orderId); + var position = clientPositions + .FirstOrDefault(x => x.security_id == clientRiskCheckReq.securityId && x.client_id == clientRiskCheckReq.clientId); + precheckQuotaSettingList = FilterPrecheckQuotaSettings(precheckQuotaSettingList, clientRiskCheckReq); + + AddClientOrderPositions(clientOrderPositions, clientPositions); + AddClientRiskCheckPosition(clientRiskCheckReq, clientPositions); + var umCodes = GetUnderlyingCodes(clientPositions, clientRiskCheckReq.securityId); + var ums = GetUnderlyings(umCodes); + var dealDate = DateTime.Parse(clientRiskCheckReq.dealDate); + var checkPoisiList = BuildCheckQuotaMoitorModels(clientPositions, ums, dealDate); foreach (var settingItem in precheckQuotaSettingList) { - ClientRiskCheckItem clientRiskCheckItem = new ClientRiskCheckItem(); - clientRiskCheckItem.quotaType = settingItem.QuotaIndex; - clientRiskCheckItem.quotaLowerLimit = settingItem.QuotaLowerLimit; - clientRiskCheckItem.quotaUpperLimit = settingItem.QuotaUpperLimit; - clientRiskCheckItem.warningUpperLimit = settingItem.WarningUpperLimit; - clientRiskCheckItem.warningLowerLimit = settingItem.WarningLowerLimit; - clientRiskCheckItem.isPercent = settingItem.Percent; + var clientRiskCheckItem = CreateClientRiskCheckItem(settingItem); + if (clientRiskCheckItem == null) continue; if (!settingItem.QuotaLowerLimit.HasValue && !settingItem.QuotaUpperLimit.HasValue && !settingItem.WarningUpperLimit.HasValue && !settingItem.WarningLowerLimit.HasValue) { continue; @@ -4380,7 +4168,186 @@ namespace YLErp.Modules.RiskModule } return clientRiskCheckResps; } + /// + /// 获取持仓标的 + /// + /// + /// + /// + private List GetUnderlyingCodes(List clientPositions, string securityId) + { + var umCodes = clientPositions.Select(s => s.security_id).Distinct().ToList(); + umCodes.Add(securityId); + return umCodes.Distinct().ToList(); + } + /// + /// 获取标的信息 + /// + /// + /// + private List GetUnderlyings(List umCodes) + { + return DataCacheProvider.GetUnderlyingDataSource().AsQueryable() + .Where(x => umCodes.Contains(x.UnderlyingCode)) + .ToList(); + } + private (List, List) GetClientPositionsAndOrders(BondOmsDBContext bondDb, long orderId) + { + var clientLongIds = DataCacheProvider.GetClientDataSource() + .AsQueryable() + .Where(s => s.BusinessUseType == "否") + .Select(s => (long)s.id) + .ToList(); + var clientPositions = bondDb.client_position.Where(x => clientLongIds.Contains(x.client_id ?? 0)).AsNoTracking().ToList(); + var startDate = DateTime.Now.Date; + var nextDate = startDate.AddDays(1); + var clientOrderPositions = bondDb.client_order.Where(x => x.status == 0 && x.create_time > startDate && x.create_time < nextDate && x.id != orderId).AsNoTracking().ToList(); + return (clientPositions, clientOrderPositions); + } + /// + /// 过滤风控检查项 + /// + /// + /// + /// + /// + private List FilterPrecheckQuotaSettings(List precheckQuotaSettingList, ClientRiskCheckItemParam clientRiskCheckReq) + { + // 过滤出与当前客户端相关的配额设置 + var clientPrecheckQuotaSettingList = precheckQuotaSettingList + .Where(x => x.QuotaRange == clientRiskCheckReq.clientId && x.QuotaType == QuotaTypeEnum.CLIENT) + .ToList(); + // 过滤出所有客户端通用的配额设置 + var allClientPrecheckQuotaSettingList = precheckQuotaSettingList + .Where(x => x.QuotaRange == 0 && x.QuotaType == QuotaTypeEnum.CLIENT) + .ToList(); + + // 获取底层数据源 + var um = DataCacheProvider.GetUnderlyingDataSource().GetData(clientRiskCheckReq.securityId); + var noneClientAllUnderlyingPrecheckQuotaSettingList = precheckQuotaSettingList + .Where(x => x.QuotaType == QuotaTypeEnum.UNDERLYING) + .ToList(); + // 处理客户端相关的配额设置 + if (clientPrecheckQuotaSettingList.Count > 0) + { + precheckQuotaSettingList = precheckQuotaSettingList + .Except(allClientPrecheckQuotaSettingList) + .ToList(); + } + return precheckQuotaSettingList; + } + /// + /// 构建风控指标类 + /// + /// + /// + private ClientRiskCheckItem CreateClientRiskCheckItem(QuotaSetting settingItem) + { + if (!settingItem.QuotaLowerLimit.HasValue && !settingItem.QuotaUpperLimit.HasValue && + !settingItem.WarningUpperLimit.HasValue && !settingItem.WarningLowerLimit.HasValue) + { + return null; + } + + return new ClientRiskCheckItem + { + quotaType = settingItem.QuotaIndex, + quotaLowerLimit = settingItem.QuotaLowerLimit, + quotaUpperLimit = settingItem.QuotaUpperLimit, + warningUpperLimit = settingItem.WarningUpperLimit, + warningLowerLimit = settingItem.WarningLowerLimit, + isPercent = settingItem.Percent + }; + } + /// + /// 将client_order构建 clientPosition + /// + /// + /// + private void AddClientOrderPositions(List clientOrderPositions, List clientPositions) + { + foreach (var item in clientOrderPositions) + { + var posi = new ClientPosition + { + commission = item.commission, + side = item.side ?? 0, + security_id = item.security_id, + full_price_now = item.full_price, + deal_full_price_avg = item.full_price ?? 0, + client_id = item.client_id, + position_qty = item.order_qty, + position_notional_principal = item.full_price * item.order_qty* ConsGlobal.bondPriceMultiple, + direction = (int)SwapDirectionEnum.支付, + id = item.id, + Current = false, + }; + clientPositions.Add(posi); + } + } + /// + /// 将下单风控校构建clientPosition + /// + /// + /// + private void AddClientRiskCheckPosition(ClientRiskCheckItemParam clientRiskCheckReq, List clientPositions) + { + var posi = new ClientPosition + { + commission = clientRiskCheckReq.commission, + side = clientRiskCheckReq.side, + security_id = clientRiskCheckReq.securityId, + full_price_now = clientRiskCheckReq.price* ConsGlobal.bondShowPriceMultiple, + deal_full_price_avg = clientRiskCheckReq.price * ConsGlobal.bondShowPriceMultiple, + client_id = clientRiskCheckReq.clientId, + position_qty = clientRiskCheckReq.qty, + position_notional_principal = clientRiskCheckReq.amount, + direction = (int)SwapDirectionEnum.支付, + id = clientRiskCheckReq.orderId, + Current = true, + }; + clientPositions.Add(posi); + } + /// + /// 给客户持仓标的信息赋值现价,构建风控校验类 + /// + /// + /// + /// + private List BuildCheckQuotaMoitorModels(List clientPositions, List ums,DateTime dealDate) + { + return clientPositions.Select(item => + { + var um = ums.FirstOrDefault(x => x.UnderlyingCode == item.security_id); + var bondPrice = EodPriceQueryService.GetBondPrice(dealDate, item.security_id); + double lastPrice = bondPrice != null ? bondPrice.ClosePrice : (um.Price ?? 0) * Convert.ToDouble(ConsGlobal.bondPriceMultiple); + var bond = new UnderlyingBond(); + if (um.IsBond()&&string.IsNullOrEmpty(um.ExJson)) { + bond = JsonHelper.Deserialize(um.ExJson); + } + return new CheckQuotaMoitorModel + { + Qty = item.position_qty ?? 0, + id = item.id, + Price = (item.deal_full_price_avg ?? 0) * ConsGlobal.bondPriceMultiple, + NowPrice = (item.full_price_now ?? 0) * ConsGlobal.bondPriceMultiple, + ContractSize = (decimal)(um?.ContractSize ?? 1), + Pv = item.position_notional_principal ?? 0, + Direction = item.direction, + UnderlyingCode = item.security_id, + Side = item.side, + Commision = item.commission ?? 0, + ClientId = Convert.ToInt32(item.client_id ?? 0), + Delta = (decimal)((item.side == 0 ? item.deal_full_price_avg : -item.deal_full_price_avg) * (item.position_qty ?? 0) * ConsGlobal.bondPriceMultiple), + UnderlyingId = um?.id ?? 0, + LastPrice = (decimal)lastPrice, + Circulation = (bond.IssueSize * 100000000m) ?? 0, + Pnl = (decimal)((item.full_price_now - item.deal_full_price_avg) * (item.position_qty ?? 0) * ConsGlobal.bondPriceMultiple), + Current = item.Current, + }; + }).ToList(); + } /// /// 获取实时持仓数据构建限额查询数据 /// @@ -5125,9 +5092,9 @@ namespace YLErp.Modules.RiskModule switch (checkItem.quotaType) { case "名义本金": - var clientPv = positionList.Where(s => s.ClientId == current.ClientId && s.UnderlyingCode == current.UnderlyingCode).Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); - var otherPv = positionList.Where(s => s.ClientId != current.ClientId || s.UnderlyingCode != current.UnderlyingCode).Sum(s => s.Pv); - currentValue = Convert.ToDouble(otherPv + Math.Abs(clientPv)); + var _posiList = DataHelper.DeepCopyObject(positionList); + var clientPv = CalcPv(_posiList, false, false); + currentValue = Convert.ToDouble(clientPv); var posiPv = positionList.Where(s => !s.Current).Sum(s => s.Pv); posiVal = Convert.ToDouble(posiPv); if (!ValidateQuoteResult(checkItem, currentValue, posiVal)) @@ -5135,9 +5102,6 @@ namespace YLErp.Modules.RiskModule return checkItem; } return null; - case "Delta金额": - currentValue = Convert.ToDouble(positionList.Sum(O => O.Delta)); - break; case "浮动盈亏": currentValue = Convert.ToDouble(positionList.Sum(O => O.Pnl)); break; @@ -5242,22 +5206,6 @@ namespace YLErp.Modules.RiskModule return checkItem; } return null; - case "止损金额": - currentValue = Convert.ToDouble(current.Pnl); - checkItem.currentValue = Math.Round(currentValue ?? 0, 2); - if (!ValidateQuoteResult(checkItem)) - { - return checkItem; - } - return null; - case "Delta金额": - currentValue = Convert.ToDouble(current.Delta); - - if (!ValidateQuoteResult(checkItem)) - { - return checkItem; - } - return null; case "互换价格偏离比例": var sportPrice = Convert.ToDouble(current.Price); var basePrice = Convert.ToDouble(current.LastPrice); @@ -5381,16 +5329,16 @@ namespace YLErp.Modules.RiskModule { return null; } - currentPv = positionList.Where(s => s.UnderlyingCode == current.UnderlyingCode).Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); - currentValue = Convert.ToDouble(currentPv); - currentValue = Math.Abs(currentValue ?? 0); - posiPv = positionList.Where(s => s.UnderlyingCode == current.UnderlyingCode && !s.Current).Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); - posiVal = Convert.ToDouble(posiPv); + positionList = positionList.Where(s => s.UnderlyingCode == current.UnderlyingCode).ToList(); + var _posiList = DataHelper.DeepCopyObject(positionList); + var posiResult = CalcPv(_posiList, false, true); + currentPv = _posiList.Where(s => s.UnderlyingCode == current.UnderlyingCode).Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); + posiPv = _posiList.Where(s => s.UnderlyingCode == current.UnderlyingCode && !s.Current).Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); + posiVal = Math.Abs(Convert.ToDouble(posiPv)); var tag = $"{tag_prefix}({checkItem.quotaType})"; switch (checkItem.quotaType) { case "轧差名义本金": - posiVal = Convert.ToDouble(posiPv); if (!ValidateQuoteResult(checkItem, currentValue, posiVal)) { return checkItem; @@ -5398,7 +5346,7 @@ namespace YLErp.Modules.RiskModule return null; case "轧差集中度": currentValue = current.Circulation == 0 ? 0 : currentValue / Convert.ToDouble(current.Circulation); - posiPv = positionList.Where(s => s.UnderlyingCode == current.UnderlyingCode && !s.Current).Sum(s => s.Pv); + posiPv = _posiList.Where(s => s.UnderlyingCode == current.UnderlyingCode && !s.Current).Sum(s => s.Pv); posiVal = current.Circulation == 0 ? 0 : Convert.ToDouble(posiPv / current.Circulation); if (!ValidateQuoteResult(checkItem, currentValue, posiVal)) { @@ -5514,6 +5462,63 @@ namespace YLErp.Modules.RiskModule return null; } } + + /// + /// 计算client名义本金,最新持仓市值,返回(名义本金,持仓市值) + /// + /// + /// + /// 是否单客户户 + /// 是否轧差 + /// + private decimal CalcPv(List positionList, bool isclient, bool roll) + { + decimal clientPv = 0; + CheckQuotaMoitorModel current = positionList.FirstOrDefault(s => s.Current); + if (current == null) + { + return 0; + } + var clientUnderlyList = positionList.Where(s => s.ClientId == current.ClientId && s.UnderlyingCode == current.UnderlyingCode && s.Side != current.Side).ToList(); + foreach (var item in clientUnderlyList) + { + if (item.Qty == 0) + { + continue; + } + if (item.Qty >= current.Qty) + { + item.Qty -= current.Qty; + item.Pv = item.Qty * item.Price; + current.Qty = 0; + current.Pv = 0; + } + else if (item.Qty < current.Qty) + { + current.Qty -= item.Qty; + current.Pv = current.Qty * current.Price; + item.Qty = 0; + item.Pv = 0; + CalcPv(positionList, isclient, roll); + } + } + if (isclient) + { + clientPv = positionList.Where(s => s.ClientId == current.ClientId).Sum(s => s.Pv); + } + else + { + if (roll) + { + clientPv = positionList.Sum(s => s.Pv * (s.Side == 0 ? 1 : -1)); + } + else + { + clientPv = positionList.Sum(s => s.Pv); + } + } + return clientPv; + } private List checkStockPercent(IEnumerable> positionList, Dictionary stockEqvNotionalDict, string tag_prefix, QuotaSetting[] settings, bool warning) { if (string.IsNullOrEmpty(tag_prefix)) diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 6055432a..f0d9010b 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -400,8 +400,8 @@ namespace YLErp.Modules.SwapModule } else if (position.InterestMode == (int)InterestModeEnum.标的期初全价) { - _closePosiNotionalValue = _posiNotionalValue * grossPrice * closePrecent; - _posiNotionalValue = _posiNotionalValue * grossPrice; + _closePosiNotionalValue = _posiNotionalValue * closePrecent; + _posiNotionalValue = _posiNotionalValue; } else if (position.InterestMode == (int)InterestModeEnum.追加预付金 || position.InterestMode == (int)InterestModeEnum.初始预付金) { @@ -409,24 +409,36 @@ namespace YLErp.Modules.SwapModule _posiNotionalValue = position.InterestPrincipalFix * closePrecent; positionClone.InterestDirection = position.InterestDirection == (int)SwapDirectionEnum.收取 ? (int)SwapDirectionEnum.支付 : (int)SwapDirectionEnum.收取; } + var calendar = "chn"; if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var rateDate = td.StartDate.Value.AddDays(-1); - if (EodPriceQueryService.TryGetPrice(rateDate, position.FloatRateUnderlyingCode, out double floatRate)) + // 获取重置频率,如果为空则默认为1 + int interestPeriod = position.interest_rest_days ?? 1; + + // 计算从 td.StartDate 到 endDate 的天数 + var days = (endDate - td.StartDate.Value).Days; + // 获取合适的 rateDate + DateTime rateDate = GetRateDate(position.interest_rule, td.StartDate.Value, endDate, days, interestPeriod, calendar); + + // 如果不需要重置,并且上一日已有 FloatRate,则不再查找 + if (preEodPosition.id != 0 && days % interestPeriod != 0) { - position.FloatRate = Convert.ToDecimal(floatRate); - positionClone.FloatRate = position.FloatRate; - if (preEodPosition.id == 0) + position.FloatRate = preEodPosition.FloatRate; + positionClone.FloatRate = preEodPosition.FloatRate; + } + else + { + // 如果没有 preEodPosition 数据或需要查找新 Rate,则去查询最新的浮动利率 + if (EodPriceQueryService.TryGetPrice(rateDate, position.FloatRateUnderlyingCode, out double floatRate)) { - preEodPosition.FloatRate = positionClone.FloatRate; - preEodPosition.TdInterestPrincipal = _posiNotionalValue; + position.FloatRate = Convert.ToDecimal(floatRate); + positionClone.FloatRate = position.FloatRate; + } + else if (needPrice) + { + throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{rateDate:yyyy年MM月dd日}的价格"); } } - else if (needPrice) - { - throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{rateDate:yyyy年MM月dd日}的价格"); - } - } decimal rate = position.InterestRateDefault; if (swapIntervalToday == null)//当日无适用观察日 @@ -453,6 +465,20 @@ namespace YLErp.Modules.SwapModule return interests; } /// + /// 根据给定条件获取 rateDate + /// + private DateTime GetRateDate(int? interest_rule, DateTime startDate, DateTime endDate, int days, int interestPeriod, string calendar) + { + // 判断是否达到重置周期 + if (days % interestPeriod == 0) + { + return QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(interest_rule ?? 0), calendar); + } + + // 如果不在重置周期内,使用 td.StartDate 来获取 rateDate + return QdpCalendarHelper.GetNonHolidayDefore(startDate.AddDays(interest_rule ?? 0), calendar); + } + /// /// 初始化利息腿信息 /// /// 交易编码 @@ -591,7 +617,7 @@ namespace YLErp.Modules.SwapModule var TdInterestPrincipal = preEodPosition.TdInterestPrincipal; decimal interest = 0; decimal tdinterest = 0; - int interestPeriod = 7; + int interestPeriod = position.interest_rest_days ?? 1; decimal dynomicPrincipal = principal; decimal tdDynomicPrincipal = posiPrincipal; var calcDays = (endDate - tradeDate).Days; @@ -605,14 +631,9 @@ namespace YLErp.Modules.SwapModule { dynomicPrincipal = dynomicPrincipal + interest; tdDynomicPrincipal = tdDynomicPrincipal + interest; - //if (rateDate > tradeDate) - //{ - // dynomicPrincipal += interestProfitSum; - // tdDynomicPrincipal += interestProfitSum; - //} if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var fr007RateDate = rateDate.AddDays(-1); + var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(position.interest_rule ?? 0)); // 获取前一工作日; if (EodPriceQueryService.TryGetPrice(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1)) { if (floatRate1 != 0) @@ -675,7 +696,7 @@ namespace YLErp.Modules.SwapModule decimal interestProfitSum = preEodPosition.InterestProfitSum; decimal interest = preEodPosition.TdInterestIncome; decimal tdinterest = preEodPosition.TdInterestIncome; - int interestPeriod = 7; + int interestPeriod = position.interest_rest_days ?? 1; decimal tdDynomicPrincipal = posiPrincipal; double floatRate = Convert.ToDouble(floateRate); var days = (endDate - tradeDate).Days; @@ -684,7 +705,8 @@ namespace YLErp.Modules.SwapModule tdDynomicPrincipal = tdDynomicPrincipal + interestProfitSum; if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var fr007RateDate = endDate.AddDays(-1); + // 获取合适的 rateDate + var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(position.interest_rule ?? 0)); // 获取前一工作日; if (EodPriceQueryService.TryGetPrice(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1)) { if (floatRate1 != 0) @@ -696,32 +718,29 @@ namespace YLErp.Modules.SwapModule { throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格"); } - flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent; - interest = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); - tdinterest = tdDynomicPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); - if (position.IsAnnualized) - { - interest /= annualDays; - tdinterest /= annualDays; - } + } - else + flowEvent.InterestPrincipal = tdDynomicPrincipal * closePercent; + interest = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); + tdinterest = tdDynomicPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); + if (position.IsAnnualized) { - flowEvent.InterestPrincipal = (preEodPosition.TdInterestPrincipal + tdDynomicPrincipal - orginPv) * closePercent; - var interest1 = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); - var tdinterest1 = (preEodPosition.TdInterestPrincipal + tdDynomicPrincipal - orginPv) * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); - if (position.IsAnnualized) - { - interest1 /= annualDays; - tdinterest1 /= annualDays; - } - interest = interest1; - tdinterest = tdinterest1; + interest /= annualDays; + tdinterest /= annualDays; } } else { - flowEvent.InterestPrincipal = preEodPosition.TdInterestPrincipal * closePercent; + flowEvent.InterestPrincipal = (preEodPosition.TdInterestPrincipal + tdDynomicPrincipal - orginPv) * closePercent; + var interest1 = flowEvent.InterestPrincipal * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); + var tdinterest1 = (preEodPosition.TdInterestPrincipal + tdDynomicPrincipal - orginPv) * (flowEvent.InterestRate + Convert.ToDecimal(floatRate)); + if (position.IsAnnualized) + { + interest1 /= annualDays; + tdinterest1 /= annualDays; + } + interest = interest1; + tdinterest = tdinterest1; } flowEvent.FloatRate = Convert.ToDecimal(floatRate); InterestAmount = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 0a6d5906..4068e2fc 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -635,6 +635,8 @@ namespace YLErp.Modules.SwapModule newEodPayPosition.HappenDate = position.HappenDate; newEodPayPosition.Currency = position.Currency; newEodPayPosition.InterestType = position.InterestType; + newEodPayPosition.interest_rest_days = position.interest_rest_days; + newEodPayPosition.interest_rule = position.interest_rule; newEodPayPosition.FloatRate = flowEvents.FirstOrDefault()?.FloatRate ?? 0; newEodPayPosition.FloatRateUnderlyingCode = position.FloatRateUnderlyingCode; newEodPayPosition.InterestFeePending = 0; @@ -733,6 +735,8 @@ namespace YLErp.Modules.SwapModule newEodPayPosition.HappenDate = position.HappenDate; newEodPayPosition.Currency = position.Currency; newEodPayPosition.InterestType = position.InterestType; + newEodPayPosition.interest_rest_days = position.interest_rest_days; + newEodPayPosition.interest_rule = position.interest_rule; newEodPayPosition.FloatRate = interests.Count > 0 ? interests.First().FloatRate ?? 0 : 0; newEodPayPosition.FloatRateUnderlyingCode = position.FloatRateUnderlyingCode; newEodPayPosition.InterestFeePending = 0; @@ -838,6 +842,8 @@ namespace YLErp.Modules.SwapModule newEodPayPosition.HappenDate = position.HappenDate; newEodPayPosition.Currency = position.Currency; newEodPayPosition.InterestType = position.InterestType; + newEodPayPosition.interest_rest_days = position.interest_rest_days; + newEodPayPosition.interest_rule = position.interest_rule; newEodPayPosition.FloatRate = interests.Count > 0 ? interests.First().FloatRate ?? 0 : 0; newEodPayPosition.FloatRateUnderlyingCode = position.FloatRateUnderlyingCode; newEodPayPosition.InterestFeePending = 0; @@ -923,6 +929,8 @@ namespace YLErp.Modules.SwapModule eodPayPosition.InterestType = position.InterestType; eodPayPosition.FloatRate = position.FloatRate; eodPayPosition.FloatRateUnderlyingCode = position.FloatRateUnderlyingCode; + eodPayPosition.interest_rest_days = position.interest_rest_days; + eodPayPosition.interest_rule = position.interest_rule; } if (newEodPayPosition == null) { diff --git a/YLErpDAL/Modules/SwapModule/SwapFloatRateService.cs b/YLErpDAL/Modules/SwapModule/SwapFloatRateService.cs index fdf7586d..b796cd35 100644 --- a/YLErpDAL/Modules/SwapModule/SwapFloatRateService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapFloatRateService.cs @@ -110,6 +110,10 @@ namespace YLErp.Modules.SwapModule swapFloatRate.ClientId = req.ClientId; swapFloatRate.ClientNumber = req.ClientNumber; swapFloatRate.ClientName = req.ClientName; + swapFloatRate.interest_type = req.interest_type; + swapFloatRate.interest_rest_days = req.interest_rest_days; + swapFloatRate.interest_rule = req.interest_rule; + swapFloatRate.is_annualized = req.is_annualized; swapFloatRate.SetOpt(UserId, UserName); } else @@ -262,6 +266,29 @@ namespace YLErp.Modules.SwapModule swapFloatRate.BaseUnderlyingCode = reader.GetString("基准利率"); swapFloatRate.StartDate = reader.GetDate("生效起始日",true).Value; swapFloatRate.EndDate = reader.GetDate("生效终止日", true).Value; + swapFloatRate.interest_rest_days = reader.GetInt32("重置频率", true); + var interestType = reader.GetString("计息方式", true); + if (Enum.TryParse(interestType, out InterestTypeEnum parsedInterestType)) + { + swapFloatRate.interest_type = (int)parsedInterestType; + } + else + { + // 如果转换失败,可以根据需要处理错误 + throw new Exception($"无法将计息方式 '{interestType}' 转换为有效的枚举值"); + } + var rule = reader.GetString("利率准则", true); + if (Enum.TryParse(rule, out SwapInterestRule parsedRule)) + { + swapFloatRate.interest_rule = (int)parsedRule; + } + else + { + // 如果转换失败,可以根据需要处理错误 + throw new Exception($"无法将利率准则 '{rule}' 转换为有效的枚举值"); + } + var is_annualized = reader.GetString("是否年化", true); + swapFloatRate.is_annualized = is_annualized == "是"; swapFloatRate.LongPricePoint = reader.GetDecimal("利差(多头加点)"); swapFloatRate.ShortPricePoint = reader.GetDecimal("利差(空头减点)"); swapFloatRate.ClientName = reader.GetString("客户名称"); diff --git a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs index b9a21eda..ee8c8200 100644 --- a/YLErpDAL/Modules/SwapModule/SwapTradeService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapTradeService.cs @@ -252,7 +252,7 @@ namespace YLErp.Modules.SwapModule string structureType = "普通债券类收益互换", bool cashNeedAfter = false) { - var td = PrepareTrade(flowMerge, client, asset, underlying, structureType); + var td = PrepareTrade(flowMerge, client, asset, underlying, clientMarginTemplate?.SwapEndDays??14, structureType); PrepareTradeExtend(flowMerge, td, underlying, swapFloatRate, clientMarginTemplate); td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext); flowMerge.SwapTradeNo = td.TradeNumber; @@ -311,7 +311,7 @@ namespace YLErp.Modules.SwapModule /// /// /// - private trade PrepareTrade(swap_flow_merge flowMerge, Client client, AssetUnit asset, underlying_manager underlying, string structureType = "普通债券类收益互换") + private trade PrepareTrade(swap_flow_merge flowMerge, Client client, AssetUnit asset, underlying_manager underlying,int swapEndDays, string structureType = "普通债券类收益互换") { trade td = new trade() { @@ -339,7 +339,7 @@ namespace YLErp.Modules.SwapModule { td.StartDate = flowMerge.SettleDate.Value; } - td.ExerciseDate = QdpCalendarHelper.GetNonHolidayDefore(td.StartDate.Value.AddDays(14)); + td.ExerciseDate = QdpCalendarHelper.GetNonHolidayDefore(td.StartDate.Value.AddDays(swapEndDays)); PrepareUnderlying(td, underlying); PrepareSwapTradeClient(td, underlying); td.TradeOldStatus = ConsTrade.新增待确认; @@ -446,6 +446,7 @@ namespace YLErp.Modules.SwapModule PosiMatuirityDate = td.ExerciseDate.Value, PosiStartDate = td.StartDate.Value, IsInitial = true, + interest_rest_days = 7, OptTime = DateTime.Now, OptId = UserInfo.UserId, OptName = UserInfo.UserName, @@ -455,6 +456,9 @@ namespace YLErp.Modules.SwapModule interestPosition.InterestRateDefault = flowMerge.BsType == (int)PositionTypeFlag.Long ? (swapFloatRate.LongPricePoint ?? 0) : (swapFloatRate.ShortPricePoint ?? 0) * -1; interestPosition.InterestRateDefault = interestPosition.InterestRateDefault * 0.0001m; interestPosition.FloatRateUnderlyingCode = swapFloatRate.BaseUnderlyingCode; + interestPosition.interest_rule = swapFloatRate.interest_rule; + interestPosition.interest_rest_days = swapFloatRate.interest_rest_days; + interestPosition.IsAnnualized = swapFloatRate.is_annualized ?? false; } var interval = new IntervalModel() { @@ -1411,6 +1415,8 @@ namespace YLErp.Modules.SwapModule position.InterestType = swap.InterestType; position.FloatRate = swap.FloatRate; position.FloatRateUnderlyingCode = swap.FloatRateUnderlyingCode; + position.interest_rest_days = swap.interest_rest_days; + position.interest_rule = swap.interest_rule; if (position.id == 0) { DbContext.swap_position.Add(position); diff --git a/YLErpWeb/App_Docs/导入模板/互换预付金率导入模板.xlsx b/YLErpWeb/App_Docs/导入模板/互换预付金率导入模板.xlsx index ffe8cdb6254f25925c87e6910c9dfdeebd525fa0..ca6173bfbc0d9207f4b7eebc0d1f503680dc4b3a 100644 GIT binary patch delta 2140 zcmV-i2&4DAOuJ05+6I5WJnZ!f0{{Tf1^@sL0001ZY%h0ja%*C5Z)+}iZEUPn&2F1O z5WZLHJD|N2Sd6iaf+PQ6HBwqxNt&pVrDzRnvof$`cO5&4a_nRD&_ku(`T~{uG|6*x z78^T>FKJR_?=lR0d^7XSuz#@3QsasW$#@XYgo}(QFvZl8g`gys38gAa zEyuP!D1cOf|ETVlL%`=*-6^NiIQ9xfNtdJF27QF;6BVsl$%!p?NK#W<+ z)O87pj4bjGr#XKYWSm0SOI$aW0)8I+u?>q;y$M`9ugX{?xa1SH2hi4v^iKTPwlIE@ zg5_=wUWVjaf?hFQ!woCpy^@u;!Sc3X*nTq_25FUA@gaGyM5}MOIjFrqVJSUZN!K7n z@rh)*QYkW0B2^eOMdJW9z~l?My#P^(dC{G-6ueH;by|POYH#E`6ktH@JE@`~CyMrX zu0U#Q>Ti`*iQP*$h}bx$mvbg4^bSY}!hw}UJ{ij)QHe1ZX@L6vXv$QN$8>ZfZ!S$G z<$46_f*t9gF}jdjO=#0tp0hmWivZPd6N0*~Ot&qnkbT7QCAP~7ACT_Za;(6qP(r@7ts-9#AOA!03+^v4LLM2q5O(;Cay3Vk24 z85iVW@y_v?4l;54N=Zv$jWe}RkjzeNzPA6!9vK%S>DvEIm~6%@>|{8=3o3uxlCryz zm0w`fH^Sy4ENqu8dRdi!^mlr`CfH}8NiWSX_lGVQmBbScu84)Yq#v?kl~J}_#QOOm zVeekO6VKOQL4ojq8W|;_JlDo-L*NSzrATx!AP~9mat9wlDFmZa_v@sQ2LU!JynY|l zRk$?woOV0H#zKLC(* zV=~G__4y_FK6?FsK8u$B0+UJ(C;^m{a}GimOi|@rk>!k0<=l|vOyF|*K)(UqhVU%2 z(+-3R3Hk_FA|wF-0Be(A86AJkO2a@Dh4+H*FxBri+5$&V@ceNT$s|awldc zV)sIWP^p4gK~ah#Zi*WzSj3lU(&jB3@#g`I%fsb-dEw@qIMxPCfTA?`=N+E-B5ptKzr$^H1>>* zX_x9G6<(l2Axs?64aaHH*pmpvR~Z@?nm{s?2bpO9WX`nY%hJVwe_F4D`0F$8u6tk)t z0s{puGHgd)v#}i}0e{_2gD@C|&rQ4s(sL+fKbZtrbY@4+Xk_u{tZBb(L@1=KvfYJ8 zUWvwdLGC&%upx`a!}fjq^y!xd<8_u=&mdKjix3gVMHUE_^F%B|G>@nD2w6%~!D*Tc z2+;-<8b`-R0V{l#OSqDG0a7QREJG5?XGMrsS{FXXimf1{%6~BpVZuc&Gpfx}E^$HG zBV7XaTz7~w(3De6aRs!CmWXyp&RS&gB-0we8HN-x5L#j45d72CAT#ynfja3lvqWzS z^QN6{m(5udw(Ye_+G1IjPT8w9j6cD5vx}Shsdgf&SusFSz?sh^P@T)@esVoOy^I6g z*{kN4Ql)2R)L4rI_}M1fzJ6}sKdi5pw*dc64Y2lasK6~_V)GsM14`msASINuv}hq3IhND(36rQdb zYXSfO6aWAK0000000000002Uh>m)$|n3F9fPyw2gekD2^E;4LKUI73AVgdjF5dZ)H S0000000000005ek(yu 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 delta 2467 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 R)Mx|wa8O|cSX1C1@IR;Ke3t+K diff --git a/YLErpWeb/App_Docs/导入模板/浮动利率默认设置导入模板.xlsx b/YLErpWeb/App_Docs/导入模板/浮动利率默认设置导入模板.xlsx index b782b3d550499a78c5b665a85fa3fbc6d9e34c85..b0870dfa797ff9c18a78e027d585933b71a51941 100644 GIT binary patch delta 2729 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 OCBO#_=Y6dFKm0$24!5lU diff --git a/YLErpWeb/App_Docs/导出模板/浮动利率默认设置导出模板.xlsx b/YLErpWeb/App_Docs/导出模板/浮动利率默认设置导出模板.xlsx index e76dc35115cee35ccfe2329a28321f03031ef90e..91c9e3359cba1f58438f47d3ec0b7e4bd1d13946 100644 GIT binary patch delta 2699 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 diff --git a/YLErpWeb/Controllers/riskController.cs b/YLErpWeb/Controllers/riskController.cs index 5fbc8cc0..19b6faa8 100644 --- a/YLErpWeb/Controllers/riskController.cs +++ b/YLErpWeb/Controllers/riskController.cs @@ -526,18 +526,6 @@ namespace YLErp.Web.Controllers else { result = service.QueryGlobalFromCalc(req); } break; - case "资产汇总": - if (req.ValueDate > DateTime.MinValue && req.ValueDate != valuedateBLL.ValueDate) - { result = service.QueryAssetFromDb(req); } - else - { result = service.QueryAssetFromCalc(req); } - break; - case "品种汇总": - if (req.ValueDate > DateTime.MinValue && req.ValueDate != valuedateBLL.ValueDate) - { result = service.QueryVarietyFromDb(req); } - else - { result = service.QueryVarietyFromCalc(req); } - break; case "标的汇总": if (req.ValueDate > DateTime.MinValue && req.ValueDate != valuedateBLL.ValueDate) { result = service.QueryUnderlyingFromDb(req); } diff --git a/YLErpWeb/Views/MarginRateSwap/MarginRateSwapEdit.cshtml b/YLErpWeb/Views/MarginRateSwap/MarginRateSwapEdit.cshtml index da6050ad..01825430 100644 --- a/YLErpWeb/Views/MarginRateSwap/MarginRateSwapEdit.cshtml +++ b/YLErpWeb/Views/MarginRateSwap/MarginRateSwapEdit.cshtml @@ -14,14 +14,6 @@ @section JS{ } -
@Html.HiddenFor(model => model.id) @@ -63,6 +71,12 @@ *
+
+ + + + * +
diff --git a/YLErpWeb/Views/SwapFloatRate/Detail.cshtml b/YLErpWeb/Views/SwapFloatRate/Detail.cshtml index d2e1529a..298e39fc 100644 --- a/YLErpWeb/Views/SwapFloatRate/Detail.cshtml +++ b/YLErpWeb/Views/SwapFloatRate/Detail.cshtml @@ -47,6 +47,22 @@ 生效终止日 @Model.EndDate.OtcFormatDate() + + 是否年化 + @(Model.is_annualized == true ? "是" : "否") + + + 计息方式 + @Model.interest_type_str + + + 重置频率(天) + @Model.interest_rest_days + + + 利率准则 + @Model.interest_rule_str + 基准利率 @baseUnderLyingCode diff --git a/YLErpWeb/Views/SwapFloatRate/Edit.cshtml b/YLErpWeb/Views/SwapFloatRate/Edit.cshtml index 754835c5..5d8d7a14 100644 --- a/YLErpWeb/Views/SwapFloatRate/Edit.cshtml +++ b/YLErpWeb/Views/SwapFloatRate/Edit.cshtml @@ -51,6 +51,31 @@
+
+ + +
+
+ + +
+
+ + +
+
+ + +
diff --git a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml index 3321e235..66b03957 100644 --- a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml +++ b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml @@ -319,6 +319,8 @@ 利率 利率是否年化 计息方式 + 重置频率(天) + 利率准则 结算规则 @@ -340,12 +342,9 @@ -