feat(bond): 支持股票和基金现金分红纳入债券支付计算 - 收紧过度开发行为
- 实现股票/基金现金分红数据从 ex_dividend_info 同步到 BondPayment - 新增公司行为去重机制,避免镜像任务完成后重复计息 - 统一现金分红存储口径为"每 10 份派现金额",保持与同步任务一致性 - 修改 CalcPayment 方法,股票/基金分红需除以 10 转换实际现金金额 - 添加单元测试验证债券票息和股票/基金分红的不同计算方式 - 更新文档注释说明"每 10 份派现金额"存储规范 - 修复公司行为生效日处理逻辑,确保正确应用除权系数 - 扩展测试覆盖股票类证券的公司行为处理场景
This commit is contained in:
@@ -97,19 +97,10 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
public void ExecuteFundCorporateActions(
|
||||
IReadOnlyCollection<eod_swap_position> positions,
|
||||
IReadOnlyCollection<eod_swap_position> previousEodPositions,
|
||||
IReadOnlyCollection<swap_flow_event> flowEvents,
|
||||
IReadOnlyCollection<ex_dividend_info> dividendInfos)
|
||||
{
|
||||
ApplyFundCorporateActions(
|
||||
ApplyCorporateActions(
|
||||
positions,
|
||||
previousEodPositions,
|
||||
flowEvents,
|
||||
dividendInfos.ToDictionary(x => x.UnderlyingCode, StringComparer.OrdinalIgnoreCase),
|
||||
SettleDate);
|
||||
ApplyFundCashDividends(
|
||||
positions,
|
||||
previousEodPositions,
|
||||
dividendInfos.ToDictionary(x => x.UnderlyingCode, StringComparer.OrdinalIgnoreCase),
|
||||
SettleDate);
|
||||
}
|
||||
@@ -315,8 +306,6 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
service.ExecuteFundCorporateActions(
|
||||
new[] { actual },
|
||||
new[] { previousEod },
|
||||
Array.Empty<swap_flow_event>(),
|
||||
service.ExDividendInfos);
|
||||
|
||||
Assert.AreEqual(2000m, actual.PosiQuantity);
|
||||
@@ -381,25 +370,24 @@ namespace YLErp.Modules.SwapModule
|
||||
new List<swap_flow_event>(),
|
||||
price: 100m);
|
||||
service.ExDividendInfos.Add(CreateFundCorporateAction(shareAmount: 10m));
|
||||
var todayEod = previousEod.Clone();
|
||||
todayEod.ValueDate = SettleDate;
|
||||
todayEod.UnderlyingPrice = 100m;
|
||||
// 生产重收盘每次都会从上一日 EOD clone 出新的当日基线,再应用一次公司行为;
|
||||
// 底层 ApplyCorporateActions 只负责处理调用方提供的未调整基线,不再承担恢复旧基线的测试兼容职责。
|
||||
var firstRunEod = previousEod.Clone();
|
||||
firstRunEod.ValueDate = SettleDate;
|
||||
firstRunEod.UnderlyingPrice = 100m;
|
||||
service.ExecuteFundCorporateActions(new[] { firstRunEod }, service.ExDividendInfos);
|
||||
|
||||
service.ExecuteFundCorporateActions(
|
||||
new[] { todayEod },
|
||||
new[] { previousEod },
|
||||
Array.Empty<swap_flow_event>(),
|
||||
service.ExDividendInfos);
|
||||
service.ExecuteFundCorporateActions(
|
||||
new[] { todayEod },
|
||||
new[] { previousEod },
|
||||
Array.Empty<swap_flow_event>(),
|
||||
service.ExDividendInfos);
|
||||
var rerunEod = previousEod.Clone();
|
||||
rerunEod.ValueDate = SettleDate;
|
||||
rerunEod.UnderlyingPrice = 100m;
|
||||
service.ExecuteFundCorporateActions(new[] { rerunEod }, service.ExDividendInfos);
|
||||
|
||||
Assert.AreEqual(2000m, todayEod.PosiQuantity);
|
||||
Assert.AreEqual(1000m, todayEod.TdChangedQty);
|
||||
Assert.AreEqual(50m, todayEod.PosiGrossPrice);
|
||||
Assert.AreEqual(100000m, todayEod.PosiNotionalValue);
|
||||
Assert.AreEqual(2000m, firstRunEod.PosiQuantity);
|
||||
Assert.AreEqual(1000m, firstRunEod.TdChangedQty);
|
||||
Assert.AreEqual(50m, firstRunEod.PosiGrossPrice);
|
||||
Assert.AreEqual(100000m, firstRunEod.PosiNotionalValue);
|
||||
Assert.AreEqual(firstRunEod.PosiQuantity, rerunEod.PosiQuantity);
|
||||
Assert.AreEqual(firstRunEod.PosiGrossPrice, rerunEod.PosiGrossPrice);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -427,8 +415,6 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
service.ExecuteFundCorporateActions(
|
||||
new[] { actual },
|
||||
new[] { previousEod },
|
||||
Array.Empty<swap_flow_event>(),
|
||||
service.ExDividendInfos);
|
||||
|
||||
Assert.AreEqual(1000m, actual.PosiQuantity);
|
||||
@@ -559,8 +545,6 @@ namespace YLErp.Modules.SwapModule
|
||||
|
||||
service.ExecuteFundCorporateActions(
|
||||
new[] { actual },
|
||||
new[] { previousEod },
|
||||
Array.Empty<swap_flow_event>(),
|
||||
service.ExDividendInfos);
|
||||
|
||||
Assert.AreEqual(10m, actual.PosiQuantity,
|
||||
|
||||
Reference in New Issue
Block a user