using System; namespace YLErp.BLL.Calculation.V2 { /// /// 风险因子种类,用于后续 ValueCalculator 薄接入层签名(CalcPvAtBumpedRiskFactor)。 /// 当前 GreeksBumpCalculator 纯类本身不依赖它,仅作为对外契约的一部分。 /// public enum RiskFactorKind { /// 标的价 S Price, /// 无风险利率 r Rate, /// 波动率 σ Volatility } /// /// 扰动步长规格:决定有限差分用的 ε。 /// /// Relative:ε = max(|x| * Value, Floor),适合指数等大量级标的,避免绝对 1bp 落入浮点舍入区。 /// Absolute:ε = Value,等价系统现行“标的价格偏移绝对 1bp”的做法。 /// /// 默认 Floor 极小,仅防止 x=0 时 ε=0 导致除零。 /// public readonly struct BumpSpec { /// 步长模式 public enum Mode { /// 相对步长(推荐,量级自适应) Relative, /// 绝对步长 Absolute } /// 步长模式 public Mode Kind { get; } /// 步长数值(Relative 时为相对比例,Absolute 时为绝对量) public decimal Value { get; } /// 相对步长下限(防止 |x| 过小导致 ε→0) public decimal Floor { get; } /// 构造步长规格 public BumpSpec(Mode kind, decimal value, decimal floor = 0.00000001m) { Kind = kind; Value = value; Floor = floor; } /// 相对步长(value 为相对比例,如 0.0005m = 0.05%) public static BumpSpec Relative(decimal value) => new(Mode.Relative, value); /// 绝对步长(value 为绝对量,如 0.0001m = 1bp) public static BumpSpec Absolute(decimal value) => new(Mode.Absolute, value); /// 把规格解析成实际 ε(用 decimal,避免 double 精度漂移) public decimal Resolve(decimal x) { if (Kind == Mode.Absolute) return Value; var eps = Math.Abs(x) * Value; return eps < Floor ? Floor : eps; } } /// /// 有限差分希腊字母计算引擎(纯函数,不依赖 QDP / DB)。 /// /// 通过委托 pv(bumpedFactor) 取得“风险因子被扰动到某值时的衍生品价值”, /// 再用中心差分估算一阶 / 二阶导。这是仓库层对 Greeks 口径的显式控制点, /// 可绕开 QDP 内部黑盒的步长 / 差分选择,并解决指数类标的使用绝对 1bp 步长失真的口径问题。 /// /// /// 用法:业务侧把“价格 / 利率 / 波动率”各自封装成一个 Func<decimal,decimal> 委托传给本类; /// Delta/Gamma/Vega/Rho 等命名方法数学上都是同一差分算子,仅扰动的风险因子不同。 /// /// public sealed class GreeksBumpCalculator { /// 一阶中心差分 Δ = [PV(x+ε) - PV(x-ε)] / (2ε),误差 O(ε²) public decimal FirstOrderCentral(Func pv, decimal x, BumpSpec bump) { ArgumentNullException.ThrowIfNull(pv); var eps = bump.Resolve(x); return (pv(x + eps) - pv(x - eps)) / (2m * eps); } /// 二阶中心差分 Γ = [PV(x+ε) - 2·PV(x) + PV(x-ε)] / ε²,误差 O(ε²) public decimal SecondOrderCentral(Func pv, decimal x, BumpSpec bump) { ArgumentNullException.ThrowIfNull(pv); var eps = bump.Resolve(x); return (pv(x + eps) - 2m * pv(x) + pv(x - eps)) / (eps * eps); } // —— 以下为按业务希腊字母命名的暴露,数学上都是上面两个差分算子,仅扰动因子不同 —— /// Delta:对标的价 S 的一阶中心差分 public decimal Delta(Func pv, decimal s, BumpSpec bump) => FirstOrderCentral(pv, s, bump); /// Gamma:对标的价 S 的二阶中心差分 public decimal Gamma(Func pv, decimal s, BumpSpec bump) => SecondOrderCentral(pv, s, bump); /// Vega:对波动率 σ 的一阶中心差分 public decimal Vega(Func pv, decimal sigma, BumpSpec bump) => FirstOrderCentral(pv, sigma, bump); /// Vega_r:对波动率 σ 的一阶中心差分(需求命名变体,等价于 Vega) public decimal VegaR(Func pv, decimal sigma, BumpSpec bump) => FirstOrderCentral(pv, sigma, bump); /// Rho:对无风险利率 r 的一阶中心差分 public decimal Rho(Func pv, decimal r, BumpSpec bump) => FirstOrderCentral(pv, r, bump); /// Delta_r:对无风险利率 r 的一阶中心差分(需求命名变体,等价于 Rho) public decimal DeltaR(Func pv, decimal r, BumpSpec bump) => FirstOrderCentral(pv, r, bump); /// Gamma_r:对无风险利率 r 的二阶中心差分 public decimal GammaR(Func pv, decimal r, BumpSpec bump) => SecondOrderCentral(pv, r, bump); /// /// 1BP 变体(Dollar Greek):直接前向 bump 1bp 的 PV 差 = PV(x+1bp) - PV(x),不除 ε,量纲为金额。 /// 对应需求中的 Delta_r(1BP) / Gamma_r(1BP) / Vega_r(1BP)。 /// public decimal BumpPv1Bp(Func pv, decimal x, decimal oneBp = 0.0001m) { ArgumentNullException.ThrowIfNull(pv); return pv(x + oneBp) - pv(x); } } }