Home  Search  Register  Login  Recent Posts

Information on DTN's Industries:
DTN Oil & Gas | DTN Trading | DTN Agriculture | DTN Weather
Follow DTNMarkets on Twitter
DTN.IQ/IQFeed on Twitter
DTN News and Analysis on Twitter
»Forums Index »NEW IQFEED FORUMS »New IQFeed Forum »(futures and equity) option chains using Python
Author Topic: (futures and equity) option chains using Python (12 messages, Page 1 of 1)

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 16, 2023 02:15 AM          Msg. 1 of 12
hi, I am just an IQFeed user so I do not have access to the development documentation. I have access to futures and "futures options" data via my subscription with IQFeed.

I want to use Python to get access to "futures option" chains (and maybe I add an Equity options subscription as well at some point).

For Yahoo Equity Options data there exists Python code that allows to have acces to put and call option chain data for a specific expiration date (see example code below). It basically puts the put and call data in a pandas dataframe.

I want to make similar dataframes for the IQFeed "futures option" data. I explain further below the Python code that can access Yahoo data.


# python medium_options.py

import yfinance as yf
import matplotlib.pyplot as plt

def main():
symbol = input("Enter the Symbol: " )
#symbol = 'UNG'
osym = yf.Ticker(symbol)
exps = osym.options

print("Expiry dates:")
print(exps)
expiry = input("\nEnter the Expiry data [format: YYYY-MM-DD]: " )

#expiry = '2023-04-21'
opc = osym.option_chain(expiry)
opccalls = opc.calls
opcputs = opc.puts
print(opc.calls)
print(opc.puts)
print(')
print(opc.calls.info())

''
plt.subplot(211)
plt.plot(opccalls['strike'],opccalls['openInterest'])
plt.subplot(212)
plt.plot(opcputs['strike'],opcputs['openInterest'])
plt.show()
''

if __name__ == "__main__":
main()


The resulting dataframes looks like this:


contractSymbol lastTradeDate strike lastPrice bid ask change percentChange volume openInterest impliedVolatility inTheMoney contractSize currency
0 UNG230421P00002000 2023-03-27 13:33:21+00:00 2.0 0.05 0.00 0.04 0.00 0.000000 2.0 24 4.750004 False REGULAR USD
1 UNG230421P00003000 2023-04-10 16:31:05+00:00 3.0 0.01 0.00 0.01 0.00 0.000000 16.0 306 2.625003 False REGULAR USD
2 UNG230421P00004000 2023-04-14 14:03:58+00:00 4.0 0.01 0.00 0.01 0.00 0.000000 88.0 752 1.750001 False REGULAR USD
3 UNG230421P00004500 2023-04-14 17:42:34+00:00 4.5 0.01 0.00 0.01 0.00 0.000000 206.0 3347 1.375003 False REGULAR USD
4 UNG230421P00005000 2023-04-14 19:54:54+00:00 5.0 0.01 0.01 0.03 -0.02 -66.666670 242.0 5222 1.375003 False REGULAR USD
5 UNG230421P00005500 2023-04-14 19:55:37+00:00 5.5 0.02 0.01 0.03 -0.02 -50.000000 595.0 7400 0.984375 False REGULAR USD
6 UNG230421P00006000 2023-04-14 19:59:43+00:00 6.0 0.06 0.05 0.07 -0.08 -57.142853 6339.0 63012 0.859376 False REGULAR USD
7 UNG230421P00006500 2023-04-14 20:09:03+00:00 6.5 0.19 0.19 0.20 -0.14 -42.424248 2028.0 8081 0.828127 False REGULAR USD
8 UNG230421P00007000 2023-04-14 20:14:48+00:00 7.0 0.45 0.42 0.46 -0.23 -33.823532 1107.0 17013 0.730471 True REGULAR USD
9 UNG230421P00007500 2023-04-14 17:42:34+00:00 7.5 0.91 0.80 1.02 -0.25 -21.551720 68.0 1799 1.031255 True REGULAR USD
10 UNG230421P00008000 2023-04-14 19:43:35+00:00 8.0 1.32 1.29 1.35 -0.34 -20.481924 104.0 37005 0.781252 True REGULAR USD
11 UNG230421P00008500 2023-04-13 13:54:25+00:00 8.5 2.09 1.59 2.05 0.00 0.000000 4.0 58 0.968750 True REGULAR USD
12 UNG230421P00009000 2023-04-14 17:13:51+00:00 9.0 2.38 2.26 2.51 -0.24 -9.160297 4.0 6204 1.750001 True REGULAR USD


I have Python code to access historical data. The message rule used I found on this forum I believe. For instance I use this code to download historical futures data. Further explanation below this code.

 
def read_historical_data_socket(sock, recv_buffer=524288):
buffer = ""
data = ""
while True:
data = sock.recv(recv_buffer)
buffer += data.decode()

# Check if the end message string arrives
if "!ENDMSG!" in buffer:
break

# Remove the end message string
buffer = buffer[:-12]
# Remove protocol message at the start
buffer = buffer[22:]
return buffer

def downloadTickDataPerDay2(sym,
bdate,
edate,
filename,
dataPath):

sym = str(sym)
bdate = str(bdate)
edate = str(edate)
filename = str(filename)
dataPath = str(dataPath)

host = "127.0.0.1" # Localhost
port = 9100 # Historical data socket port
message = "HTT,%s,%s,%s,,,,1\n" % ( sym, bdate, edate )

# Open a streaming socket to the IQFeed server locally
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.sendall(b'S,SET PROTOCOL,6.2\r\n')

# Send the historical data request
# message and buffer the data
sock.sendall(message.encode())
data = read_historical_data_socket(sock)
sock.close

# remove blank line at start where the protocol message was removed
data = data.strip()
# Remove all the endlines and line-ending
# comma delimiter from each record
data = "".join(data.split("\r"))
data = data.replace(",\n","\n")[:-1]
data = data.replace("LH,","")

if data != 'E,!NO_DATA!,':
# Write the data stream to disk
f = open(dataPath + sym + "//" + filename, "w")
f.write(data)
f.close()
else:
print("No Data found ....")


so I am after Python code that can either download "futures option chains" and "equity options chains". It should give
1) a list of expiration dates
2) if the expiration date is given it should put the put and call option chains in for instance pandas dataframes

