test(swap): EQD-6977 罚息契约钉死——金标准恒等式(全期=已结+罚息,含不算尾/中段平仓双承接量) + 边界四象限 + 部分平仓 + 冻结取率规则
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
using YLErp.DBModels.Enums;
|
||||
using YLErp.Modules.SwapModule;
|
||||
using YLErp.Modules.SwapModule.Accrual;
|
||||
using YLErp.Modules.SwapModule.Penalty;
|
||||
|
||||
namespace UnitTestProject.Modules.SwapModule.Penalty
|
||||
{
|
||||
/// <summary>
|
||||
/// EQD-6977 罚息冻结利率解析契约测试。
|
||||
/// 规则(需求 2.2.2):冻结为「最后一个重置区间」定盘;终止日为重置日也取上一区间。
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class PenaltyLegRateResolverTest
|
||||
{
|
||||
private const decimal Spread = 0.05m; // +500bp
|
||||
private static readonly DateTime UnwindDate = new(2026, 8, 25);
|
||||
|
||||
private static swap_position CreateFloatPosition(int interestRule = 0)
|
||||
=> new()
|
||||
{
|
||||
id = 1001, SwapTradeId = 1, PosiDirection = 0,
|
||||
InterestDirection = (int)SwapDirectionEnum.支付,
|
||||
InterestMode = (int)InterestModeEnum.标的期初全价,
|
||||
InterestRateDefault = Spread,
|
||||
PosiStartDate = new DateTime(2026, 7, 31),
|
||||
interest_rest_days = 7, interest_rule = interestRule,
|
||||
FloatRateUnderlyingCode = "FR007",
|
||||
FloatRate = 0.0185m
|
||||
};
|
||||
|
||||
[TestMethod]
|
||||
public void 浮动腿_preEod快照优先_重置日下午仍取上一区间()
|
||||
{
|
||||
// 8/25 为重置日且下午已出新价的边缘场景:preEod.FloatRate(昨日区间定盘)仍优先,
|
||||
// 解析器不做任何取价——「终止日取上一区间」由快照语义天然覆盖。
|
||||
var p = CreateFloatPosition();
|
||||
var rate = PenaltyLegRateResolver.ResolveFrozenRate(
|
||||
p, spread: Spread, preEodFloatRate: 0.0210m,
|
||||
unwindDate: UnwindDate, tryGetFixing: _ => throw new AssertFailedException("preEod 在场时不应取价"));
|
||||
|
||||
Assert.AreEqual(Spread + 0.0210m, rate.AllInRate, "冻结 all-in = 利差 + 上一区间定盘");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void 浮动腿_无preEod_按前一营业日取价日取定盘()
|
||||
{
|
||||
var p = CreateFloatPosition(interestRule: 0); // 当前营业日规则
|
||||
DateTime? askedDate = null;
|
||||
var rate = PenaltyLegRateResolver.ResolveFrozenRate(
|
||||
p, spread: Spread, preEodFloatRate: null,
|
||||
unwindDate: UnwindDate,
|
||||
tryGetFixing: d => { askedDate = d; return 0.0195m; });
|
||||
|
||||
Assert.AreEqual(new DateTime(2026, 8, 24), askedDate, "取价日 = GetFixingDate(8/24, rule=0)");
|
||||
Assert.AreEqual(Spread + 0.0195m, rate.AllInRate);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void 浮动腿_无preEod_缺价抛异常()
|
||||
{
|
||||
var p = CreateFloatPosition();
|
||||
Assert.ThrowsException<Exception>(() =>
|
||||
PenaltyLegRateResolver.ResolveFrozenRate(
|
||||
p, spread: Spread, preEodFloatRate: null,
|
||||
unwindDate: UnwindDate, tryGetFixing: _ => null));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void 固定腿_不取价_直接固定利率()
|
||||
{
|
||||
var p = CreateFloatPosition();
|
||||
p.FloatRateUnderlyingCode = null;
|
||||
|
||||
var rate = PenaltyLegRateResolver.ResolveFrozenRate(
|
||||
p, spread: Spread, preEodFloatRate: null,
|
||||
unwindDate: UnwindDate, tryGetFixing: _ => throw new AssertFailedException("固定腿不应取价"));
|
||||
|
||||
Assert.AreEqual(Spread, rate.AllInRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user