QuantLib 金融計算——案例之普通利率互換分析(3)
基本解決了一直想解決的問題,牛年開局良好 😃
哈皮牛耶
概述
下面嘗試實現 FR007 互換的分析。
相關組件
對比 OvernightIndexedSwap
,分析 FR007 互換用到了如下幾個類:
ChinaFixingRepo
(對應OvernightIndex
),存儲定盤回購利率的相關信息,包括名稱、期限、計息規則等,這些信息在構造互換對象內部也會直接或間接地用到。ChinaFixingRepoCoupon
(對應OvernightIndexedCoupon
),用來表示某一期的浮動現金流。內部會持有一個ChinaFixingRepoCouponPricer
對象。ChinaFixingRepoCouponPricer
(對應OvernightIndexedCouponPricer
),為ChinaFixingRepoCoupon
對象確定浮動利率。ChinaFixingRepoLeg
(對應OvernightLeg
),根據日期表生成浮動現金流,也就是一個ChinaFixingRepoCoupon
的向量,存儲在ChinaFixingRepoSwap
對象中。ChinaFixingRepoSwap
(對應OvernightIndexedSwap
),表示定盤回購利率相關的互換,是OvernightIndexedSwap
和VanillaSwap
的兄弟類,同屬Swap
的派生類,考慮到 FR007 互換的經濟含義,ChinaFixingRepoSwap
成員函數更接近VanillaSwap
。MakeChinaFixingRepoSwap
(對應MakeOIS
),是創建ChinaFixingRepoSwap
的工廠類。ChinaFixingRepoSwapRateHelper
(對應OISRateHelper
),用於根據 FR007 互換的報價進行 bootstrap。
以上各個組件的實現可以查看 QuantLibEx 中的同名文件。
測試組件
測試 ChinaFixingRepoCouponPricer
下面以文檔《人民幣利率互換的定價模型》中圖 9 的結果作基准,測試 ChinaFixingRepoCouponPricer
能否正確的推算出浮動利率。完整的實現請查看 TestChinaFixingRepoCoupon
函數。
圖 9 的結果
測試代碼中用到了 QuantLib 中的另一個“單體”——IndexManager
,用戶可以根據它統一管理各種利率的歷史數據,因為 fixing 的過程可能涉及到去數據庫調用歷史數據,特別是在 OIS 和 FR007 互換的語境下。
錄入 FR007 的歷史數據:
ext::shared_ptr<ChinaFixingRepo> fr(
new ChinaFixingRepo(
Period(7, Days),
fixingDays));
vector<Date> dates = {
Date(27, July, 2018),
Date(3, August, 2018),
Date(10, August, 2018),
Date(17, August, 2018),
Date(24, August, 2018),
Date(31, August, 2018),
Date(7, September, 2018),
Date(14, September, 2018),
Date(21, September, 2018),
Date(30, September, 2018),
Date(12, October, 2018),
Date(19, October, 2018),
Date(26, October, 2018)};
vector<Rate> fwds = {
2.8 / 100.0,
2.4 / 100.0,
2.29 / 100.0,
2.65 / 100.0,
2.5 / 100.0,
2.66 / 100.0,
2.69 / 100.0,
2.6 / 100.0,
2.65 / 100.0,
2.76 / 100.0,
2.6 / 100.0,
2.61 / 100.0,
2.65 / 100.0};
TimeSeries<Real> ts(dates.begin(), dates.end(), fwds.begin());
IndexManager::instance().setHistory(fr->name(), ts);
輸出浮動利率和日期:
cout << coupon.rate() << endl;
size_t n = coupon.fixingDates().size();
for (size_t i = 0; i < n; ++i) {
cout << setw(15) << coupon.fixingDates()[i]
<< setw(15) << coupon.valueDates()[i] << endl;
}
0.0262145
July 27th, 2018 July 30th, 2018
August 3rd, 2018 August 6th, 2018
August 10th, 2018 August 13th, 2018
August 17th, 2018 August 20th, 2018
August 24th, 2018 August 27th, 2018
August 31st, 2018 September 3rd, 2018
September 7th, 2018 September 10th, 2018
September 14th, 2018 September 17th, 2018
September 21st, 2018 September 24th, 2018
September 30th, 2018 October 1st, 2018
September 30th, 2018 October 8th, 2018
October 12th, 2018 October 15th, 2018
October 19th, 2018 October 22nd, 2018
October 26th, 2018 October 29th, 2018
結果完全符合預期,無論是利率還是日期,結果都是對的。
測試 ChinaFixingRepoSwap
下面以文檔《利率互換貼現因子曲線的構造模型》中圖 12 的結果作基准,測試 ChinaFixingRepoSwap
的運行是否正確。完整的實現請查看 TestChinaFixingRepoSwap
函數。
圖 12 的結果
以 10 年期互換為例(CNYFR_S10Y),若采用圖中的期限結構定價互換合約,其 NPV 將會等於零或者極為接近零(相對於互換的本金而言)。
cout << swap.NPV() / 10000000.0 * 100.0 << '%' << endl;
cout << swap.fixedLegNPV() / 10000000.0 * 100.0 << '%' << endl;
cout << swap.floatingLegNPV() / 10000000.0 * 100.0 << '%' << endl;
0.00340699%
-27.3602%
27.3636%
NPV 並未等於零,但相對於合約面值而言已經很接近於零。差異原因稍候解釋。
測試 Bootstrap
依然是以文檔《利率互換貼現因子曲線的構造模型》中圖 12 的結果作基准,測試 ChinaFixingRepoSwapRateHelper
的運行是否正確。完整的實現請查看 ChinaFixingRepoSwapCurve
函數,代碼實現與 ShiborIRScurve
幾乎一致。
運行結果:
Today: January 21st, 2020
Settlement date: January 22nd, 2020
13, 0.99907852, 2.5884391
34, 0.99759776, 2.5819802
92, 0.99355973, 2.5633687
183, 0.98719415, 2.570667
275, 0.98071798, 2.5842461
367, 0.9742452, 2.5950071
734, 0.94794334, 2.6584605
1098, 0.92102612, 2.7347369
1462, 0.89302652, 2.8246057
1828, 0.86428623, 2.9122383
2558, 0.80737256, 3.0531303
3654, 0.72642071, 3.1927605
結果與基准相比並不吻合,特別是日期的計算,但數值值已經非常接近。差異原因稍候解釋。
差異可能的來源
相比於 ShiborIRScurve
的測試結果,這次 ChinaFixingRepoSwapCurve
的結果與基准差異較大。究其原因,可能是因為工作日轉換規則是 MFL,對假期比較敏感,而這次的估值日期安排 在公歷 1 月下旬,更容易受到農歷春節七天長假的影響。
QuantLib 中包含中國假期的日歷類是 China
,不過它對中國農歷假期的維護並不完善,所以它所記錄的假期很可能和建信金科系統的假期不一致。
另一個可能的原因是 bootstrap 中缺少 FR001 和 FR014 的報價。