Provide a nice wrapper to clients that streams options data into a pandas data frame
This commit is contained in:
parent
6cfa03edaf
commit
332dad3138
44
client.py
44
client.py
@ -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,14 +113,51 @@ 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()
|
||||
|
11
get_options_chain_example.py
Normal file
11
get_options_chain_example.py
Normal 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
9
option.py
Normal file
@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Option:
|
||||
Strike: str
|
||||
Type: str
|
||||
Bid: float
|
||||
Ask: float
|
||||
Delta: float
|
@ -1,2 +1,3 @@
|
||||
pandas
|
||||
python-dotenv
|
||||
requests
|
@ -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)
|
Loading…
Reference in New Issue
Block a user