forked from xuruilong100/QuantLibPythonExamples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConvertibleBonds.py
183 lines (150 loc) · 5.96 KB
/
ConvertibleBonds.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import QuantLib as ql
import prettytable as pt
optType = ql.Option.Put
underlying = 36.0
spreadRate = 0.005
dividendYield = 0.02
riskFreeRate = 0.06
volatility = 0.20
settlementDays = 3
length = 5
redemption = 100.0
conversionRatio = redemption / underlying
# set up dates/schedules
calendar = ql.TARGET()
today = calendar.adjust(ql.Date.todaysDate())
ql.Settings.instance().evaluationDate = today
settlementDate = calendar.advance(today, settlementDays, ql.Days)
exerciseDate = calendar.advance(settlementDate, length, ql.Years)
issueDate = calendar.advance(exerciseDate, -length, ql.Years)
convention = ql.ModifiedFollowing
frequency = ql.Annual
schedule = ql.Schedule(
issueDate,
exerciseDate,
ql.Period(frequency),
calendar,
convention,
convention,
ql.DateGeneration.Backward,
False)
dividends = ql.DividendSchedule()
callability = ql.CallabilitySchedule()
coupons = ql.DoubleVector(1, 0.05)
bondDayCount = ql.Thirty360(ql.Thirty360.BondBasis)
callLength = [2, 4] # Call dates, years 2, 4.
putLength = [3] # Put dates year 3
callPrices = [101.5, 100.85]
putPrices = [105.0]
# Load call schedules
for i in range(len(callLength)):
callability.push_back(
ql.SoftCallability(
ql.BondPrice(
callPrices[i], ql.BondPrice.Clean),
schedule[callLength[i]],
1.20))
for i in range(len(putLength)):
callability.push_back(
ql.Callability(
ql.BondPrice(
putPrices[i], ql.BondPrice.Clean),
ql.Callability.Put,
schedule[putLength[i]]))
# Assume dividends are paid every 6 months.
d = today + ql.Period(6, ql.Months)
while d < exerciseDate:
dividends.push_back(
ql.FixedDividend(1.0, d))
d += ql.Period(6, ql.Months)
dayCounter = ql.Actual365Fixed()
maturity = dayCounter.yearFraction(settlementDate, exerciseDate)
print("option type =", optType)
print("Time to maturity =", format(maturity, '.6'))
print("Underlying price =", underlying)
print("Risk-free interest rate =", format(riskFreeRate, '%'))
print("Dividend yield =", format(dividendYield, '%'))
print("Volatility =", format(volatility, '%'))
exercise = ql.EuropeanExercise(exerciseDate)
amExercise = ql.AmericanExercise(settlementDate, exerciseDate)
underlyingH = ql.QuoteHandle(
ql.SimpleQuote(underlying))
flatTermStructure = ql.YieldTermStructureHandle(
ql.FlatForward(settlementDate, riskFreeRate, dayCounter))
flatDividendTS = ql.YieldTermStructureHandle(
ql.FlatForward(settlementDate, dividendYield, dayCounter))
flatVolTS = ql.BlackVolTermStructureHandle(
ql.BlackConstantVol(settlementDate, calendar, volatility, dayCounter))
stochasticProcess = ql.BlackScholesMertonProcess(
underlyingH, flatDividendTS, flatTermStructure, flatVolTS)
timeSteps = 801
creditSpread = ql.QuoteHandle(ql.SimpleQuote(spreadRate))
rate = ql.SimpleQuote(riskFreeRate)
discountCurve = ql.YieldTermStructureHandle(
ql.FlatForward(today, ql.QuoteHandle(rate), dayCounter))
europeanBond = ql.ConvertibleFixedCouponBond(
exercise, conversionRatio,
dividends, callability, creditSpread,
issueDate, settlementDays, coupons,
bondDayCount, schedule, redemption)
americanBond = ql.ConvertibleFixedCouponBond(
amExercise, conversionRatio,
dividends, callability, creditSpread,
issueDate, settlementDays, coupons,
bondDayCount, schedule, redemption)
tab = pt.PrettyTable(["Tree type", "European", "American"])
print('=' * 56)
print("Tsiveriotis-Fernandes method")
print('=' * 56)
engine = ql.BinomialJRConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Jarrow-Rudd", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialCRRConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Cox-Ross-Rubinstein", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialEQPConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Additive equiprobabilities", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialTrigeorgisConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Trigeorgis", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialTianConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Tian", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialLRConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Leisen-Reimer", europeanBond.NPV(), americanBond.NPV()])
engine = ql.BinomialJ4ConvertibleEngine(stochasticProcess, timeSteps)
europeanBond.setPricingEngine(engine)
americanBond.setPricingEngine(engine)
tab.add_row(["Joshi", europeanBond.NPV(), americanBond.NPV()])
tab.float_format = '.6'
tab.align = 'l'
print(tab)
'''
option type = Put
Time to maturity = 5.00274
Underlying price = 36
Risk-free interest rate = 6.000000 %
Dividend yield = 2.000000 %
Volatility = 20.000000 %
===============================================================
Tsiveriotis-Fernandes method
===============================================================
Tree type European American
---------------------------------------------------------------
Jarrow-Rudd 105.698023 108.165159
Cox-Ross-Rubinstein 105.703739 108.167778
Additive equiprobabilities 105.634611 108.108016
Trigeorgis 105.704232 108.168222
Tian 105.721092 108.178469
Leisen-Reimer 105.671891 108.179334
Joshi 105.671891 108.179335
===============================================================
'''