-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathUpdated-Max-Pain-Calculator
118 lines (93 loc) · 4.04 KB
/
Updated-Max-Pain-Calculator
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
import pandas as pd
import yfinance as yf
import datetime
import matplotlib.pyplot as plt
def options_chain(tk, expiry):
'''
Get's the option chain for a given symbol and expiry date and add it to panda df
Credit: https://medium.com/@txlian13/webscrapping-options-data-with-python-and-yfinance-e4deb0124613
'''
# Get options exp
options = pd.DataFrame()
opt = tk.option_chain(expiry.strip())
opt = pd.concat([opt.calls, opt.puts], ignore_index=True)SP
opt['expirationDate'] = expiry
options = pd.concat([options, opt], ignore_index=True)
# Add 1 day to get the correct expiration date
options['expirationDate'] = pd.to_datetime(options['expirationDate']) + datetime.timedelta(days=1)
options['dte'] = (options['expirationDate'] - datetime.datetime.today()).dt.days / 365
# Boolean column if the option is a CALL
options['CALL'] = options['contractSymbol'].str[4:].apply(
lambda x: "C" in x)
options[['bid', 'ask', 'strike']] = options[['bid', 'ask', 'strike']].apply(pd.to_numeric)
# Drop unnecessary and meaningless columns
options = options.drop(
columns=['contractSize', 'currency', 'change', 'percentChange', 'lastTradeDate', 'lastPrice', 'contractSymbol',
'bid', 'ask', 'impliedVolatility', 'inTheMoney', 'dte'])
return options
def total_loss_on_strike(chain, expiry_price):
'''
Get's the total loss at the given strike price
'''
# call options with strike price below the expiry price -> loss for option writers
callChain = chain.loc[chain['CALL'] == True]
callChain = callChain.dropna()
in_money_calls = callChain[callChain['strike'] < expiry_price][["openInterest", "strike"]]
in_money_calls["CLoss"] = (expiry_price - in_money_calls['strike']) * in_money_calls["openInterest"]
# get puts n drop null values
putChain = chain.loc[chain['CALL'] == False]
putChain = putChain.dropna()
# put options with strike price above the expiry price -> loss for option writers
in_money_puts = putChain[putChain['strike'] > expiry_price][["openInterest", "strike"]]
in_money_puts["PLoss"] = (in_money_puts['strike'] - expiry_price) * in_money_puts["openInterest"]
total_loss = in_money_calls["CLoss"].sum() + in_money_puts["PLoss"].sum()
return total_loss
def getInput():
'''
gets the user input on symbol and expiry
'''
symbol = input("Enter the Symbol: ")
tk = yf.Ticker(symbol)
# Expiration dates
exps = tk.options
print("Expiry dates:")
for i in exps:
print(f"{i}", end=", ")
expiry = input("\nEnter the Expiry data [format: YYYY-MM-DD]: ")
return tk, expiry, symbol
def main():
'''
Get's the symbol and expiry date n plot the data
'''
# gets the user input on symbol and expiry
tk, expiry, symbol = getInput()
chain = options_chain(tk, expiry)
strikes = chain.get(['strike']).values.tolist()
losses = [total_loss_on_strike(chain, strike[0]) for strike in strikes]
# max pain min loss to option writers/sellers at strike price
flat_strikes = [item for sublist in strikes for item in sublist]
point = losses.index(min(losses))
max_pain = flat_strikes[point]
buffer = 3
bufferHigh = max_pain + (max_pain * (buffer / 100))
bufferLow = max_pain - (max_pain * (buffer / 100))
print(f"Maximum Pain: {bufferLow} < {max_pain} < {bufferHigh}")
# calc put to call ratio
callChain = chain.loc[chain['CALL'] == True]
putChain = chain.loc[chain['CALL'] == False]
pcr = putChain["volume"].sum() / callChain["volume"].sum()
print("Put to call ratio:", round(pcr, 2))
# get the cummulated losses
total = {}
for i in range(len(flat_strikes)):
if flat_strikes[i] not in total:
total[flat_strikes[i]] = losses[i]
else:
total[flat_strikes[i]] += losses[i]
# plot
keys = set(list(total.keys()))
plt.bar(list(keys), list(total.values()), width=1)
plt.xlabel('Strike Price')
plt.title(f'{symbol.upper()} Max Pain')
if __name__ == "__main__":
main()