Provide a nice wrapper to clients that streams options data into a pandas data frame

This commit is contained in:
moshferatu 2024-01-29 07:18:05 -08:00
parent 6cfa03edaf
commit 332dad3138
5 changed files with 68 additions and 3 deletions

View File

@ -1,8 +1,11 @@
import json
import pandas as pd
import requests
import webbrowser
from datetime import datetime
from dotenv import load_dotenv
from option import Option
from os import getenv
load_dotenv()
@ -110,15 +113,52 @@ class TradeStationClient:
response = requests.get(url, headers = headers, params = params, stream = True)
try:
# TODO: Return a generator to the client.
for line in response.iter_lines():
if line:
print(line.decode('utf-8'))
option_data = json.loads(line.decode('utf-8'))
for leg in option_data.get('Legs', []):
option = Option(
Strike = leg.get('StrikePrice', 'StrikePrice'),
Type = leg.get('OptionType', '').upper(),
Bid = float(option_data.get('Bid', 0)),
Ask = float(option_data.get('Ask', 0)),
Delta = float(option_data.get('Delta', 0))
)
yield option
except Exception as e:
print(f'Error while streaming data: {str(e)}')
finally:
response.close()
def get_options_chain(self, symbol: str, expiration: datetime = None, strike_proximity: int = 25) -> pd.DataFrame:
options_columns = ['Strike', 'Type', 'Bid', 'Ask', 'Delta']
dtypes = {'Strike': float, 'Type': str, 'Bid': float, 'Ask': float, 'Delta': float}
options_chain = pd.DataFrame(columns = options_columns).astype(dtypes)
for option in self.stream_options_chain(
symbol, expiration = expiration, strike_proximity = strike_proximity):
option_data = pd.DataFrame([{
'Strike': option.Strike,
'Type': option.Type,
'Bid': option.Bid,
'Ask': option.Ask,
'Delta': option.Delta
}])
# Only append a new row if the option doesn't already exist in the chain, otherwise update the row.
option_mask = (options_chain['Strike'] == option.Strike) & (options_chain['Type'] == option.Type)
if options_chain[option_mask].empty:
options_chain = pd.concat([options_chain, option_data], ignore_index = True)
else:
options_chain.loc[option_mask, ['Bid', 'Ask', 'Delta']] = [option.Bid, option.Ask, option.Delta]
# Number of strikes on either side of the spot price (x2) for each option type (x2).
if len(options_chain) >= strike_proximity * 4:
break
return options_chain
if __name__ == '__main__':
client = TradeStationClient()
client.open_authorization_url()

View File

@ -0,0 +1,11 @@
from client import TradeStationClient
from datetime import datetime
from dotenv import load_dotenv
from os import getenv
load_dotenv()
client = TradeStationClient(getenv('TRADESTATION_REFRESH_TOKEN'))
options_chain = client.get_options_chain('$SPXW.X', expiration = datetime.now())
print(options_chain)

9
option.py Normal file
View File

@ -0,0 +1,9 @@
from dataclasses import dataclass
@dataclass
class Option:
Strike: str
Type: str
Bid: float
Ask: float
Delta: float

View File

@ -1,2 +1,3 @@
pandas
python-dotenv
requests

View File

@ -1,3 +1,5 @@
import pandas as pd
from client import TradeStationClient
from datetime import datetime
from dotenv import load_dotenv
@ -6,4 +8,6 @@ from os import getenv
load_dotenv()
client = TradeStationClient(getenv('TRADESTATION_REFRESH_TOKEN'))
client.stream_options_chain('$SPXW.X', expiration = datetime(2024, 1, 26))
for option in client.stream_options_chain('$SPXW.X', expiration = datetime.now()):
print(option)