zoukankan      html  css  js  c++  java
  • QuantLib 金融计算——原理之 Bootstrap

    以下文字源自我对源代码的理解,如有不同意见,欢迎留言讨论或发邮件(xuruilong100@163.com

    QuantLib 金融计算——原理之 Bootstrap

    这次新开一个系列,不讲应用案例了,尝试介绍 QuantLib 某些核心功能背后的代码逻辑与数学原理。

    Bootstrap 的原理

    通过合约报价推算期限结构的过程称为“bootstrap”,其思想和实践非常类似于理论证明中用到的“数学归纳法”,大体过程如下:

    1. 首先将要用到的已知利率和金融工具根据期限升序排列;
    2. 假设已经求得期限结构上的第 (n) 个值——(TS_n),对应于第 (n) 个报价;
    3. (TS_{n+1}) 是个待定参数 (x),并给定一个初值;
    4. 用已知的期限结构数据——(TS_1,dots,TS_n,x),对第 (n+1) 个金融工具进行估值;
    5. 调整 (x),使得估值结果与报价达到一致;
    6. 此时,(x) 便是要求解的 (TS_{n+1})
    7. 以此类推。

    其中 (TS) 可以是即期利率、远期利率、贴现因子三者中的任意一个,而可用的插值方法也有线性插值、样条插值、对数线性插值和常数插值等等。两个维度相互搭配可以产生非常多的组合,QuantLib 通过模板技术实现两个维度的自由搭配,具体选择哪种组合要视业务需要而定。

    其他问题语境下的 bootstrap 计算原理类似。

    QuantLib 中的 bootstrap 计算(利率语境)

    要在 QuantLib 中 bootstrap 出一条利率曲线所涉及的最核心的类有两个:

    • 直接调用的类是 PiecewiseYieldCurve 模板类,它直接接受一组报价;
    • 另外一个间接调用的类是 IterativeBootstrap 模板类,作为 PiecewiseYieldCurve 的默认模板参数。

    PiecewiseYieldCurve 需要三个模板参数,前两个分别确定底层数据和插值方法的选择。比如说 PiecewiseYieldCurve<Discount, LogLinear> 表示程序内部 bootstrap 出一条贴现因子曲线,用对数线性法插值得到任意日期上的利率值。

    IterativeBootstrapPiecewiseYieldCurve 需要的第三个模板参数,并且是默认选项。它本身就是个模板类,而它的模板参数正是实例化后的 PiecewiseYieldCurve。C++ 模板就是这么神奇!

    在整个 bootstrap 计算过程中,实际出苦力的类是 IterativeBootstrap,它负责从若干金融工具的报价数据中迭代地求解出利率曲线,而 PiecewiseYieldCurve 则是充当 Boss 的角色。

    核心代码细节

    现在来看看 QuantLib 具体怎么实现 bootstrap 的。

    通过一些模板技巧,PiecewiseYieldCurve 其实是 YieldTermStructure 的派生类,所以它最核心的方法是 discountImpl(要了解这一点,请阅读《构建 QuantLib》)。

    DiscountFactor PiecewiseYieldCurve<C,I,B>::discountImpl(Time t) const
    {
        calculate();
        return base_curve::discountImpl(t);
    }
    

    在返回数据之前,PiecewiseYieldCurve 会先调用 calculate,bootstrap 的计算就发生在这里。

    PiecewiseYieldCurvecalculate 方法直接复用其基类 LazyObjectcalculate 方法。这里应用了“模板方法模式”,calculate 只起到传达命令的作用,实际的计算任务被重新委派回了 PiecewiseYieldCurveperformCalculations 方法。

    void PiecewiseYieldCurve<C,I,B>::performCalculations() const
    {
        // just delegate to the bootstrapper
        bootstrap_.calculate();
    }
    

    performCalculations 方法中 IterativeBootstrap 的一个实例 bootstrap_ 最终执行所有计算。

    尽管 IterativeBootstrapcalculate 方法代码很长,但毛教员教育我们分析问题要“抓大放小”,其实最核心的代码只有两行,

    if (validData)
        solver_.solve(*errors_[i], accuracy, guess, min, max);
    else
        firstSolver_.solve(*errors_[i], accuracy, guess, min, max);
    

    solver_firstSolver_ 分别是 BrentFiniteDifferenceNewtonSafe 对象,用于求解(非)线性函数的根,也就是求解利率。

    errors_[i] = ext::shared_ptr<BootstrapError<Curve> >(
        new BootstrapError<Curve>(ts_, helper, i));
    

    errors_BootstrapError 对象,也是一个函数对象,它负责返回估值结果与实际报价之间的差距,充当待求解的(非)线性函数。

    const ext::shared_ptr<typename Traits::helper>& helper = ts_->instruments_[j];
    

    helper 就是某个传递给 PiecewiseYieldCurve 的报价对象,在利率语境下通常是 FraRateHelperSwapRateHelperXXXRateHelper 对象,这些 XXXRateHelper 类专门用于 bootstrap 计算。

    上述代码便是 QuantLib 对 bootstrap 原理的实现。

    开放问题:如何实现 FR007 互换的相关分析?

    利率互换的分析分为两大类:

    1. 对存续合约估计、计算敏感性等;
    2. 根据最新合约的报价推算利率期限结构。

    FR007 互换的现金流结构和普通的利率互换(例如 Shibor3M 互换)基本一致,每隔三个月交换现金流,但确定浮动端利率的方式有不同。在三个月的付息区间内 FR007 利率要每隔七天确定一次,付息区间内的若干 FR007 利率还需要经过某些计算才能最终确定浮动端利率。

    根据上述代码的分析,要想最大限度的复用当前逻辑并最小程度的编写代码,需要在 helper 上做文章,可以考虑实现 SwapRateHelper 的兄弟类 FR007SwapRateHelper,以及配套的 FR007Swap 类(作为 VanillaSwap 的派生类或兄弟类)。

    QuantLib 当前实现的 ArithmeticAverageOISArithmeticOISRateHelper 也许是非常值得效仿的范例。

    下一步将尝试按照上述思路实现 C++ 代码。

    扩展阅读

    《QuantLib 金融计算》系列合集

    ★ 持续学习 ★ 坚持创作 ★
  • 相关阅读:
    NodeJs使用Mysql模块实现事务处理
    Javascript(JS)对Cookie的读取、删除、写入操作帮助方法
    SLERP 导数
    General matrix representations for B-splines 论文理解
    搭建私人实体编译服务器
    A Micro Lie Theory 论文理解
    [备忘,无新意] undistort (求反函数对某个值的映射)使用迭代优化方法
    Dual Quaternion representing Rigid Transformation
    B 样条曲线的 SE(3) 应用
    [ceres-solver] From QuaternionParameterization to LocalParameterization
  • 原文地址:https://www.cnblogs.com/xuruilong100/p/14310633.html
Copyright © 2011-2022 走看看