Files
zszq-trs/UnitTestProject/Modules/SwapModule/SwapAdditionalMarginCalcTest.cs

143 lines
6.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using YLErp.DBModels;
using YLErp.Modules.SwapModule;
using YLErp.Modules.SwapModule.Margin;
namespace YLErp.Modules.SwapModule
{
/// <summary>
/// R3 阶段四 §4.1 合约维度追加保证金计算测试(纯函数):
/// 目标 = 维持保证金 − 应付预付金净收额(≤0 不追);当日新增 = 目标 − 已补足(现金记录累计+授信占用累计);
/// 授信优先分配;重跑幂等(新增=0 不写);追保回落不返还(负缺口走可用资金公式)。
/// </summary>
[TestClass]
public class SwapAdditionalMarginCalcTest
{
[TestMethod]
public void AM_001_目标计算_维持大于应付()
{
//维持 180 应付净收 100 = 80
Assert.AreEqual(80, SwapAdditionalMarginCalc.CalcTarget(180, 100), 1e-6);
}
[TestMethod]
public void AM_002_目标计算_应付覆盖维持_不追()
{
Assert.AreEqual(0, SwapAdditionalMarginCalc.CalcTarget(80, 100), 1e-6);
}
[TestMethod]
public void AM_003_目标计算_维持为负_我方净支付方向不追()
{
Assert.AreEqual(0, SwapAdditionalMarginCalc.CalcTarget(-50, 100), 1e-6);
}
[TestMethod]
public void AM_004_分配_授信充足_全额授信()
{
var (credit, cash) = SwapAdditionalMarginCalc.Allocate(80, 100);
Assert.AreEqual(80, credit, 1e-6);
Assert.AreEqual(0, cash, 1e-6);
}
[TestMethod]
public void AM_005_分配_授信不足_拆为授信加现金()
{
var (credit, cash) = SwapAdditionalMarginCalc.Allocate(80, 30);
Assert.AreEqual(30, credit, 1e-6);
Assert.AreEqual(50, cash, 1e-6);
}
[TestMethod]
public void AM_006_分配_无授信_全额现金()
{
var (credit, cash) = SwapAdditionalMarginCalc.Allocate(80, 0);
Assert.AreEqual(0, credit, 1e-6);
Assert.AreEqual(80, cash, 1e-6);
}
[TestMethod]
public void AM_007_分配_新增为零或负_不产生()
{
Assert.AreEqual((0d, 0d), SwapAdditionalMarginCalc.Allocate(0, 100));
Assert.AreEqual((0d, 0d), SwapAdditionalMarginCalc.Allocate(-5, 100));
}
/// <summary>
/// 幂等与跨日增量(资金记录存累计值的口径验证):
/// 第1日 维持180/应付100 → 新增80;第2日 维持不变、已补足80 → 新增0(重跑不写);
/// 第3日 维持升到200 → 目标100 − 已补足80 = 新增20(记录累计值更新为100,历史增量自然承载)。
/// </summary>
[TestMethod]
public void AM_008_跨日增量与幂等()
{
double fundedCash = 0, fundedCredit = 0;
var payableNet = 100d;
var day1 = Math.Round(SwapAdditionalMarginCalc.CalcTarget(180, payableNet) - fundedCash - fundedCredit, 2, MidpointRounding.AwayFromZero);
Assert.AreEqual(80, day1, 1e-6);
var (c1, m1) = SwapAdditionalMarginCalc.Allocate(day1, 30);
fundedCredit += c1;
fundedCash += m1;
Assert.AreEqual(30, fundedCredit, 1e-6);
Assert.AreEqual(50, fundedCash, 1e-6);
//重跑同日:目标/已补足不变 → 新增 0
var day1Rerun = Math.Round(SwapAdditionalMarginCalc.CalcTarget(180, payableNet) - fundedCash - fundedCredit, 2, MidpointRounding.AwayFromZero);
Assert.AreEqual(0, day1Rerun, 1e-6);
//第2日 维持不变 → 已补足=目标 → 新增 0
var day2 = Math.Round(SwapAdditionalMarginCalc.CalcTarget(180, payableNet) - fundedCash - fundedCredit, 2, MidpointRounding.AwayFromZero);
Assert.AreEqual(0, day2, 1e-6);
//第3日 维持上升 → 只补差额
var day3 = Math.Round(SwapAdditionalMarginCalc.CalcTarget(200, payableNet) - fundedCash - fundedCredit, 2, MidpointRounding.AwayFromZero);
Assert.AreEqual(20, day3, 1e-6);
}
/// <summary>
/// 授信垫付的初始预付金计入已缴(2026-08-27 修正,交易2538实证):
/// 初始预付金走授信腿不产生应付预付金流水(现金净收额=0),已缴初始=授信初始占用净额——
/// 目标追加 = 维持 −(现金净收额+初始授信占用净额),否则每个结算日按维持全额重复开追加。
/// </summary>
[TestMethod]
public void AM_009_授信初始预付金计入已缴_不重复追加()
{
//交易2538 首日实际数据:维持2,808,000;初始预付金2,000,000全走授信(现金净收额0)
var payableNetCash = 0d;
var initCreditNet = 2_000_000d;
var target = SwapAdditionalMarginCalc.CalcTarget(2_808_000, payableNetCash + initCreditNet);
Assert.AreEqual(808_000, target, 1e-6);
//对照:修正前只扣现金净收额 → 目标2,808,000 全额追加(多收2,000,000 授信占用,即本BUG
}
/// <summary>
/// 追保回落(维持下降到应付之下)不返还:目标为 0 → 已补足保持,新增 0;
/// 超付部分由可用资金公式的负缺口(Σ维持−累计)体现,不产生返还记录。
/// </summary>
[TestMethod]
public void AM_009_追保回落不返还()
{
var target = SwapAdditionalMarginCalc.CalcTarget(50, 100);
Assert.AreEqual(0, target, 1e-6);
var (credit, cash) = SwapAdditionalMarginCalc.Allocate(target - 80, 100);
Assert.AreEqual(0, credit, 1e-6);
Assert.AreEqual(0, cash, 1e-6);
}
/// <summary>
/// 追加保证金授信出入记录的 remark 前缀识别(RemoveByTrade 保留判定与累计口径共用)。
/// </summary>
[TestMethod]
public void AM_010_追加保证金记录识别()
{
Assert.IsTrue(ClientCreditInoutService.IsAdditionalMarginRecord(
new client_credit_inout { change_type = client_credit_inout.ChangeTypeOccupy, remark = "追加保证金占用" }));
Assert.IsFalse(ClientCreditInoutService.IsAdditionalMarginRecord(
new client_credit_inout { change_type = client_credit_inout.ChangeTypeOccupy, remark = "簿记授信占用" }));
Assert.IsFalse(ClientCreditInoutService.IsAdditionalMarginRecord(
new client_credit_inout { remark = null }));
}
}
}