文章

QuantLib 金融计算——原理之有限差分法(FDM)

介绍 QuantLib 中有限差分法的代码架构。

QuantLib 金融计算——原理之有限差分法(FDM)

概述

如果 Monte Carlo 定价方法的复杂程度相当于一台汽车发动机,有限差分(FDM)定价方法的复杂程度无疑相当于一台航空发动机。

FDM 的基本结构

怎样用 FDM 求解衍生品定价问题?

首先,要有描述衍生品价格的 PDE,包括边界条件、初始状态中间事件(例如支付股息)等等。

其次,在一个充分大的闭区间内划定网格,在网格上构造 PDE 的离散近似。

第三,规定合适的求解格式,例如隐式欧拉格式和 Crank-Nicolson 格式,求解格式、网格上的离散近似和边界条件共同决定了一系列数值线性代数问题。逐一迭代求解数值线性代数问题就可以最终得到衍生品的定价。

QuantLib 中的 FDM

由于 FDM 的复杂程度远大于 Monte Carlo,在这种情况下,相较于类的“继承”,类的“组合”才是一个更合适的选择。因此 QuantLib 中的 FDM 定价引擎没有采用“模板方法模式”,而是根据 FDM 的基本结构归纳总结出若干独立组件,将不同的组件拼合在一起,最终形成一个定价引擎。

尽管不存在一个基类来控制所有计算过程,FDM 定价引擎却有一条共同的“求解链条”。

FdBlackScholesVanillaEngineFdHestonVanillaEngine 为例,定价计算分别委托给了 FdmBlackScholesSolverFdmHestonSolver。两个 Solver 再各自将计算任务委托给 Fdm1DimSolverFdm2DimSolver。无论是一维、二维、三维还是 N 维的 Solver,计算任务统一委托给 FdmBackwardSolverFdmBackwardSolver再委托给 FiniteDifferenceModel。特定的定价引擎仅负责构造出合适的“组件”对象,并将组件拼合在一起形成一个 Solver,最终是 FiniteDifferenceModel 直接或间接调用各个组件完成定价计算。

graph TD;

FdBlackScholesVanillaEngine --> FdmBlackScholesSolver;
FdHestonVanillaEngine --> FdmHestonSolver;

FdmBlackScholesSolver --> Fdm1DimSolver;
FdmHestonSolver --> Fdm2DimSolver;

Fdm1DimSolver --> FdmBackwardSolver;
Fdm2DimSolver --> FdmBackwardSolver;

FdmBackwardSolver --> FiniteDifferenceModel;

下面以 FdHestonVanillaEngine 为例展示主要组件之间的关系。

graph TD;

Fdm2DimSolver -.- FdmHestonSolver;

FdmSolverDesc --> Fdm2DimSolver;
FdmLinearOpComposite --> Fdm2DimSolver;
FdmSchemeDesc --> Fdm2DimSolver;

FdmMesher --> FdmLinearOpComposite;

FdmBoundaryConditionSet --> FdmSolverDesc;
FdmStepConditionComposite --> FdmSolverDesc;
FdmInnerValueCalculator --> FdmSolverDesc;
FdmMesher --> FdmSolverDesc;

FdmLinearOpLayout --> FdmMesher;
Fdm1dMesher --> FdmMesher;

BoundaryCondition -.- FdmBoundaryConditionSet;

FdmMesher --> FdmInnerValueCalculator;

FdmLinearOpIterator -.- FdmLinearOpLayout;

StepCondition -.- FdmStepConditionComposite;

FdmLinearOp -.- BoundaryCondition;

若干格式 -.- FdmSchemeDesc

FdmSchemeDesc 用于描述“求解格式”,FiniteDifferenceModel 会根据 FdmSchemeDesc 构造出特定的求解格式(例如隐式欧拉格式和 Crank-Nicolson 格式),求解格式决定了以何种方式求解数值线性代数问题。

FdmLinearOpComposite 是基类的名称,它的派生类 FdmHestonOp 描述如何对 Heston PDE 做离散近似(这也就是为什么配置 FdmLinearOpComposite 需要用 FdmMesher)。

FdmSolverDesc 的配置是最复杂的,因为它具体地描述如何求解一个 PDE,因此它需要 FdmBoundaryConditionSetFdmStepConditionCompositeFdmInnerValueCalculatorFdmMesher,分别用来描述边界条件、步骤条件(例如支付股息)、初始值计算和网格划分。

FdmMesher 是基类的名称,最常用的是它的派生类 FdmMesherComposite。如果需要描述二维网格的话,FdmMesherComposite 要接受两个 Fdm1dMesher 对象,分别描述各自维度上的网格如何划分。

在求解数值线性代数问题时,状态价格以一维向量的形式出现,而 Heston PDE 是两维的。如何操纵网格,将状态价格切片(一个二维的平面)映射成一维向量是 PDE 数值解过程中最精巧的部分。完成这一步就需要用到 FdmLinearOpIteratorFdmLinearOpLayoutFdmLinearOpLayout 可以描述多维网格上点与点之间的相邻关系,借助 FdmLinearOpIterator 则可以遍历一个多维网格。

FDM 与 Autocall

怎样扩展当前的架构以适应 Autocall Note 的估值?

Autocall Note 的特点是在一系列离散的观察日期(通常间隔一个月)上设置障碍值,当标的价格突破障碍时则会支付相应的票息。很显然,Autocall Note 支付票息的这种行为是一种 Step Condition,因此可以编写一个 StepCondition 的派生类来模拟观察日期上支付票息的行为。

当前的架构存在一个特殊概念——阻尼,也就是 Rannacher 平滑(文献【1】), FiniteDifferenceModel 在计算状态价格的时候,如果遇到非平滑的输入就直接采用隐式欧拉格式求解 PDE,其他情况下依然按照事先设定的求解格式。

常见的期权仅在到期日这一天会出现不平滑的状态价格,所以当前的架构设计成阻尼仅作用于初始计算阶段。Autocall Note 支付票息的行为却会在求解过程中多次制造出不平滑的状态价格,因此需要修改 FiniteDifferenceModel 以支持连续使用 Rannacher 平滑,这并不是难事。

启发

另一个流行的 Autocall Note 定价法是积分法(文献【2】),积分法在形式上和 FDM 非常相似,现有 FDM 框架归纳出的组件和流程也很有普适意义,因此可以参考 FDM 的代码实现为积分法设计一个通用框架。

参考文献

【1】Luskin, Mitchell, et al. “On the Smoothing Property of the Crank-Nicolson Scheme.” Applicable Analysis, vol. 14, no. 2, Jan. 1982, pp. 117–35. DOI.org (Crossref), https://doi.org/10.1080/00036818208839415. 【2】Huang, Min, and Guo Luo. “A Simple and Efficient Numerical Method for Pricing Discretely Monitored Early-Exercise Options.” Applied Mathematics and Computation, vol. 422, June 2022, p. 126985. DOI.org (Crossref), https://doi.org/10.1016/j.amc.2022.126985.

本文由作者按照 CC BY 4.0 进行授权