Probably the Python code would be similar to the code posted just above but I do not know the correct message rule and port etc.

I will also ask Math Paquette later using his Csharp plugin. I tried to use it but the documentation is basically the Csharp source code which is slightly above my head. Here is some code using the plugin which gives some output (assuming IQFeed is launched). However, I have not been able to find the put and call data. I would however prefer pure Python code without having to use the Csharp plugin.

thanks

 
# https://github.com/mathpaquette/IQFeed.CSharpApiClient/blob/master/docs/USING-WITH-PYTHON.md
# Dynamically add IQFeed.CSharpApiClient DLL
# assembly_path = r"C:\<folder>"
# type in CMD window: python iqfeedcsharpapiclientOptionTest.py

assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'

import sys
sys.path.append(assembly_path)

# Reference IQFeed.CSharpApiClient DLL
import clr
clr.AddReference("IQFeed.CSharpApiClient")

# from IQFeed.CSharpApiClient import IQFeedLauncher

# Step 2 - Use the appropriate factory to create the client
from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
from IQFeed.CSharpApiClient.Lookup.Chains import OptionSideFilterType

lookupClient = LookupClientFactory.CreateNew()

# Step 3 - Connect it
lookupClient.Connect()

ticks = lookupClient.Chains.GetChainFutureOption( "QNG", OptionSideFilterType.CP, "K", '23')

for tt in ticks:
print(tt.Symbol,tt.StrikePrice)
#print(dir(tt))

print('Completed!')


emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 16, 2023 04:03 AM          Msg. 2 of 12
i think I understand the idea of the csharp plugin. "GetChainFutureOption" gives the list of symbols for "Futures Options". These symbols one can then use to retrieve the data. I was thinking the data would come with it but it is just a list. So hopefully I can use this list of symbols to retrieve the data.


# https://github.com/mathpaquette/IQFeed.CSharpApiClient/blob/master/docs/USING-WITH-PYTHON.md
# Dynamically add IQFeed.CSharpApiClient DLL
# assembly_path = r"C:\<folder>"
# type in CMD window: python iqfeedcsharpapiclientOptionTest.py

assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'

import sys
sys.path.append(assembly_path)

# Reference IQFeed.CSharpApiClient DLL
import clr
clr.AddReference("IQFeed.CSharpApiClient")

from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
from IQFeed.CSharpApiClient.Lookup.Chains import OptionSideFilterType

lookupClient = LookupClientFactory.CreateNew()
lookupClient.Connect()

ticks = lookupClient.Chains.GetChainFutureOption( "QNG", OptionSideFilterType.CP, "K", '23')

for tt in ticks:
print(tt.Symbol)

print('Completed!')


DTN_Gary_Stephen
-DTN Guru-
Posts: 403
Joined: Jul 3, 2019


Posted: Apr 17, 2023 05:14 PM          Msg. 3 of 12
GetFutureOption must be building an Option Chains request, as described at http://www.iqfeed.net/dev/api/docs/OptionChainsviaTCPIP.cfm

Quote:
ticks = lookupClient.Chains.GetChainFutureOption( "QNG", OptionSideFilterType.CP, "K", '23')


QNG# is a future. That looks like it's building the command:

CFU,QNG,K,23

The OptionSideFilterType.CP parameter is telling it which command to use (out of CFU, CFS, CFO, CEO). K is the month code (May) and 23 are the years (years ending in 2 or 3). It would return:

LC,QNGK23,QNGK32,QNGK33,

Sincerely,
Gary Stephen
DTN IQFeed Implementation Support Specialist

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 18, 2023 12:56 AM          Msg. 4 of 12
thanks for your help, I will try that

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 18, 2023 01:40 AM          Msg. 5 of 12
and yes I am after the "Futures Options" for now since I have an IQFeed subscription for US futures only. And I have no access to the "development library" since I only have a subscription to use the data.

actually using csharp I managed to get the list of options that belong to a chain for a certain month and year, see code below.

Now I still need to get the data. I have some code that gets the price data for the futures options but the Open Interest is apparently stored somewhere else. I still need to figure out how to access the Open Interest. Apparently this is not saved in a similar way as the price is.

Also the option chain lists are not saved in history apparently. I have access to historical futures options data but the "historical futures chain lists" are apparently not saved.

here the code that uses Csharp that gives the symbols of a chain

 
https://github.com/mathpaquette/IQFeed.CSharpApiClient/blob/master/docs/USING-WITH-PYTHON.md
# Dynamically add IQFeed.CSharpApiClient DLL
# assembly_path = r"C:\<folder>"
# filename: iqfeedcsharpGetFuturesOptionChainAFL.py


if '__' + __file__ + '_initialized' not in globals():
globals()['__' + __file__ + '_initialized'] = True
assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'

import sys
sys.path.append(assembly_path)

# Reference IQFeed.CSharpApiClient DLL
import clr
clr.AddReference("IQFeed.CSharpApiClient")

from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
from IQFeed.CSharpApiClient.Lookup.Chains import OptionSideFilterType
#import AmiPy

def getFuturesOptionsChainSymbols(f_symbol, o_month, o_year):

'''
Month codes:
January: F
February: G
March: H
April: J
May: K
June: M
July: N
August: Q
September: U
October: V
November: X
December: Z
'''

f_symbol = str(f_symbol)
o_month = str(o_month)
o_year = str(o_year)

lookupClient = LookupClientFactory.CreateNew()
lookupClient.Connect()

try:
# symtax Symbol (QNG), OptionSideFilterType.CP, Month Code, Year Code
ticks = lookupClient.Chains.GetChainFutureOption( f_symbol, OptionSideFilterType.CP, o_month, o_year )
symbollist = ''
for tt in ticks:
symbollist += tt.Symbol
symbollist += ','

# remove last comma
symbollist = symbollist[:len(symbollist)-1]
#AmiPy.Print(symbollist)
except Exception as err:
#AmiPy.Print(f"Unexpected {err=}, {type(err)=}")
print(f"Unexpected {err=}, {type(err)=}")

return symbollist

def main():
optionchain = getFuturesOptionsChainSymbols("QNG", "K", "23")
print(optionchain)

if __name__ == "__main__":
main()


DTN_Gary_Stephen
-DTN Guru-
Posts: 403
Joined: Jul 3, 2019


Posted: Apr 18, 2023 09:19 AM          Msg. 6 of 12
Only Daily history data includes Open Interest. Interval and Tick history do not. So I think you're looking for what MathPaquette calls ReqHistoryDailyDatapoints or ReqHistoryDailyTimeframe. Both return the same data, but the former lets you specify the how many data points you wanty, and latter lets you set a date range. The resulting request and response will be:

HDT,@ES#,20230102,20230109
LH,2023-01-09,3973.25,3909.75,3918.50,3913.75,1697887,2005511,
LH,2023-01-06,3928.75,3819.00,3833.00,3915.50,2026154,2007262,
LH,2023-01-05,3885.50,3822.50,3871.00,3829.00,1679973,2006357,
LH,2023-01-04,3896.25,3836.50,3842.75,3874.50,1912155,2003469,
LH,2023-01-03,3906.75,3814.50,3895.00,3846.00,1782473,1999096,
!ENDMSG!,

The last figure is the Open Interest.

Sincerely,
Gary Stephen
DTN IQFeed Implementation Support Specialist

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 19, 2023 01:09 AM          Msg. 7 of 12
thanks for your help. I will try that. I also managed to access the data inside Amibroker. But I use Python to access the list (chain) of options. Will later ask Amibroker if they also can add a function to access this chain of option symbols.

Is there also a call to access the list of expiration dates for a particular symbol? So if I give the futures symbol it would give a list of expiration dates?

For instance in the Python example using Yahoo data (see code below) the command in line 10, osym.options gives me a list of expiration dates for the stock symbol given.

For futures options it would coincide with the expiration of the underlying future. I guess for futures options you rather would want a list of expiration months. Not sure.

thank you


 
# python medium_options.py

import yfinance as yf
import matplotlib.pyplot as plt

def main():
symbol = input("Enter the Symbol: " )
#symbol = 'UNG'
osym = yf.Ticker(symbol)
exps = osym.options

print("Expiry dates:")
print(exps)
expiry = input("\nEnter the Expiry data [format: YYYY-MM-DD]: " )

#expiry = '2023-04-21'
opc = osym.option_chain(expiry)
opccalls = opc.calls
opcputs = opc.puts
print(opc.calls)
print(opc.puts)
print('')
print(opc.calls.info())

'''
plt.subplot(211)
plt.plot(opccalls['strike'],opccalls['openInterest'])
plt.subplot(212)
plt.plot(opcputs['strike'],opcputs['openInterest'])
plt.show()
'''

if __name__ == "__main__":
main()

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 19, 2023 04:58 AM          Msg. 8 of 12
actually using the Csharp code I get access to OpenInterest data using GetHistoryDailyDatapoints, see code below.

About the OpenInterest. It seems the last data point is zero. Is this data updated only at certain times?

Data output from code below looks like:


C:\Users\win 10\AppData\Local\Programs\Python\Python38\mypython\iqfeed>python charpHistoricalDataTest.py
Timestamp: 4/19/2023 12:00:00 AM, High: 0.181, Low: 0.181, Open: 0.181, Close: 0.181, PeriodVolume: 3, OpenInterest: 0, RequestId:
Timestamp: 4/18/2023 12:00:00 AM, High: 0.192, Low: 0.13, Open: 0.154, Close: 0.19, PeriodVolume: 18, OpenInterest: 221, RequestId:
Timestamp: 4/17/2023 12:00:00 AM, High: 0.155, Low: 0.09, Open: 0.099, Close: 0.143, PeriodVolume: 28, OpenInterest: 226, RequestId:
Timestamp: 4/14/2023 12:00:00 AM, High: 0.08, Low: 0.039, Open: 0.055, Close: 0.079, PeriodVolume: 57, OpenInterest: 240, RequestId:
Timestamp: 4/13/2023 12:00:00 AM, High: 0.073, Low: 0.053, Open: 0.073, Close: 0.055, PeriodVolume: 19, OpenInterest: 265, RequestId:
Completed!


So this output I created at 2023-04-19 at 05:55 ET and the OpenInterest on the 19-th is showing 0. Why is it showing 0? Shouldn't that be showing the last value of the prior day? At what time of the day is it updated?

Thanks.

Python code using Csharp plugin
 
# python charpHistoricalDataTest.py

# Dynamically add IQFeed.CSharpApiClient DLL
import sys
import clr
assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'
sys.path.append(assembly_path)
clr.AddReference("IQFeed.CSharpApiClient")

# Step 2 - Use the appropriate factory to create the client
from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
#from IQFeed.CSharpApiClient.Lookup.Historical import LookupClientFactory
lookupClient = LookupClientFactory.CreateNew()

# Step 3 - Connect it
lookupClient.Connect()

# Step 4 - Make any requests you need or want!
#ticks = lookupClient.Historical.GetHistoryTickDatapoints("QNGK23C2250", 10)
ticks = lookupClient.Historical.GetHistoryDailyDatapoints("QNGK23C2250", 5)

for tick in ticks:
print(tick)

print('Completed!')

DTN_Gary_Stephen
-DTN Guru-
Posts: 403
Joined: Jul 3, 2019


Posted: Apr 19, 2023 08:13 AM          Msg. 9 of 12
All data points are updated continuously. Since you're requesting daily data. The numbers you get will reflect conditions at the end of the trading day. It is normal for a contract to show an open interest of zero when that contract expires, and when it first begins and hasn't been traded yet.

ADDED: I should clarify this to add that Open Interest is always a day behind. Fore example, open interest for today’s datapoint on all contracts will be zero until tomorrow morning/next trading day's opening.



Sincerely,
Gary Stephen
DTN IQFeed Implementation Support Specialist

Edited by DTN_Gary_Stephen on Apr 20, 2023 at 10:10 AM

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 19, 2023 09:01 AM          Msg. 10 of 12
thanks. I also check in the Options Chain App and the Open Interest shown is the value of yesterdays close. So it is not updated. I mean the Volume is updating but not the OI. Not sure if this is normal, I am no expert on this.

Maybe I post my Python code later. It is really slow. What I do I first get the Option Chain list (for calls and puts). I put them in a pandas dataframe sorted for the strike price. Then I loop through all the symbols of the chain to find the OI for all the symbols. That takes too long.

Will post code complete later.

A snippet of the code shows what I do, see below. The function passes the future option symbol and the startdate plus enddate (which are the same and I use yesterdays date since todays values are zero). This is slow. It gives the correct OI values. Maybe it is because I get the OI from a string. I should be able to access it directly but I do not know the correct csharp code for that.

 
def getOpenInterestdata( sym, d1, d2 ):
sym = str(sym)
lookupClient = LookupClientFactory.CreateNew()
lookupClient.Connect()

# Step 4 - Make any requests you need or want!
#ticks = lookupClient.Historical.GetHistoryTickDatapoints("QNGK23C2250", 10)
#ticks = lookupClient.Historical.GetHistoryDailyDatapoints(sym, 5)
ticks = lookupClient.Historical.GetHistoryDailyTimeframe(sym, d1, d2)

for tick in ticks:
s = str(tick)
datalist = s.split(',')
#print(int(str(datalist[6]).replace(' OpenInterest: ','')))
oi = int(str(datalist[6]).replace(' OpenInterest: ',''))

return oi

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 19, 2023 09:42 AM          Msg. 11 of 12
yes it seems that this line (in the function getOpenInterestdata) makes it slow:

 
ticks = lookupClient.Historical.GetHistoryDailyTimeframe(sym, d1, d2)


the total code is below. What it does is it makes 2 pandas dataframes. 1 for Futures Call contracts and 1 for the Futures Put contracts. In the columns are, the symbols, strike price and Open interest.

It works but it is slow. The openInterest for various strike prices should be instantly accessible. At least the IQFeed chains App finds them almost instantly. So somethings is wrong with this code.

 
# filesname: charpHistoricalDataTest.py
# to run code IQFeed should be launched already
# to run code type in the CMD window (path to python should be known)
# python charpHistoricalDataTest.py

# Dynamically add IQFeed.CSharpApiClient DLL
import sys
import clr
assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'
sys.path.append(assembly_path)
clr.AddReference("IQFeed.CSharpApiClient")
from System import DateTime
from datetime import datetime, timedelta
from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
from IQFeed.CSharpApiClient.Lookup.Chains import OptionSideFilterType
import pandas as pd

lookupClient = LookupClientFactory.CreateNew()
lookupClient.Connect()

def createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, o_side):

'''
Month codes:
January: F
February: G
March: H
April: J
May: K
June: M
July: N
August: Q
September: U
October: V
November: X
December: Z
'''

f_symbol = str(f_symbol)
o_month = str(o_month)
o_year = str(o_year)

if( o_side == 1):
side = OptionSideFilterType.C
if( o_side == 2):
side = OptionSideFilterType.P

try:
ticks = lookupClient.Chains.GetChainFutureOption( f_symbol, side, o_month, o_year )
symbollist = ''
strikepricelist = ''
for tt in ticks:
symbollist += str(tt.Symbol)
symbollist += ','
strikepricelist += str(tt.StrikePrice)
strikepricelist += ','

# remove last comma
symbollist = symbollist[:len(symbollist)-1]
except Exception as err:
print(f"Unexpected {err=}, {type(err)=}")

return symbollist,strikepricelist

def getOpenInterestdata( sym, d1, d2 ):
sym = str(sym)
#ticks = lookupClient.Historical.GetHistoryDailyDatapoints(sym, 1)
ticks = lookupClient.Historical.GetHistoryDailyTimeframe(sym, d1, d2)

for tick in ticks:
s = str(tick)
datalist = s.split(',')
#print(int(str(datalist[6]).replace(' OpenInterest: ','')))
oi = int(str(datalist[6]).replace(' OpenInterest: ',''))

return oi

def main():
f_symbol = 'QNG'
o_month = 'K'
o_year = '23'

yesterday = datetime.now() - timedelta(1)
d1 = DateTime(yesterday.year,yesterday.month,yesterday.day)
d2 = DateTime(yesterday.year,yesterday.month,yesterday.day)

# Calls
symbollist,strikepricelist = createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, 1)
list1 = symbollist.split(',')
list2 = strikepricelist.split(',')
df_calls = pd.DataFrame(list(zip(list1, list2)), columns =['Symbols', 'Strike'])
df_calls = df_calls.astype({'Strike':'float'})
df_calls = df_calls.sort_values(by=['Strike'])
df_calls['OpenInterest'] = 0

idx = 0
for index, row in df_calls.iterrows():
sym = row['Symbols']
oi = getOpenInterestdata( sym, d1, d2 )
df_calls.iloc[idx, 2] = oi
#print(idx,row['Strike'],row['Symbols'],oi)
idx += 1

print(df_calls)

# Puts
symbollist,strikepricelist = createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, 2)
list1 = symbollist.split(',')
list2 = strikepricelist.split(',')
df_puts = pd.DataFrame(list(zip(list1, list2)), columns =['Symbols', 'Strike'])
df_puts = df_puts.astype({'Strike':'float'})
df_puts = df_puts.sort_values(by=['Strike'])
df_puts['OpenInterest'] = 0

idx = 0
for index, row in df_puts.iterrows():
sym = row['Symbols']
oi = getOpenInterestdata( sym, d1, d2 )
df_puts.iloc[idx, 2] = oi
#print(idx,row['Strike'],row['Symbols'],oi)
idx += 1

print(df_puts)

if __name__ == "__main__":
main()

emp
-Interested User-
Posts: 32
Joined: Aug 10, 2011


Posted: Apr 19, 2023 10:57 AM          Msg. 12 of 12
this is the final "max pain" code. Kind of slowwwwww. Maybe IQFeed can add max pain so we do not have to calculate it.

Getting max pain for NQ June expiration 12800 and ES June expiration 4050

 
# filesname: charpHistoricalDataTest.py
# to run code IQFeed should be launched already
# to run code type in the CMD window (path to python should be known)
# python charpHistoricalDataTest.py

# Dynamically add IQFeed.CSharpApiClient DLL
import sys
import clr
assembly_path = r'C:/Program Files/AmiBroker/IQFeedCSharpApiClient'
sys.path.append(assembly_path)
clr.AddReference("IQFeed.CSharpApiClient")
from System import DateTime
from datetime import datetime, timedelta
from IQFeed.CSharpApiClient.Lookup import LookupClientFactory
from IQFeed.CSharpApiClient.Lookup.Chains import OptionSideFilterType
import pandas as pd
import matplotlib.pyplot as plt

lookupClient = LookupClientFactory.CreateNew()
lookupClient.Connect()

def total_loss_at_strike(chainC, chainP, expiry_price):
"""Calculate loss at strike price"""
# All call options with strike price below the expiry price will result in loss for option writers
in_money_calls = chainC[chainC['Strike'] < expiry_price][["OpenInterest", "Strike"]]
in_money_calls["CE loss"] = (expiry_price - in_money_calls['Strike'])*in_money_calls["OpenInterest"]

