/
make_zero_coupon.py
163 lines (126 loc) · 5.06 KB
/
make_zero_coupon.py
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""
Copyright (C) 2011, Enthought Inc
Copyright (C) 2011, Patrick Henaff
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
"""
from __future__ import division
from __future__ import print_function
# This script shows how to build libor zero-coupon
# curves from deposits and swap rates, and plot
# a series of such curves
from quantlib.settings import Settings
from quantlib.termstructures.yields.rate_helpers import \
DepositRateHelper, SwapRateHelper
from quantlib.termstructures.yields.piecewise_yield_curve import \
PiecewiseYieldCurve, BootstrapTrait, Interpolator
from quantlib.time.api import Date, TARGET, Period, Months, Years, Days
from quantlib.time.api import (ModifiedFollowing, Actual360,
Thirty360, Semiannual, ActualActual)
from quantlib.time.api import ISDA, pydate_from_qldate
from quantlib.currency.api import USDCurrency
from quantlib.quotes import SimpleQuote
from quantlib.indexes.libor import Libor
import datetime
import numpy as np
import matplotlib.pyplot as plt
import pandas
def get_term_structure(df_libor, dtObs):
settings = Settings()
# Market information
calendar = TARGET()
# must be a business day
eval_date = calendar.adjust(Date.from_datetime(dtObs))
settings.evaluation_date = eval_date
settlement_days = 2
settlement_date = calendar.advance(eval_date, settlement_days, Days)
# must be a business day
settlement_date = calendar.adjust(settlement_date)
depositData = [[1, Months, 'Libor1M'],
[3, Months, 'Libor3M'],
[6, Months, 'Libor6M']]
swapData = [[1, Years, 'Swap1Y'],
[2, Years, 'Swap2Y'],
[3, Years, 'Swap3Y'],
[4, Years, 'Swap4Y'],
[5, Years, 'Swap5Y'],
[7, Years, 'Swap7Y'],
[10, Years, 'Swap10Y'],
[30, Years, 'Swap30Y']]
rate_helpers = []
end_of_month = True
for m, period, label in depositData:
tenor = Period(m, Months)
rate = df_libor.get_value(dtObs, label)
helper = DepositRateHelper(SimpleQuote(rate / 100.0), tenor,
settlement_days,
calendar, ModifiedFollowing,
end_of_month,
Actual360())
rate_helpers.append(helper)
liborIndex = Libor('USD Libor', Period(3, Months),
settlement_days,
USDCurrency(), calendar,
Actual360())
spread = SimpleQuote(0)
fwdStart = Period(0, Days)
for m, period, label in swapData:
rate = df_libor.get_value(dtObs, label)
helper = SwapRateHelper.from_tenor(
SimpleQuote(rate / 100.0),
Period(m, Years),
calendar, Semiannual,
ModifiedFollowing, Thirty360(),
liborIndex, spread, fwdStart)
rate_helpers.append(helper)
ts_day_counter = ActualActual(ISDA)
tolerance = 1.0e-15
ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount,
Interpolator.LogLinear,
settlement_date,
rate_helpers,
ts_day_counter,
tolerance)
ts.extrapolation = True
return ts
def zero_curve(ts, dtObs):
dtMax = ts.max_date
calendar = TARGET()
days = range(10, 365 * 20, 30)
dtMat = [min(dtMax, calendar.advance(Date.from_datetime(dtObs), d, Days))
for d in days]
# largest dtMat < dtMax, yet QL run time error
df = np.array([ts.discount(dt) for dt in dtMat])
dtMat = [pydate_from_qldate(dt) for dt in dtMat]
dtToday = dtObs.date()
dt = np.array([(d - dtToday).days / 365.0 for d in dtMat])
zc = -np.log(df) / dt
return (dtMat, zc)
if __name__ == '__main__':
df_libor = pandas.read_pickle('examples/data/df_libor.pkl')
dtObs = df_libor.index
fig = plt.figure()
ax = fig.add_subplot(111)
# compute x-axis limits
ts = get_term_structure(df_libor, dtObs[0])
(dtMat, zc) = zero_curve(ts, dtObs[0])
dtMin = dtMat[0]
ts = get_term_structure(df_libor, dtObs[-1])
(dtMat, zc) = zero_curve(ts, dtObs[-1])
dtMax = dtMat[-1]
print('dtMin %s dtMax %s' % (dtMin, dtMax))
ax.set_xlim(dtMin, dtMax)
ax.set_ylim(0.0, 0.1)
dtI = dtObs[range(0, len(dtObs) - 1, 100)]
for dt in dtI:
try:
ts = get_term_structure(df_libor, dt)
(dtMat, zc) = zero_curve(ts, dt)
ax.plot(dtMat, zc)
except:
print('Error when computing ZC curve for %s' % dt)
plt.title('Zero-coupon USD Libor from %s to %s' %
(dtI[0].strftime('%m/%d/%Y'),
dtI[-1].strftime('%m/%d/%Y')))
plt.show()