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 requests
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from option import Option
|
||||||
from os import getenv
|
from os import getenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@ -110,15 +113,52 @@ class TradeStationClient:
|
|||||||
response = requests.get(url, headers = headers, params = params, stream = True)
|
response = requests.get(url, headers = headers, params = params, stream = True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# TODO: Return a generator to the client.
|
|
||||||
for line in response.iter_lines():
|
for line in response.iter_lines():
|
||||||
if line:
|
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:
|
except Exception as e:
|
||||||
print(f'Error while streaming data: {str(e)}')
|
print(f'Error while streaming data: {str(e)}')
|
||||||
finally:
|
finally:
|
||||||
response.close()
|
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__':
|
if __name__ == '__main__':
|
||||||
client = TradeStationClient()
|
client = TradeStationClient()
|
||||||
client.open_authorization_url()
|
client.open_authorization_url()
|
||||||
|
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
|
python-dotenv
|
||||||
requests
|
requests
|
@ -1,3 +1,5 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
from client import TradeStationClient
|
from client import TradeStationClient
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
@ -6,4 +8,6 @@ from os import getenv
|
|||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
client = TradeStationClient(getenv('TRADESTATION_REFRESH_TOKEN'))
|
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