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