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 金融計算》系列合集


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM