From 6ddea890854ca7f31ffca032aeebda2c0d576963 Mon Sep 17 00:00:00 2001 From: moshferatu Date: Fri, 15 Sep 2023 08:20:36 -0700 Subject: [PATCH] Initial commit of Tastytrade API client --- requirements.txt | 1 + tastytrade/__init__.py | 1 + tastytrade/instrument_type.py | 5 ++++ tastytrade/option_type.py | 2 ++ tastytrade/order.py | 23 ++++++++++++++++ tastytrade/order_action.py | 4 +++ tastytrade/order_type.py | 5 ++++ tastytrade/price_effect.py | 2 ++ tastytrade/symbology.py | 6 +++++ tastytrade/tastytrade.py | 50 +++++++++++++++++++++++++++++++++++ tastytrade/time_in_force.py | 3 +++ 11 files changed, 102 insertions(+) create mode 100644 requirements.txt create mode 100644 tastytrade/__init__.py create mode 100644 tastytrade/instrument_type.py create mode 100644 tastytrade/option_type.py create mode 100644 tastytrade/order.py create mode 100644 tastytrade/order_action.py create mode 100644 tastytrade/order_type.py create mode 100644 tastytrade/price_effect.py create mode 100644 tastytrade/symbology.py create mode 100644 tastytrade/tastytrade.py create mode 100644 tastytrade/time_in_force.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..663bd1f --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/tastytrade/__init__.py b/tastytrade/__init__.py new file mode 100644 index 0000000..7d00fc0 --- /dev/null +++ b/tastytrade/__init__.py @@ -0,0 +1 @@ +from .tastytrade import Tastytrade \ No newline at end of file diff --git a/tastytrade/instrument_type.py b/tastytrade/instrument_type.py new file mode 100644 index 0000000..8a3d16a --- /dev/null +++ b/tastytrade/instrument_type.py @@ -0,0 +1,5 @@ +CRYPTOCURRENCY = 'Cryptocurrency' +EQUITY = 'Equity' +EQUITY_OPTION = 'Equity Option' +FUTURE = 'Future' +FUTURE_OPTION = 'Future Option' \ No newline at end of file diff --git a/tastytrade/option_type.py b/tastytrade/option_type.py new file mode 100644 index 0000000..79eb23f --- /dev/null +++ b/tastytrade/option_type.py @@ -0,0 +1,2 @@ +CALL = 'C' +PUT = 'P' \ No newline at end of file diff --git a/tastytrade/order.py b/tastytrade/order.py new file mode 100644 index 0000000..df83ea3 --- /dev/null +++ b/tastytrade/order.py @@ -0,0 +1,23 @@ +from .instrument_type import EQUITY_OPTION +from .order_action import SELL_TO_OPEN, BUY_TO_OPEN +from .order_type import LIMIT +from .price_effect import CREDIT +from .time_in_force import GTC + +def create_leg(instrument_type: str, symbol: str, action: str, quantity: int): + return {'instrument-type': instrument_type, 'symbol': symbol, 'action': action, 'quantity': quantity} + +def create_order(order_type: str, time_in_force: str, price: float, price_effect: str, legs: list): + return { + 'order-type': order_type, + 'time-in-force': time_in_force, + 'price': price, + 'price-effect': price_effect, + 'legs': legs + } + +def create_credit_spread(short_contract: str, long_contract: str, price: float, quantity: int, + instrument_type: str = EQUITY_OPTION, time_in_force: str = GTC): + short_leg = create_leg(instrument_type, short_contract, SELL_TO_OPEN, quantity) + long_leg = create_leg(instrument_type, long_contract, BUY_TO_OPEN, quantity) + return create_order(LIMIT, time_in_force, price, CREDIT, [short_leg, long_leg]) \ No newline at end of file diff --git a/tastytrade/order_action.py b/tastytrade/order_action.py new file mode 100644 index 0000000..72d8812 --- /dev/null +++ b/tastytrade/order_action.py @@ -0,0 +1,4 @@ +BUY_TO_OPEN = 'Buy to Open' +SELL_TO_OPEN = 'Sell to Open' +BUY_TO_CLOSE = 'Buy to Close' +SELL_TO_CLOSE = 'Sell to Close' \ No newline at end of file diff --git a/tastytrade/order_type.py b/tastytrade/order_type.py new file mode 100644 index 0000000..92a427a --- /dev/null +++ b/tastytrade/order_type.py @@ -0,0 +1,5 @@ +LIMIT = 'Limit' +MARKET = 'Market' +STOP = 'Stop' +STOP_LIMIT = 'Stop Limit' +NOTIONAL_MARKET = 'Notional Market' \ No newline at end of file diff --git a/tastytrade/price_effect.py b/tastytrade/price_effect.py new file mode 100644 index 0000000..c2c3b65 --- /dev/null +++ b/tastytrade/price_effect.py @@ -0,0 +1,2 @@ +CREDIT = 'Credit' +DEBIT = 'Debit' \ No newline at end of file diff --git a/tastytrade/symbology.py b/tastytrade/symbology.py new file mode 100644 index 0000000..818283f --- /dev/null +++ b/tastytrade/symbology.py @@ -0,0 +1,6 @@ +from datetime import datetime + +def zero_dte_spx_contract(option_type: str, strike: float) -> str: + contract_date = datetime.now().strftime('%y%m%d') + formatted_strike = f'{int(strike * 1000):08}' + return f'SPXW {contract_date}{option_type}{formatted_strike}' \ No newline at end of file diff --git a/tastytrade/tastytrade.py b/tastytrade/tastytrade.py new file mode 100644 index 0000000..5dd8d57 --- /dev/null +++ b/tastytrade/tastytrade.py @@ -0,0 +1,50 @@ +import json +import requests + +class Tastytrade: + + def __init__(self, username: str, password: str = None) -> None: + self.username = username + self.password = password + self.session_token = None + + def get(self, path: str, params: dict = {}) -> dict: + return requests.get( + url = f'https://api.tastytrade.com{path}', + headers = {'Authorization': self.session_token}, + params = params + ) + + def post(self, path: str, data: dict = {}) -> dict: + return requests.post( + url = f'https://api.tastytrade.com{path}', + headers = {'Content-Type': 'application/json', 'Authorization': self.session_token}, + data = json.dumps(data) + ) + + def login(self) -> dict: + response = self.post( + path = '/sessions', + data = {'login': self.username, 'password': self.password} + ) + if response.status_code == 201: + self.session_token = response.json()['data']['session-token'] + return response.json() + + def get_accounts(self) -> dict: + return self.get(path = '/customers/me/accounts').json() + + def get_live_orders(self, account_number: str) -> dict: + return self.get(path = f'/accounts/{account_number}/orders/live').json() + + def get_option_chain(self, symbol: str) -> dict: + return self.get(path = f'/option-chains/{symbol}/nested').json() + + def get_option_chain_compact(self, symbol: str) -> dict: + return self.get(path = f'/option-chains/{symbol}/compact').json() + + def get_positions(self, account_number: str) -> dict: + return self.get(path = f'/accounts/{account_number}/positions').json() + + def submit_order(self, account_number: str, order: dict) -> dict: + return self.post(path = f'/accounts/{account_number}/orders', data = order).json() \ No newline at end of file diff --git a/tastytrade/time_in_force.py b/tastytrade/time_in_force.py new file mode 100644 index 0000000..e082675 --- /dev/null +++ b/tastytrade/time_in_force.py @@ -0,0 +1,3 @@ +DAY = 'Day' +GTC = 'GTC' +GTD = 'GTD' \ No newline at end of file