-
Notifications
You must be signed in to change notification settings - Fork 2
/
portfolio.py
122 lines (99 loc) · 4.2 KB
/
portfolio.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
#!/usr/bin/env python3
from itertools import product
import sys
import QuantLib as ql
def price(t = 1, s = 100, k = 100, z = 0.2, r = 0.05, q = 0.0, w = -1, e = True):
anchor = ql.Date(18,4,2023)
ql.Settings.instance().setEvaluationDate(anchor)
day_count = ql.Actual360()
calendar = ql.UnitedStates(ql.UnitedStates.NYSE)
spot_handle = ql.QuoteHandle( ql.SimpleQuote( s ) )
flat_ts = ql.YieldTermStructureHandle( ql.FlatForward( anchor, r, day_count ))
dividend_yield = ql.YieldTermStructureHandle( ql.FlatForward( anchor, q, day_count))
flat_vol_ts = ql.BlackVolTermStructureHandle( ql.BlackConstantVol( anchor, calendar, z, day_count ))
bsm_process = ql.BlackScholesMertonProcess( spot_handle, dividend_yield, flat_ts, flat_vol_ts )
payoff = ql.PlainVanillaPayoff( ql.Option.Put if w < 0 else ql.Option.Call, k )
maturity = anchor + ql.Period(round(t * 360.), ql.Days)
if e:
engine = ql.QdFpAmericanEngine( bsm_process, ql.QdFpAmericanEngine.highPrecisionScheme() )
asset = ql.VanillaOption( payoff, ql.AmericanExercise( anchor, maturity ))
else:
engine = ql.AnalyticEuropeanEngine( bsm_process )
asset = ql.VanillaOption( payoff, ql.EuropeanExercise( maturity ))
asset.setPricingEngine(engine)
return asset.NPV()
def _diff(key, order=1, bump=0.01, **kwargs):
x = kwargs[key]
kwargs[key] = (1 + bump) * x
v_up = price(**kwargs)
kwargs[key] = (1 - bump) * x
v_down = price(**kwargs)
kwargs[key] = x
if order == 1:
return (v_up - v_down) / (2 * bump * x) + 0
elif order == 2:
return (v_up - 2 * price(**kwargs) + v_down) / (bump * x)**2 + 0
return None
def delta(**kwargs):
return _diff('s', order=1, **kwargs)
def gamma(**kwargs):
return _diff('s', order=2, **kwargs)
def rho(**kwargs):
return _diff('r', order=1, **kwargs) / 100
def theta(**kwargs):
return _diff('t', order=1, **kwargs) / 360
def vega(**kwargs):
return _diff('z', order=1, **kwargs) / 100
def generate(fo, portfolio):
if portfolio == 'fd1d':
t = [1./12, 0.25, 0.5, 0.75, 1.]
s = [100]
k = [25, 50, 80, 90, 100, 110, 120, 150, 175, 200]
z = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
r = [0.02, 0.04, 0.06, 0.08, 0.1]
q = [0.0, 0.04, 0.08, 0.12]
w = [-1]
e = [True]
elif portfolio == 'qdfp':
t = [1./12, 0.25, 0.5, 0.75, 1.]
s = [25, 50, 80, 90, 100, 110, 120, 150, 175, 200]
k = [100]
z = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
r = [0.02, 0.04, 0.06, 0.08, 0.1]
q = [0.0, 0.04, 0.08, 0.12]
w = [-1]
e = [True]
else:
e = [True, False]
k = [100]
q = [0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12]
r = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1]
s = [25, 50, 80, 90, 100, 110, 120, 150, 175, 200]
t = [1./12, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0]
w = [-1, 1]
z = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5]
def to_string(x):
x_ = round(x, 12) + 0
return f'{x_:.12f}'.rstrip('0')
fo.write('expiry,spot,strike,volatility,interest_rate,dividend_rate,parity,exercise,price\n')
#fo.write('expiry,spot,strike,volatility,interest_rate,dividend_rate,parity,exercise,price,delta,gamma,vega,theta,rgo\n')
for option in product(t, s, k, z, r, q, w, e):
t, s, k, z, r, q, w, e = option
price_ = to_string(price(*option))
#price_ = to_string(price(*option))
#delta_ = to_string(delta(**kwargs))
#gamma_ = to_string(gamma(**kwargs))
#rho_ = to_string(rho(**kwargs))
#theta_ = to_string(theta(**kwargs))
#vega_ = to_string(vega(**kwargs))
line = f'{t},{s},{k},{z},{r},{q},{"c" if w > 0 else "p"},{"a" if e else "e"},{price_}\n'
#line = f'{t},{s},{k},{z},{r},{q},{"c" if w > 0 else "p"},{"a" if e else "e"},{price_},{delta_},{gamma_},{vega_},{theta_},{rho_}\n'
print(line, end='')
fo.write(line)
if __name__ == '__main__':
if len(sys.argv) != 2:
print("portfolio.py <mode>")
exit()
mode = sys.argv[1]
with open(f'portfolio_{mode}.csv', 'w') as fo:
generate(fo, mode)