Files
zszq-trs/UnitTestProject/Modules/SwapModule/GreeksBumpCalculatorTests.cs
T
hjhan 985162242d feat(greeks): 新增 risk-factor bump 计算与注册
ParameterBase.Clone() 保留运行时类型深拷贝; ValueCalculator 两个薄接入方法; GreeksBumpCalculator/GreeksRiskFactor 引擎。加法性重定价桥,不动现有定价输出。
2026-07-21 15:28:15 +08:00

115 lines
5.2 KiB
C#
Raw 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.BLL.Calculation.V2;
namespace UnitTestProject.Modules.SwapModule
{
/// <summary>
/// GreeksBumpCalculator 纯数学契约测试(先写,锁定 ε / 差分逻辑)。
/// 不碰 DB / QDP:用已知解析导数的函数(f(x)=x²,d/dx=2x,d²/dx²=2)验证中心差分本身正确。
/// 业务侧集成测试(真实定价路径 + 真实 FR007)见后续 ValueCalculator 薄接入落地后再补。
/// </summary>
[TestClass]
public class GreeksBumpCalculatorTests
{
/// <summary>
/// 一阶中心差分对 f(x)=x² 在 x=3 应精确等于 2x=6。
/// 二次多项式的中心差分对任意 ε 都精确(截断误差为 0),因此用相对步长 0.05% 仍得 6。
/// </summary>
[TestMethod]
public void CentralDelta_of_x2_equals_2x()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x; // d/dx = 2x
var delta = calc.Delta(f, 3m, BumpSpec.Relative(0.0005m));
Assert.AreEqual(6m, delta);
}
/// <summary>
/// 二阶中心差分对 f(x)=x² 在 x=3 应精确等于 2(二阶导数恒为 2)。
/// 验证 Gamma 的二阶差分算子正确。
/// </summary>
[TestMethod]
public void CentralGamma_of_x2_equals_2()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x; // d²/dx² = 2
var gamma = calc.Gamma(f, 3m, BumpSpec.Relative(0.0005m));
Assert.AreEqual(2m, gamma);
}
/// <summary>
/// 1BP 变体(Dollar Greek)对 f(x)=x² 在 x=3、bump 1bp 应等于 (3.0001)² - 3²。
/// 验证 BumpPv1Bp 直接前向 bump 的 PV 差逻辑。
/// </summary>
[TestMethod]
public void BumpPv1Bp_of_x2_forward()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x;
var bumped = calc.BumpPv1Bp(f, 3m);
Assert.AreEqual(3.0001m * 3.0001m - 3m * 3m, bumped);
}
/// <summary>
/// 线性函数 f(x)=2x+1:一阶中心差分应精确等于斜率 2,二阶中心差分应精确为 0(线性无曲率)。
/// 验证算子对"一次/零次"函数的精确性(二次之外另一种精确情形)。
/// </summary>
[TestMethod]
public void CentralDelta_of_linear_is_slope()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => 2m * x + 1m; // d/dx = 2, d²/dx² = 0
Assert.AreEqual(2m, calc.Delta(f, 5m, BumpSpec.Relative(0.0005m)));
Assert.AreEqual(0m, calc.Gamma(f, 5m, BumpSpec.Relative(0.0005m)));
}
/// <summary>
/// 三次函数 f(x)=x³:中心差分对任意 ε 不精确(仅二次及以下精确),结果逼近解析导 3x² 但有 O(ε²) 误差。
/// 验证 Layer B 集成测试必须带容差,不能 Assert.AreEqual 死等精确值。x=2 解析导=12。
/// </summary>
[TestMethod]
public void CentralDelta_of_cubic_is_approx_analytic_with_tolerance()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x * x; // d/dx = 3x² = 12 at x=2
var delta = calc.Delta(f, 2m, BumpSpec.Relative(0.0005m));
Assert.IsTrue(Math.Abs(delta - 12m) < 0.001m, $"中心差分三次函数应有 O(ε²) 误差,实际={delta}");
}
/// <summary>
/// 扭结点测试:看涨 payoff f(x)=max(x-3,0) 在行权价 x=3 处不可导。
/// 中心差分跨扭结取到左右斜率的平均 (0+1)/2 = 0.5,说明对障碍/美式等扭结结构必须用单边差分。
/// </summary>
[TestMethod]
public void CentralDelta_at_kink_is_average_of_one_sided()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x > 3m ? x - 3m : 0m; // call payoff K=3
var delta = calc.Delta(f, 3m, BumpSpec.Relative(0.0005m));
Assert.AreEqual(0.5m, delta); // 中心差分给出左右斜率平均,非真实单边 Greek
}
/// <summary>
/// 边界 x=0(相对步长会触到 Floor):f(x)=x² 在 0 处对称,Δ 应精确为 0,证明 Floor 兜底不产生噪声。
/// </summary>
[TestMethod]
public void CentralDelta_at_zero_uses_floor_but_stays_correct()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x;
Assert.AreEqual(0m, calc.Delta(f, 0m, BumpSpec.Relative(0.0005m)));
}
/// <summary>
/// 利率量级小值 x=0.00011bp 量级)用相对步长:Resolve 返回 max(0.0001·0.0005, 1e-8)=5e-8
/// 远大于 Floor,证明利率类小量级不会被舍入噪声吞掉。f=x² 在 0.0001 解析导=2·0.0001=0.0002。
/// </summary>
[TestMethod]
public void CentralDelta_of_tiny_rate_like_x_is_stable()
{
var calc = new GreeksBumpCalculator();
Func<decimal, decimal> f = x => x * x;
Assert.AreEqual(0.0002m, calc.Delta(f, 0.0001m, BumpSpec.Relative(0.0005m)));
}
}
}