文章

QuantLib 金融计算——案例之普通利率互换分析(2)

介绍用 QuantLib 对 FR007 互换合约估值。

由于版本问题,代码可能与最新版不兼容。

QuantLib 金融计算——案例之普通利率互换分析(3):FR007 互换分析

基本解决了一直想解决的问题,牛年开局良好 :)

哈皮牛耶

概述

下面尝试实现 FR007 互换的分析。

相关组件

对比 OvernightIndexedSwap,分析 FR007 互换用到了如下几个类:

  • ChinaFixingRepo(对应 OvernightIndex),存储定盘回购利率的相关信息,包括名称、期限、计息规则等,这些信息在构造互换对象内部也会直接或间接地用到。
  • ChinaFixingRepoCoupon(对应 OvernightIndexedCoupon),用来表示某一期的浮动现金流。内部会持有一个 ChinaFixingRepoCouponPricer 对象。
  • ChinaFixingRepoCouponPricer(对应 OvernightIndexedCouponPricer),为 ChinaFixingRepoCoupon 对象确定浮动利率。
  • ChinaFixingRepoLeg(对应 OvernightLeg),根据日期表生成浮动现金流,也就是一个 ChinaFixingRepoCoupon 的向量,存储在 ChinaFixingRepoSwap 对象中。
  • ChinaFixingRepoSwap(对应 OvernightIndexedSwap),表示定盘回购利率相关的互换,是 OvernightIndexedSwapVanillaSwap 的兄弟类,同属 Swap 的派生类,考虑到 FR007 互换的经济含义,ChinaFixingRepoSwap 成员函数更接近 VanillaSwap
  • MakeChinaFixingRepoSwap(对应 MakeOIS),是创建 ChinaFixingRepoSwap 的工厂类。
  • ChinaFixingRepoSwapRateHelper(对应 OISRateHelper),用于根据 FR007 互换的报价进行 bootstrap。

以上各个组件的实现可以查看 QuantLibEx 中的同名文件。

测试组件

测试 ChinaFixingRepoCouponPricer

下面以文档《人民币利率互换的定价模型》中图 9 的结果作基准,测试 ChinaFixingRepoCouponPricer 能否正确的推算出浮动利率。完整的实现请查看 TestChinaFixingRepoCoupon 函数。

图 9 的结果

p9

测试代码中用到了 QuantLib 中的另一个“单体”——IndexManager,用户可以根据它统一管理各种利率的历史数据,因为 fixing 的过程可能涉及到去数据库调用历史数据,特别是在 OIS 和 FR007 互换的语境下。

录入 FR007 的历史数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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);

输出浮动利率和日期:

1
2
3
4
5
6
7
8
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

结果完全符合预期,无论是利率还是日期,结果都是对的。

img

测试 ChinaFixingRepoSwap

下面以文档《利率互换贴现因子曲线的构造模型》中图 12 的结果作基准,测试 ChinaFixingRepoSwap 的运行是否正确。完整的实现请查看 TestChinaFixingRepoSwap 函数。

图 12 的结果

p12

以 10 年期互换为例(CNYFR_S10Y),若采用图中的期限结构定价互换合约,其 NPV 将会等于零或者极为接近零(相对于互换的本金而言)。

1
2
3
cout << swap.NPV() / 10000000.0 * 100.0 << '%' << endl;
cout << swap.fixedLegNPV() / 10000000.0 * 100.0 << '%' << endl;
cout << swap.floatingLegNPV() / 10000000.0 * 100.0 << '%' << endl;
1
2
3
0.00340699%
-27.3602%
27.3636%

img

NPV 并未等于零,但相对于合约面值而言已经很接近于零。差异原因稍候解释。

测试 Bootstrap

依然是以文档《利率互换贴现因子曲线的构造模型》中图 12 的结果作基准,测试 ChinaFixingRepoSwapRateHelper 的运行是否正确。完整的实现请查看 ChinaFixingRepoSwapCurve 函数,代码实现与 ShiborIRScurve 几乎一致。

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

img

结果与基准相比并不吻合,特别是日期的计算,但数值值已经非常接近。差异原因稍候解释。

差异可能的来源

相比于 ShiborIRScurve 的测试结果,这次 ChinaFixingRepoSwapCurve 的结果与基准差异较大。究其原因,可能是因为工作日转换规则是 MFL,对假期比较敏感,而这次的估值日期安排 在公历 1 月下旬,更容易受到农历春节七天长假的影响。

QuantLib 中包含中国假期的日历类是 China,不过它对中国农历假期的维护并不完善,所以它所记录的假期很可能和建信金科系统的假期不一致。

另一个可能的原因是 bootstrap 中缺少 FR001 和 FR014 的报价。

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