feat(trade): 新增真实除权日字段并完善基金公司行为处理 init
- 添加 EffectiveDate 字段用于标识真实除权生效日 - 实现公司行为价格系数和数量系数统一计算方法 - 增加基金除权回退和平仓基线恢复功能 - 完善除权日验证逻辑,确保真实除权日不早于股权登记日 - 重构平仓流程,支持按有效EOD基线重新计算损益和现金 - 添加基金拆合股和现金分红的特殊处理逻辑 - 增加单元测试验证各种公司行为场景下的正确性
This commit is contained in:
@@ -1538,6 +1538,9 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
else
|
||||
{
|
||||
// 按日期回退时只恢复 valueDate 之前最近实际收盘的快照;当天及以后数据会在
|
||||
// InvalidTradeOptionDatasByDate 中清理。这样回退到除权日 D 会回到 D-1 的
|
||||
// 1000 份/100 基线并让重收盘重新应用公司行为;回退到 D+1 则保留 D 的 2000 份/50。
|
||||
TradeBackByDate(td, valueDate, swapPositions);
|
||||
}
|
||||
if (swapEvent != null)//展期
|
||||
@@ -1673,8 +1676,14 @@ namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
SwapEodPositionService eodPositionService = new SwapEodPositionService(this);
|
||||
SwapDealService swapDealService = new SwapDealService(this);
|
||||
var preDay = valueDate.AddDays(-1);
|
||||
var eodSwapPositionList = DbContext.eod_swap_position.Where(x => x.ValueDate == preDay && x.SwapTradeId == td.id).ToList();
|
||||
// 回退基线必须是 valueDate 之前最近一个实际 EOD,而不是 valueDate-1 自然日。
|
||||
// 例如周一/节假日后的 valueDate 没有周日 EOD 时,AddDays(-1) 会得到空集合,
|
||||
// 实时腿仍保留除权后的数量/价格。回退到除权日 D 选择 D 前基线并由下面的
|
||||
// InvalidTradeOptionDatasByDate 删除 D 及以后 EOD;回退到 D+1 则会选择 D,
|
||||
// 保留 D 已生效的公司行为。ex_dividend_info 本身不删除,重收盘 D 会再应用一次。
|
||||
var eodSwapPositionList = eodPositionService.GetLatestEodPositionsBefore(td.id, valueDate);
|
||||
// 没有 valueDate 之前的有效 EOD 时,eodSwapPositionList 为空;这是“没有可证明基线”的情况,
|
||||
// 下面不会伪造数量/价格或重算公司行为,只保留当前实时持仓并继续清理回退日之后的数据。
|
||||
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.SwapTradeId == td.id && x.EventDate >= valueDate && x.DataState > (int)SwapFlowDateStateEnum.废弃).ToList();
|
||||
var positions = swapPositions.Where(x => x.PosiDirection > 0 && !x.IsInitial).ToList();
|
||||
|
||||
@@ -1700,6 +1709,8 @@ namespace YLErp.Modules.SwapModule
|
||||
td.TradeAmount = Convert.ToDouble(posi.PosiQuantity);
|
||||
}
|
||||
}
|
||||
// eodPosi 为空时刻意不改 posi:回退只能使用已落库的历史快照,不能把缺失数据
|
||||
// 猜成 0 或交易初始值,否则会把未验证的 Fund 除权数量带入后续收盘。
|
||||
}
|
||||
td.UnWindDate = null;
|
||||
td.UnWindNotional = null;
|
||||
@@ -1740,6 +1751,10 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <param name="valueDate"></param>
|
||||
private void InvalidTradeOptionDatasByDate(int tradeId, DateTime valueDate, bool backToBegin)
|
||||
{
|
||||
// 所有清理条件都采用闭区间起点 [valueDate, +∞):回退到除权日 D 要删除 D 当天
|
||||
// 已应用的 EOD/流水,随后重收盘 D 才会从 D-1 快照重新套一次系数;回退到 D+1
|
||||
// 不会删除 D,因而保留 D 已生效的 2000 份/50。valueDate 之前的快照始终保留,
|
||||
// 作为 TradeBackByDate 的唯一可验证基线。
|
||||
var swapEvents = DbContext.swap_event.Where(x => !x.Invalid && x.SwapTradeId == tradeId && x.ValueDate >= valueDate).ToList();
|
||||
var swapEodPositions = DbContext.eod_swap_position.Where(x => x.SwapTradeId == tradeId && x.ValueDate >= valueDate);
|
||||
var swapEods = DbContext.eod_swap.Where(x => x.SwapTradeId == tradeId && x.ValueDate >= valueDate);
|
||||
|
||||
Reference in New Issue
Block a user