diff --git a/YLErpDAL/Modules/RiskEngine/测试用例.md b/YLErpDAL/Modules/RiskEngine/测试用例.md
index 2eb3b5fe..a268de5b 100644
--- a/YLErpDAL/Modules/RiskEngine/测试用例.md
+++ b/YLErpDAL/Modules/RiskEngine/测试用例.md
@@ -2180,17 +2180,16 @@ WHERE t.id = @TradeId;
## 19. 规则 8 查询结果排查 SQL
-规则 8:支付日为银行间交易日(本地)。用于核对交易平仓窗口的支付日期是否为银行间交易日;若支付日期未落在 IB 日历的非交易日列表中,则命中。
+规则 8:支付日为银行间交易日(本地)。用于核对互换交易-交易查看-交易平仓窗口中本次提交的支付日期是否为银行间交易日;若支付日期未落在 IB 日历的非交易日列表中,则命中。
取数流程:
```text
-1. 根据 TradeId 查 swap_flow_event。
-2. 限定 SwapTradeId = TradeId、EventType = 2、DataState <> 0,取平仓事件。
-3. 取 swap_flow_event.PayDate,作为交易平仓窗口的支付日期。
-4. 根据 PayDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
-5. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
-6. 若 HolidayJson 不包含支付日期对应的 yyyy,MM,dd,则说明支付日期是银行间交易日,命中规则。
+1. 用户从互换交易-交易查看进入交易平仓窗口。
+2. 取交易平仓窗口本次提交的支付日期,即 UnwindData.PayDate。
+3. 根据 PayDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
+4. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
+5. 若 HolidayJson 不包含支付日期对应的 yyyy,MM,dd,则说明支付日期是银行间交易日,命中规则。
```
规则公式:
@@ -2202,10 +2201,9 @@ WHERE t.id = @TradeId;
规则字段口径:
```text
-支付日期:swap_flow_event.PayDate,对应交易平仓窗口的支付日期
-平仓事件:swap_flow_event.EventType = 2
+支付日期:UnwindData.PayDate,对应互换交易-交易查看-交易平仓窗口的支付日期
银行间日历:calendar.Country = 'IB'
-日历年份:calendar.Year = swap_flow_event.PayDate.Year
+日历年份:calendar.Year = UnwindData.PayDate.Year
非交易日:calendar.HolidayJson
```
@@ -2216,6 +2214,17 @@ WHERE t.id = @TradeId;
```
+变量 Roslyn 示例:变量名为“平仓支付日期为银行间交易日”,DataType 为 Bool;规则前端配置“平仓支付日期为银行间交易日 == true”。该变量必须使用本次平仓请求中的 PayDate,不能查询 swap_flow_event 历史平仓事件,否则首次提交和修改支付日期后的试算会取不到当前页面值。
+
+```csharp
+if (!PayDate.HasValue)
+ throw new Exception("平仓支付日期为空");
+
+return new RiskVariableValueDetail(
+ RiskCalendarHelper.IsInterbankTradingDay(DbContext, PayDate.Value),
+ $"交易ID {TradeId},本次平仓支付日期为{PayDate.Value:yyyy-MM-dd}");
+```
+
注释规则定义:
```csharp
@@ -2223,8 +2232,8 @@ WHERE t.id = @TradeId;
//{
// Id = 1000008,
// RuleName = "支付日为银行间交易日(本地)",
-// RuleText = "取值字段:通过 DbContext.swap_flow_event 按 SwapTradeId=TradeId、EventType=2、DataState<>0 取平仓事件的 PayDate,PayDate 对应交易平仓窗口的支付日期;通过 DbContext.calendar 按 Country='IB' 且 Year=PayDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若支付日期对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明支付日期是银行间交易日,触发审批。",
-// RuleExpr = "DbContext.swap_flow_event.Any(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.PayDate.HasValue) && !DbContext.calendar.First(c => c.Country == \"IB\" && c.Year == DbContext.swap_flow_event.Where(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.PayDate.HasValue).OrderByDescending(e => e.id).First().PayDate.Value.Year && c.ValidState != \"InValid\").HolidayJson.Contains(DbContext.swap_flow_event.Where(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.PayDate.HasValue).OrderByDescending(e => e.id).First().PayDate.Value.ToString(\"yyyy,MM,dd\"))",
+// RuleText = "取值字段:取互换交易-交易查看-交易平仓窗口本次提交的 UnwindData.PayDate,PayDate 对应页面支付日期;通过 DbContext.calendar 按 Country='IB' 且 Year=PayDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若支付日期对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明支付日期是银行间交易日,触发审批。",
+// RuleExpr = "PayDate.HasValue && RiskCalendarHelper.IsInterbankTradingDay(DbContext, PayDate.Value)",
// Version = 1,
// Status = RiskRuleStatus.Active,
// OptId = 0,
@@ -2236,6 +2245,8 @@ WHERE t.id = @TradeId;
//});
```
+变量值核对 SQL:用于核对已落库平仓事件的支付日期是否为银行间交易日;首次提交前的页面值应以请求中的 UnwindData.PayDate 为准,不能只依赖该 SQL。
+
```sql
SET @TradeId = 3001699;
@@ -2274,33 +2285,54 @@ WHERE t.id = @TradeId;
## 20. 规则 9 查询结果排查 SQL
-规则 9:到期日为银行间交易日(本地)。用于核对互换交易界面的到期日是否为银行间交易日;若到期日未落在 IB 日历的非交易日列表中,则命中。
+规则 9:到期日为银行间交易日(本地)。用于核对新增互换交易的到期日期是否为银行间交易日;若到期日期未落在 IB 日历的非交易日列表中,则命中。
取数流程:
```text
-1. 根据 TradeId 查当前 trade。
-2. 取 trade.ExerciseDate,作为互换交易界面的到期日。
-3. 根据 ExerciseDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
-4. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
-5. 若 HolidayJson 不包含到期日对应的 yyyy,MM,dd,则说明到期日是银行间交易日,命中规则。
+1. 根据 TradeId 查 swap_position。
+2. 限定 SwapTradeId = TradeId、IsInitial = 1,取新增互换交易生成的期初持仓。
+3. 取 swap_position.PosiMatuirityDate,作为新增互换交易的到期日期。
+4. 根据 PosiMatuirityDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
+5. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
+6. 若 HolidayJson 不包含到期日期对应的 yyyy,MM,dd,则说明到期日期是银行间交易日,命中规则。
```
规则公式:
```text
-到期日 ∉ IB 日历非交易日
+到期日期 ∉ IB 日历非交易日
```
规则字段口径:
```text
-到期日:trade.ExerciseDate,对应互换交易界面的到期日
+到期日期:swap_position.PosiMatuirityDate,对应新增互换交易的到期日期
+期初持仓:swap_position.IsInitial = 1
银行间日历:calendar.Country = 'IB'
-日历年份:calendar.Year = trade.ExerciseDate.Year
+日历年份:calendar.Year = swap_position.PosiMatuirityDate.Year
非交易日:calendar.HolidayJson
```
+变量 Roslyn 示例:变量名为“互换到期日期为银行间交易日”,DataType 为 Bool;规则前端配置“互换到期日期为银行间交易日 == true”。该变量取新增互换交易生成的期初持仓到期日期,即 swap_position.PosiMatuirityDate。
+
+```csharp
+var maturityDate = DbContext.swap_position
+ .Where(p => p.SwapTradeId == TradeId
+ && p.IsInitial
+ && p.PosiMatuirityDate.HasValue)
+ .OrderBy(p => p.id)
+ .Select(p => p.PosiMatuirityDate)
+ .FirstOrDefault();
+
+if (!maturityDate.HasValue)
+ throw new Exception("互换到期日期为空");
+
+return new RiskVariableValueDetail(
+ RiskCalendarHelper.IsInterbankTradingDay(DbContext, maturityDate.Value),
+ $"交易ID {TradeId},互换到期日期为{maturityDate.Value:yyyy-MM-dd}");
+```
+
注释规则定义:
```csharp
@@ -2308,8 +2340,8 @@ WHERE t.id = @TradeId;
//{
// Id = 1000009,
// RuleName = "到期日为银行间交易日(本地)",
-// RuleText = "取值字段:通过 DbContext.trade 按 TradeId 取当前交易的 ExerciseDate,ExerciseDate 对应互换交易界面的到期日;通过 DbContext.calendar 按 Country='IB' 且 Year=ExerciseDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若到期日对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明到期日是银行间交易日,触发审批。",
-// RuleExpr = "DbContext.trade.First(t => t.id == TradeId).ExerciseDate.HasValue && !DbContext.calendar.First(c => c.Country == \"IB\" && c.Year == DbContext.trade.First(t => t.id == TradeId).ExerciseDate.Value.Year && c.ValidState != \"InValid\").HolidayJson.Contains(DbContext.trade.First(t => t.id == TradeId).ExerciseDate.Value.ToString(\"yyyy,MM,dd\"))",
+// RuleText = "取值字段:通过 DbContext.swap_position 按 SwapTradeId=TradeId、IsInitial=true 取新增互换交易生成的期初持仓 PosiMatuirityDate,PosiMatuirityDate 对应新增互换交易的到期日期;通过 DbContext.calendar 按 Country='IB' 且 Year=PosiMatuirityDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若到期日期对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明到期日期是银行间交易日,触发审批。",
+// RuleExpr = "DbContext.swap_position.Any(p => p.SwapTradeId == TradeId && p.IsInitial && p.PosiMatuirityDate.HasValue) && RiskCalendarHelper.IsInterbankTradingDay(DbContext, DbContext.swap_position.Where(p => p.SwapTradeId == TradeId && p.IsInitial && p.PosiMatuirityDate.HasValue).OrderBy(p => p.id).First().PosiMatuirityDate.Value)",
// Version = 1,
// Status = RiskRuleStatus.Active,
// OptId = 0,
@@ -2327,19 +2359,30 @@ SET @TradeId = 3001699;
SELECT
t.id AS TradeId,
t.TradeType,
- t.ExerciseDate AS MaturityDate,
+ sp.id AS SwapPositionId,
+ sp.IsInitial,
+ sp.PosiMatuirityDate AS MaturityDate,
c.Country AS CalendarCountry,
c.Year AS CalendarYear,
- DATE_FORMAT(t.ExerciseDate, '%Y,%m,%d') AS MaturityDateText,
+ DATE_FORMAT(sp.PosiMatuirityDate, '%Y,%m,%d') AS MaturityDateText,
CASE
- WHEN t.ExerciseDate IS NOT NULL
- AND c.HolidayJson NOT LIKE CONCAT('%', DATE_FORMAT(t.ExerciseDate, '%Y,%m,%d'), '%') THEN 1
+ WHEN sp.PosiMatuirityDate IS NOT NULL
+ AND c.HolidayJson NOT LIKE CONCAT('%', DATE_FORMAT(sp.PosiMatuirityDate, '%Y,%m,%d'), '%') THEN 1
ELSE 0
END AS IsMaturityDateIBTradingDay
FROM trade t
+LEFT JOIN (
+ SELECT *
+ FROM swap_position
+ WHERE SwapTradeId = @TradeId
+ AND IsInitial = 1
+ AND PosiMatuirityDate IS NOT NULL
+ ORDER BY id
+ LIMIT 1
+) sp ON sp.SwapTradeId = t.id
LEFT JOIN calendar c
ON c.Country = 'IB'
- AND c.Year = YEAR(t.ExerciseDate)
+ AND c.Year = YEAR(sp.PosiMatuirityDate)
AND c.ValidState <> 'InValid'
WHERE t.id = @TradeId;
```
@@ -2348,17 +2391,16 @@ WHERE t.id = @TradeId;
## 21. 规则 10 查询结果排查 SQL
-规则 10:平仓日为银行间交易日(本地)。用于核对交易平仓窗口的平仓日期是否为银行间交易日;若平仓日期未落在 IB 日历的非交易日列表中,则命中。
+规则 10:平仓日为银行间交易日(本地)。用于核对互换交易-交易查看-交易平仓窗口中本次提交的平仓日期是否为银行间交易日;若平仓日期未落在 IB 日历的非交易日列表中,则命中。
取数流程:
```text
-1. 根据 TradeId 查 swap_flow_event。
-2. 限定 SwapTradeId = TradeId、EventType = 2、DataState <> 0,取平仓事件。
-3. 取 swap_flow_event.UnwindDate,作为交易平仓窗口的平仓日期。
-4. 根据 UnwindDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
-5. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
-6. 若 HolidayJson 不包含平仓日期对应的 yyyy,MM,dd,则说明平仓日期是银行间交易日,命中规则。
+1. 用户从互换交易-交易查看进入交易平仓窗口。
+2. 取交易平仓窗口本次提交的平仓日期,即 UnwindData.UnwindDate。
+3. 根据 UnwindDate.Value.Year 查询 calendar 表中 Country = 'IB' 的银行间日历。
+4. calendar.HolidayJson 存储该年非交易日,格式为 yyyy,MM,dd。
+5. 若 HolidayJson 不包含平仓日期对应的 yyyy,MM,dd,则说明平仓日期是银行间交易日,命中规则。
```
规则公式:
@@ -2370,10 +2412,9 @@ WHERE t.id = @TradeId;
规则字段口径:
```text
-平仓日期:swap_flow_event.UnwindDate,对应交易平仓窗口的平仓日期
-平仓事件:swap_flow_event.EventType = 2
+平仓日期:UnwindData.UnwindDate,对应互换交易-交易查看-交易平仓窗口的平仓日期
银行间日历:calendar.Country = 'IB'
-日历年份:calendar.Year = swap_flow_event.UnwindDate.Year
+日历年份:calendar.Year = UnwindData.UnwindDate.Year
非交易日:calendar.HolidayJson
```
@@ -2384,6 +2425,17 @@ WHERE t.id = @TradeId;
```
+变量 Roslyn 示例:变量名为“平仓日期为银行间交易日”,DataType 为 Bool;规则前端配置“平仓日期为银行间交易日 == true”。该变量必须使用本次平仓请求中的 UnwindDate,不能查询 swap_flow_event 历史平仓事件,否则首次提交和修改平仓日期后的试算会取不到当前页面值。
+
+```csharp
+if (!UnwindDate.HasValue)
+ throw new Exception("平仓日期为空");
+
+return new RiskVariableValueDetail(
+ RiskCalendarHelper.IsInterbankTradingDay(DbContext, UnwindDate.Value),
+ $"交易ID {TradeId},本次平仓日期为{UnwindDate.Value:yyyy-MM-dd}");
+```
+
注释规则定义:
```csharp
@@ -2391,8 +2443,8 @@ WHERE t.id = @TradeId;
//{
// Id = 1000010,
// RuleName = "平仓日为银行间交易日(本地)",
-// RuleText = "取值字段:通过 DbContext.swap_flow_event 按 SwapTradeId=TradeId、EventType=2、DataState<>0 取平仓事件的 UnwindDate,UnwindDate 对应交易平仓窗口的平仓日期;通过 DbContext.calendar 按 Country='IB' 且 Year=UnwindDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若平仓日期对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明平仓日期是银行间交易日,触发审批。",
-// RuleExpr = "DbContext.swap_flow_event.Any(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.UnwindDate.HasValue) && !DbContext.calendar.First(c => c.Country == \"IB\" && c.Year == DbContext.swap_flow_event.Where(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.UnwindDate.HasValue).OrderByDescending(e => e.id).First().UnwindDate.Value.Year && c.ValidState != \"InValid\").HolidayJson.Contains(DbContext.swap_flow_event.Where(e => e.SwapTradeId == TradeId && e.EventType == 2 && e.DataState != 0 && e.UnwindDate.HasValue).OrderByDescending(e => e.id).First().UnwindDate.Value.ToString(\"yyyy,MM,dd\"))",
+// RuleText = "取值字段:取互换交易-交易查看-交易平仓窗口本次提交的 UnwindData.UnwindDate,UnwindDate 对应页面平仓日期;通过 DbContext.calendar 按 Country='IB' 且 Year=UnwindDate.Year 取银行间日历,HolidayJson 存储该年非交易日。计算逻辑:若平仓日期对应的 yyyy,MM,dd 不存在于 IB 日历 HolidayJson 中,则说明平仓日期是银行间交易日,触发审批。",
+// RuleExpr = "UnwindDate.HasValue && RiskCalendarHelper.IsInterbankTradingDay(DbContext, UnwindDate.Value)",
// Version = 1,
// Status = RiskRuleStatus.Active,
// OptId = 0,
@@ -2404,6 +2456,8 @@ WHERE t.id = @TradeId;
//});
```
+变量值核对 SQL:用于核对已落库平仓事件的平仓日期是否为银行间交易日;首次提交前的页面值应以请求中的 UnwindData.UnwindDate 为准,不能只依赖该 SQL。
+
```sql
SET @TradeId = 3001699;