EQD-6967 fix(eod): 收盘缺失价检查按客户作用域收敛持仓分支
- EodCheckSettlePrice 抽出 public static QueryPositionUnderlyingCodes, 增加 clienIds 过滤:client-scoped 收盘不再把其他客户/系统级(ClientId=0) 持仓标的纳入"检查标的结算价格缺失"。 - clienIds==null(系统级全结算)时短路为 true,零回归。 - class 改 public 便于单测。 - 新增 EodCheckSettlePriceClientScopeTest 确定性回归测试(红绿双段验证)。 - 代码补充 EQD-6967 防御行为详细注释(仅聚焦客户作用域收敛)。 - 防御范围说明:场内 exchange_trade 无 ClientId 列,场内分支噪声需靠结算模式选 '场外交易'(IsSettleExchangeTrades=false)规避,本提交不覆盖该分支。
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Configuration.Enums;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
|
||||
namespace YLErp.Modules.EodModule.SettlementModule
|
||||
@@ -7,7 +7,7 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
/// <summary>
|
||||
/// 检查当日结算价,是否全部进系统。
|
||||
/// </summary>
|
||||
class EodCheckSettlePrice : EodSettleServiceBaseV2
|
||||
public class EodCheckSettlePrice : EodSettleServiceBaseV2
|
||||
{
|
||||
public const string Step = "检查标的结算价格缺失";
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
|
||||
allQuery = DbContext.trade.Where(tradePredicate).Select(n => n.UnderlyingCode).Distinct();
|
||||
|
||||
if (PS.Config.ErpElement.ForwardTradePriceModel == Configuration.Enums.ForwardTradePriceModel.STANDARD)
|
||||
if (PS.Config.ErpElement.ForwardTradePriceModel == ForwardTradePriceModel.STANDARD)
|
||||
{
|
||||
allQuery = allQuery.Union(DbContext.trade.Where(tradePredicate).Where(x => x.BasisUnderlyingCode != null && x.BasisUnderlyingCode != "").Select(n => n.BasisUnderlyingCode).Distinct());
|
||||
}
|
||||
@@ -88,14 +88,8 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
allQuery = allQuery == null ? exTradeQuery.Distinct() : allQuery.Union(exTradeQuery.Distinct());
|
||||
|
||||
var preSettleDate = _context.PreSettleDate;
|
||||
//最后一个交易日持仓信息
|
||||
var futureTypes = ConsGlobal.InstrumentType.GetFutureTypes();
|
||||
var positionQuery = from t in DbContext.eod_trade_position
|
||||
join um in DbContext.underlying_manager on t.UnderlyingCode equals um.UnderlyingCode
|
||||
where t.ValueDate == preSettleDate && t.Amount != 0
|
||||
&& ConsTrade.TradeTypesForHedge.Contains(t.TradeType)
|
||||
&& (!futureTypes.Contains(um.UnderlyingInstrumentType) || um.MaturityDate >= settleDate)
|
||||
select t.UnderlyingCode;
|
||||
// 持仓分支传入 clienIds:使上一交易日持仓标的按当前收盘客户作用域收敛(防御点详见 QueryPositionUnderlyingCodes)。
|
||||
var positionQuery = QueryPositionUnderlyingCodes(DbContext, preSettleDate, settleDate, clienIds);
|
||||
|
||||
allQuery = allQuery.Union(positionQuery.Distinct());
|
||||
}
|
||||
@@ -130,6 +124,41 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
_context.RaiseError(Step, "标的代码:" + codes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取上一交易日持仓中需结算价的标的(持仓分支)。
|
||||
/// 抽成 static 以便单测直接覆盖 ClientId 收敛语义。
|
||||
///
|
||||
/// ── 防御行为(EQD-6967)─────────────────────────────────────────────
|
||||
/// 收盘缺失价检查在“按客户作用域结算(ClientIds 非 null)”时,本应只校验
|
||||
/// 当前收盘客户自己的标的,而不应把“其他客户”或“系统级(ClientId=0)”的
|
||||
/// 上一交易日持仓标的误报为缺失价。历史上持仓分支完全未引用 ClientId,
|
||||
/// 导致客户 A 收盘时被其他客户/系统级持仓的标的噪声干扰(见缺陷现象)。
|
||||
///
|
||||
/// 本方法通过 clienIds 过滤做收敛,与 OTC 分支、客户产品分支已有的
|
||||
/// ClientId 过滤语义保持一致:
|
||||
/// · clienIds == null → 系统级全量结算,短路为 true(不收窄,零回归);
|
||||
/// · clienIds != null → 仅返回属于指定客户的持仓标的(Contains(t.ClientId)),
|
||||
/// 过滤掉其他客户及系统级(ClientId=0)持仓噪声。
|
||||
/// 注意:场外交易结算模式(IsSettleExchangeTrades=false)下持仓分支整块跳过,
|
||||
/// 此时本方法不会被调用,属操作层面的规避而非修复。
|
||||
/// ───────────────────────────────────────────────────────────────────
|
||||
/// </summary>
|
||||
public static IQueryable<string> QueryPositionUnderlyingCodes(YLContext db, DateTime preSettleDate, DateTime settleDate, IEnumerable<int> clienIds)
|
||||
{
|
||||
var futureTypes = ConsGlobal.InstrumentType.GetFutureTypes();
|
||||
return from t in db.eod_trade_position
|
||||
join um in db.underlying_manager on t.UnderlyingCode equals um.UnderlyingCode
|
||||
where t.ValueDate == preSettleDate && t.Amount != 0
|
||||
&& ConsTrade.TradeTypesForHedge.Contains(t.TradeType)
|
||||
&& (!futureTypes.Contains(um.UnderlyingInstrumentType) || um.MaturityDate >= settleDate)
|
||||
// 【防御点·EQD-6967】按客户作用域收敛持仓标的:
|
||||
// clienIds==null → 系统级全量结算,不收窄(零回归);
|
||||
// clienIds!=null → 仅保留指定客户持仓,过滤掉其他客户/系统级(ClientId=0)持仓噪声。
|
||||
&& (clienIds == null || clienIds.Contains(t.ClientId))
|
||||
select t.UnderlyingCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取互换标的
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user