-
Notifications
You must be signed in to change notification settings - Fork 0
/
Par_Spot_Yield_Curve_Bootstrapper_2.py
123 lines (99 loc) · 3.77 KB
/
Par_Spot_Yield_Curve_Bootstrapper_2.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
#http://www.financialexamhelp123.com/par-curve-spot-curve-and-forward-curve/
#mastering-python-for-finance-second-edition
def zero_coupon_bond(par, y, t):
"""
Price a zero coupon bond.
:param par: face value of the bond.
:param y: annual yield or rate of the bond.
:param t: time to maturity, in years.
"""
return par/(1+y)**t
print(zero_coupon_bond(100, 0.02, 0.5))
print(zero_coupon_bond(100, 0.024, 1))
print(zero_coupon_bond(100, 0.0276, 1.5))
print(zero_coupon_bond(100, 0.030840, 2))
print(zero_coupon_bond(100, 0.033756, 2.5))
print(zero_coupon_bond(100, 0.036380, 3))
"""
99.01475429766742
97.65625
95.99836946727454
94.10603498524202
92.03539739675895
89.83445342308401
"""
import math
class BootstrapYieldCurve(object):
def __init__(self):
self.zero_rates = dict()
self.instruments = dict()
def add_instrument(self, par, T, coup, price, compounding_freq=2):
self.instruments[T] = (par, coup, price, compounding_freq)
def get_maturities(self):
"""
:return: a list of maturities of added instruments
"""
return sorted(self.instruments.keys())
def get_zero_rates(self):
"""
Returns a list of spot rates on the yield curve.
"""
self.bootstrap_zero_coupons()
self.get_bond_spot_rates()
return [self.zero_rates[T] for T in self.get_maturities()]
def bootstrap_zero_coupons(self):
"""
Bootstrap the yield curve with zero coupon instruments first.
"""
for (T, instrument) in self.instruments.items():
(par, coup, price, freq) = instrument
if coup == 0:
spot_rate = self.zero_coupon_spot_rate(par, price, T)
self.zero_rates[T] = spot_rate
def zero_coupon_spot_rate(self, par, price, T):
"""
:return: the zero coupon spot rate with continuous compounding.
"""
spot_rate = math.log(par/price)/T
return spot_rate
def get_bond_spot_rates(self):
"""
Get spot rates implied by bonds, using short-term instruments.
"""
for T in self.get_maturities():
instrument = self.instruments[T]
(par, coup, price, freq) = instrument
if coup != 0:
spot_rate = self.calculate_bond_spot_rate(T, instrument)
self.zero_rates[T] = spot_rate
def calculate_bond_spot_rate(self, T, instrument):
try:
(par, coup, price, freq) = instrument
periods = T*freq
value = price
per_coupon = coup/freq
for i in range(int(periods)-1):
t = (i+1)/float(freq)
spot_rate = self.zero_rates[t]
discounted_coupon = per_coupon*math.exp(-spot_rate*t)
value -= discounted_coupon
last_period = int(periods)/float(freq)
spot_rate = -math.log(value/(par+per_coupon))/last_period
return spot_rate
except:
print("Error: spot rate not found for T=", t)
yield_curve = BootstrapYieldCurve()
yield_curve.add_instrument(100, 0.5, 0.02, 99.01475429766742,2)
yield_curve.add_instrument(100, 1.0, 0.024, 97.65625,2 )
yield_curve.add_instrument(100, 1.5, 0.0276, 95.99836946727454,2 )
yield_curve.add_instrument(100, 2.0, 0.030840, 94.10603498524202,2 )
yield_curve.add_instrument(100, 2.5, 0.033756, 92.03539739675895,2 )
yield_curve.add_instrument(100, 3.0, 0.036380, 89.83445342308401,2 )
y = yield_curve.get_zero_rates()
x = yield_curve.get_maturities()
%pylab inline
fig = plt.figure(figsize=(12, 8))
plot(x, y)
title("Zero Curve")
ylabel("Zero Rate (%)")
xlabel("Maturity in Years");