82 lines
3.4 KiB
C#
82 lines
3.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|