Swap Curve Construction
在这个示例中,我们将指导用户如何使用平台的功能,完成从利率互换的市场报价完成收益率曲线的构造。
from CAL.PyCAL import *
SetEvaluationDate(Date(2015, 8, 6))
1. 构造收益率曲线
我们从一组市场标准化互换的市场报价中获取收益率曲线的信息:
swap_rates
:标准互换对应的固定端利率swap_tenor
:标准互换对应的期限
swap_rates = [0.02, 0.03, 0.04 ,0.05, 0.055, 0.06, 0.065, 0.07]
swap_tenor = ['6M', '1Y', '2Y', '3Y', '4Y', '5Y', '7Y', '10Y']
shiborIndex = Shibor('3M')
instruments = []
for rate, tenor in zip(swap_rates, swap_tenor):
print('{0:3s} benchmark Shibor Swap fixed at: {1:.2f}%'.format(tenor, rate*100))
rateHelper = ShiborSwapRateHelper(rate, Period(tenor), Frequency.Quarterly, shiborIndex)
instruments.append(rateHelper)
6M benchmark Shibor Swap fixed at: 2.00%
1Y benchmark Shibor Swap fixed at: 3.00%
2Y benchmark Shibor Swap fixed at: 4.00%
3Y benchmark Shibor Swap fixed at: 5.00%
4Y benchmark Shibor Swap fixed at: 5.50%
5Y benchmark Shibor Swap fixed at: 6.00%
7Y benchmark Shibor Swap fixed at: 6.50%
10Y benchmark Shibor Swap fixed at: 7.00%
通过标准互换校正(calibration)收益率曲线:
calibratedCurve = CalibratedYieldCurve(EvaluationDate(), instruments, 'Actual/365 (Fixed)')
收益率曲线的基本信息:
discount
:折现因子forward(%)
:远期利率zero(%)
:零息利率
calibratedCurve.curveProfile().head(10)
date | discount | forward(%) | zero(%) | |
---|---|---|---|---|
2015-08-06 | 2015-08-06 | 1.000000 | 1.994947 | 2.014979 |
2015-09-06 | 2015-09-06 | 0.998307 | 1.994947 | 2.014979 |
2015-10-06 | 2015-10-06 | 0.996672 | 1.994947 | 2.014979 |
2015-11-06 | 2015-11-06 | 0.994984 | 1.994947 | 2.014979 |
2015-12-06 | 2015-12-06 | 0.993354 | 1.994947 | 2.014979 |
2016-01-06 | 2016-01-06 | 0.991672 | 1.994947 | 2.014979 |
2016-02-06 | 2016-02-06 | 0.989994 | 1.994947 | 2.014979 |
2016-03-06 | 2016-03-06 | 0.986950 | 4.014304 | 2.276446 |
2016-04-06 | 2016-04-06 | 0.983591 | 4.014304 | 2.505840 |
2016-05-06 | 2016-05-06 | 0.980351 | 4.014304 | 2.678750 |
我们可以画图来看:
calibratedCurve.curveProfile()['zero(%)'].plot(figsize=(16,8))
<matplotlib.axes.AxesSubplot at 0x6bbabd0>
2. 测试
首先可以看这条收益率曲线是否真的可以完美定价基准互换(perfectly pricing):
cal = Calendar('China.IB')
startDate = cal.advanceDate(Date(2015, 8, 6), '1B', BizDayConvention.Following)
shiborIndex = Shibor('3M', calibratedCurve)
nominal = 100000000.
pricingEngine = DiscountingSwapEngine(calibratedCurve)
for rate, tenor in zip(swap_rates, swap_tenor):
benchmarkSwap = ShiborSwap(SwapLegType.Payer, nominal, startDate, Period(tenor), Period('3M'), rate, shiborIndex)
benchmarkSwap.setPricingEngine(pricingEngine)
print('{0:3s} benchmark Shibor Swap NPV: {1:>8.4f}'.format(tenor, benchmarkSwap.NPV()))
6M benchmark Shibor Swap NPV: 0.0000
1Y benchmark Shibor Swap NPV: -0.0000
2Y benchmark Shibor Swap NPV: 0.0000
3Y benchmark Shibor Swap NPV: 0.0000
4Y benchmark Shibor Swap NPV: -0.0000
5Y benchmark Shibor Swap NPV: 0.0000
7Y benchmark Shibor Swap NPV: 0.0000
10Y benchmark Shibor Swap NPV: 0.0000
然后我们取一个假设已经存在的互换(seasoned swap),通过这条收益率曲线估计它的现值:
startDate = Date(2015, 7, 15)
shiborIndex.addFixing(Date(2015, 7, 14), 0.045)
customizeSwap = ShiborSwap(SwapLegType.Receiver, nominal, startDate, Period('9Y'), Period('3M'), 0.06, shiborIndex)
customizeSwap.setPricingEngine(pricingEngine)
print('{0:3s} Shibor Swap fixed at {1:.2f}% NPV: {2:15.4f}'.format('9Y',6.00, customizeSwap.NPV()))
9Y Shibor Swap fixed at 6.00% NPV: -6308510.5573
customizeSwap.legAnalysis(0).head(10)
AMOUNT | NOMINAL | ACCRUAL_START_DATE | ACCRUAL_END_DATE | ACCRUAL_DAYS | INDEX | FIXING_DAYS | FIXING_DATES | INDEX_FIXING | DAY_COUNTER | ACCRUAL_PERIOD | EFFECTIVE_RATE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
PAYMENT_DATE | ||||||||||||
2015-10-15 | 1512329 | 1e+08 | 2015-07-15 | 2015-10-15 | 92 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2520548 | 0.06 |
2016-01-15 | 1512329 | 1e+08 | 2015-10-15 | 2016-01-15 | 92 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2520548 | 0.06 |
2016-04-15 | 1495890 | 1e+08 | 2016-01-15 | 2016-04-15 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2016-07-15 | 1495890 | 1e+08 | 2016-04-15 | 2016-07-15 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2016-10-17 | 1545205 | 1e+08 | 2016-07-15 | 2016-10-17 | 94 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2575342 | 0.06 |
2017-01-16 | 1495890 | 1e+08 | 2016-10-17 | 2017-01-16 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2017-04-17 | 1495890 | 1e+08 | 2017-01-16 | 2017-04-17 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2017-07-17 | 1495890 | 1e+08 | 2017-04-17 | 2017-07-17 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2017-10-16 | 1495890 | 1e+08 | 2017-07-17 | 2017-10-16 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
2018-01-15 | 1495890 | 1e+08 | 2017-10-16 | 2018-01-15 | 91 | #NA | #NA | #NA | #NA | Actual/365 (Fixed) | 0.2493151 | 0.06 |
customizeSwap.legAnalysis(1).head(10)
AMOUNT | NOMINAL | ACCRUAL_START_DATE | ACCRUAL_END_DATE | ACCRUAL_DAYS | INDEX | FIXING_DAYS | FIXING_DATES | INDEX_FIXING | DAY_COUNTER | ACCRUAL_PERIOD | EFFECTIVE_RATE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
PAYMENT_DATE | ||||||||||||
2015-10-15 | 1150000 | 1e+08 | 2015-07-15 | 2015-10-15 | 92 | Shibor3M Actual/360 | 1 | 2015-07-14 | 0.045 | Actual/360 | 0.2555556 | 0.045 |
2016-01-15 | 504102.3 | 1e+08 | 2015-10-15 | 2016-01-15 | 92 | Shibor3M Actual/360 | 1 | 2015-10-14 | 0.01972574 | Actual/360 | 0.2555556 | 0.01972574 |
2016-04-15 | 871825.4 | 1e+08 | 2016-01-15 | 2016-04-15 | 91 | Shibor3M Actual/360 | 1 | 2016-01-14 | 0.03448979 | Actual/360 | 0.2527778 | 0.03448979 |
2016-07-15 | 1005852 | 1e+08 | 2016-04-15 | 2016-07-15 | 91 | Shibor3M Actual/360 | 1 | 2016-04-14 | 0.03979193 | Actual/360 | 0.2527778 | 0.03979193 |
2016-10-17 | 1234864 | 1e+08 | 2016-07-15 | 2016-10-17 | 94 | Shibor3M Actual/360 | 1 | 2016-07-14 | 0.04729266 | Actual/360 | 0.2611111 | 0.04729266 |
2017-01-16 | 1260227 | 1e+08 | 2016-10-17 | 2017-01-16 | 91 | Shibor3M Actual/360 | 1 | 2016-10-14 | 0.04985512 | Actual/360 | 0.2527778 | 0.04985512 |
2017-04-17 | 1260227 | 1e+08 | 2017-01-16 | 2017-04-17 | 91 | Shibor3M Actual/360 | 1 | 2017-01-13 | 0.04985512 | Actual/360 | 0.2527778 | 0.04985512 |
2017-07-17 | 1260227 | 1e+08 | 2017-04-17 | 2017-07-17 | 91 | Shibor3M Actual/360 | 1 | 2017-04-14 | 0.04985512 | Actual/360 | 0.2527778 | 0.04985512 |
2017-10-16 | 1668056 | 1e+08 | 2017-07-17 | 2017-10-16 | 91 | Shibor3M Actual/360 | 1 | 2017-07-14 | 0.06598904 | Actual/360 | 0.2527778 | 0.06598904 |
2018-01-15 | 1790725 | 1e+08 | 2017-10-16 | 2018-01-15 | 91 | Shibor3M Actual/360 | 1 | 2017-10-13 | 0.07084187 | Actual/360 | 0.2527778 | 0.07084187 |