# All put options with strike price above the expiry price will result in loss for option writers
in_money_puts = chainP[chainP['Strike'] > expiry_price][["OpenInterest", "Strike"]]
in_money_puts["PE loss"] = (in_money_puts['Strike'] - expiry_price)*in_money_puts["OpenInterest"]
total_loss = in_money_calls["CE loss"].sum() + in_money_puts["PE loss"].sum()

return total_loss

def createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, o_side):

'''
Month codes:
January: F
February: G
March: H
April: J
May: K
June: M
July: N
August: Q
September: U
October: V
November: X
December: Z
'''

f_symbol = str(f_symbol)
o_month = str(o_month)
o_year = str(o_year)

if( o_side == 1):
side = OptionSideFilterType.C
if( o_side == 2):
side = OptionSideFilterType.P

try:
ticks = lookupClient.Chains.GetChainFutureOption( f_symbol, side, o_month, o_year )
symbollist = ''
strikepricelist = ''
for tt in ticks:
symbollist += str(tt.Symbol)
symbollist += ','
strikepricelist += str(tt.StrikePrice)
strikepricelist += ','

# remove last comma
symbollist = symbollist[:len(symbollist)-1]
except Exception as err:
print(f"Unexpected {err=}, {type(err)=}")

return symbollist,strikepricelist

def getOpenInterestdata( sym, d1, d2 ):
sym = str(sym)
#ticks = lookupClient.Historical.GetHistoryDailyDatapoints(sym, 1)
ticks = lookupClient.Historical.GetHistoryDailyTimeframe(sym, d1, d2)

for tick in ticks:
s = str(tick)
datalist = s.split(',')
#print(int(str(datalist[6]).replace(' OpenInterest: ','')))
oi = int(str(datalist[6]).replace(' OpenInterest: ',''))

return oi

def main():
f_symbol = '@NQ'
o_month = 'M'
o_year = '23'

yesterday = datetime.now() - timedelta(1)
d1 = DateTime(yesterday.year,yesterday.month,yesterday.day)
d2 = DateTime(yesterday.year,yesterday.month,yesterday.day)

# Calls
symbollist,strikepricelist = createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, 1)
list1 = symbollist.split(',')
list2 = strikepricelist.split(',')
df_calls = pd.DataFrame(list(zip(list1, list2)), columns =['Symbols', 'Strike'])
df_calls = df_calls.astype({'Strike':'float'})
df_calls = df_calls.sort_values(by=['Strike'])
df_calls['OpenInterest'] = 0

idx = 0
for index, row in df_calls.iterrows():
sym = row['Symbols']
oi = getOpenInterestdata( sym, d1, d2 )
df_calls.iloc[idx, 2] = oi
#print(idx,row['Strike'],row['Symbols'],oi)
idx += 1

print(df_calls)

# Puts
symbollist,strikepricelist = createListofSymbolPlusStrikePrice(f_symbol, o_month, o_year, 2)
list1 = symbollist.split(',')
list2 = strikepricelist.split(',')
df_puts = pd.DataFrame(list(zip(list1, list2)), columns =['Symbols', 'Strike'])
df_puts = df_puts.astype({'Strike':'float'})
df_puts = df_puts.sort_values(by=['Strike'])
df_puts['OpenInterest'] = 0

idx = 0
for index, row in df_puts.iterrows():
sym = row['Symbols']
oi = getOpenInterestdata( sym, d1, d2 )
df_puts.iloc[idx, 2] = oi
#print(idx,row['Strike'],row['Symbols'],oi)
idx += 1

print(df_puts)

strikes = list(df_calls['Strike'])
losses = [total_loss_at_strike(df_calls, df_puts, strike)/1000000 for strike in strikes]

m = losses.index(min(losses))
print("Max pain > {}".format(strikes[m]))

plt.plot(strikes, losses)
plt.ylabel('Total loss in (Millon)')
plt.show()

if __name__ == "__main__":
main()



File Attached: es2.png (downloaded 384 times)
 

 

Time: Tue November 12, 2024 3:37 AM CFBB v1.2.0 11 ms.
© AderSoftware 2002-2003