def get_stream_client(self): easy_client = auth.easy_client( api_key=self.customer_key, redirect_uri=self.callback_url, token_path=self.token_path + "/token", ) return StreamClient(easy_client, account_id=self.account_id)
def test_token_file(self, client_from_token_file): webdriver_func = MagicMock() client_from_token_file.return_value = self.token self.assertEquals( self.token, auth.easy_client(API_KEY, REDIRECT_URL, self.pickle_path))
async def stream_account_activity(self): client = easy_client( api_key=self._apiKey, redirect_uri=REDIRECT_URI, token_path=self._loginDataPath, webdriver_func=lambda: webdriver.Chrome(ChromeDriverManager().install())) stream_client = StreamClient(client, account_id=int(self._accountID)) await self.read_stream(self.send_message, stream_client)
def authenticate(self): from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager with webdriver.Chrome(ChromeDriverManager().install()) as driver: self.client = easy_client(api_key=self.key, redirect_uri=self.callback_url, token_path=self.token_path, webdriver_func=driver)
def __init__(self, methodName): super().__init__(methodName) self.client = easy_client( api_key=os.getenv("TDA_API_KEY"), redirect_uri="http://localhost", token_path="/home/dkasabovn/Dev/python/ameritrade/token.pickle", ) self.ticker = "AAPL" self.algo = TestImplementation(self.ticker) self.algo.temp_add_client(self.client)
def initialize(self): self.tda_client = easy_client( api_key=self.api_key, redirect_uri="http://localhost", token_path="/home/dkasabovn/Dev/python/ameritrade/token.pickle", webdriver_func=make_webdriver) self.stream_client = StreamClient(self.tda_client, account_id=self.account_id) self.stream_client.add_chart_equity_handler(self.handle_ohlc)
async def main(): api_key = os.getenv("TDA_API_KEY") client = easy_client( api_key=api_key, redirect_uri="http://localhost", token_path="/home/dkasabovn/Dev/python/ameritrade/token.pickle", webdriver_func=make_webdriver) producer = GonseProducer(client, ["AAPL"]) producer.initialize() await producer.stream()
def test_token_file_with_enums_enabled(self, client_from_token_file): self.write_token() webdriver_func = MagicMock() client_from_token_file.return_value = self.token self.assertEquals( self.token, auth.easy_client(API_KEY, REDIRECT_URL, self.json_path)) client_from_token_file.assert_called_once_with(self.json_path, API_KEY, asyncio=False, enforce_enums=True)
def __init__(self): def make_webdriver(): from selenium import webdriver driver = webdriver.Chrome() atexit.register(lambda: driver.quit()) return driver self.client = easy_client( api_key=api_key, redirect_uri=redirect_uri, token_path=token_path, webdriver_func=make_webdriver, )
def initialize(self): """ Create the clients and log in. Using easy_client, we can get new creds from the user via the web browser if necessary """ self.tda_client = easy_client(api_key=self.api_key, redirect_uri='https://localhost:8080', token_path=self.credentials_path) self.stream_client = StreamClient(self.tda_client, account_id=self.account_id) # The streaming client wants you to add a handler for every service type self.stream_client.add_timesale_equity_handler( self.handle_timesale_equity)
def main(): c = easy_client(api_key=client_id, redirect_uri=redirect_uri, token_path='/home/carmelo/Documents/StockMarket/StockCode/TOS/token.pickle') fpt = get_fpt(c, trades=4) buy_dict_day = 0 downloaded = True bought_today = [] if os.path.exists('TOS/positions.pickle'): p = get_positions() while True: day = get_day_params() day_condition = all([day[3] * 24 + day[4] / 60 >= 6 * 24 + 40 / 60, day[3] < 13]) download_condition = all([16 <= day[3] < 23, not downloaded]) if all([day[3] * 24 + day[4] / 60 >= 6 * 24 + 30 / 60, buy_dict_day != day[2]]): downloaded = False buy_dict = get_buy_list(c, 'SO', fpt) #buy_dict = get_buy_list(c, 'SO', fpt, buy_dict) buy_dict_day = day[2] try: account, round_trips, available_funds, num_trades_available = get_account_deets(c, funds_per_trade=fpt) num_trades_available = 0 if num_trades_available > 0 and len(buy_dict) > 0 and day_condition: if len(buy_dict) >= num_trades_available: buy_today = random.sample(list(buy_dict.keys()), num_trades_available) else: buy_today = list(buy_dict.keys()) buy_today = [bt for bt in buy_today if bt not in bought_today] p = buy(c, buy_dict, buy_today) if os.path.exists('TOS/positions.pickle'): for stock in p.keys(): if p[stock]['buy_status'] == 'FILLED' and p[stock]['sell_order_id'] == 0: bought_today.append(stock) p[stock] = update_fill_price(c, p[stock]) sell(c, stock, p) if day_condition: p = monitor(c, p) status_bar(p) except Exception: print(traceback.format_exc()) pass if day[3] > 13 or day[3] < 6: do_sleep(600, 601) else: do_sleep(44, 45) if download_condition: bought_today = [] downloaded = True download_data() process_data()
def test_no_token_file_with_wd_func(self, client_from_token_file, client_from_login_flow): webdriver_func = MagicMock() client_from_token_file.side_effect = FileNotFoundError() client_from_login_flow.return_value = 'returned client' webdriver_func = MagicMock() self.assertEquals( 'returned client', auth.easy_client(API_KEY, REDIRECT_URL, self.pickle_path, webdriver_func=webdriver_func)) webdriver_func.assert_called_once() client_from_login_flow.assert_called_once()
def __init__(self): self.account_id = '275356186' self.key = 'FA3ISKLEGYIFXQRSUJQCB93AKXFRGZUK' self.callback_url = 'https://localhost:8080' self.token_path = '../doc/token' # Setup client try: self.client = easy_client(api_key=self.key, redirect_uri=self.callback_url, token_path=self.token_path) except FileNotFoundError: self.authenticate() # Setup stream self.stream = StreamClient(self.client, account_id=self.account_id)
def initialize(self): """ Create the clients and log in. Using easy_client, we can get new creds from the user via the web browser if necessary """ self.tda_client = easy_client( # You can customize your browser here webdriver_func=lambda: webdriver.Chrome(), #webdriver_func=lambda: webdriver.Firefox(), #webdriver_func=lambda: webdriver.Safari(), #webdriver_func=lambda: webdriver.Ie(), api_key=self.api_key, redirect_uri='https://localhost:8080', token_path=self.credentials_path) self.stream_client = StreamClient(self.tda_client, account_id=self.account_id) # The streaming client wants you to add a handler for every service type self.stream_client.add_timesale_equity_handler( self.handle_timesale_equity)
def test_no_token_file_with_wd_func_with_enums_enabled( self, client_from_token_file, client_from_login_flow): client_from_token_file.side_effect = SystemExit() client_from_login_flow.return_value = 'returned client' webdriver_func = MagicMock() self.assertEquals( 'returned client', auth.easy_client(API_KEY, REDIRECT_URL, self.json_path, webdriver_func=webdriver_func)) webdriver_func.assert_called_once() client_from_login_flow.assert_called_once_with(_, API_KEY, REDIRECT_URL, self.json_path, asyncio=False, enforce_enums=True)
DELETE FROM tda_stock_price_minute """) connection.commit() cursor.execute(""" SELECT symbol, name FROM stock JOIN stock_strategy ON stock_strategy.stock_id = stock.id """) stocks = cursor.fetchall() symbols = [stock['symbol'] for stock in stocks] logging.info(symbols) client = easy_client(api_key=config.tda_api_key, redirect_uri=config.tda_redirect_uri, token_path=config.tda_token_path) stream_client = StreamClient(client, account_id=config.tda_account_id) async def insert_stream_data(msg, symbols): data = json.loads(msg) with sqlite3.connect(config.DB_FILE) as conn: conn.execute("""CREATE TABLE IF NOT EXISTS tda_stock_price_minute ( seq INTEGER, key TEXT, open REAL, high REAL, low REAL,
import traceback import httpx from tda.auth import easy_client from tda.auth import client_from_login_flow from Resources.config import client_id, redirect_url from selenium import webdriver import pandas as pd try: # Tries to initialize tda client client = easy_client(api_key=client_id, redirect_uri=redirect_url, token_path='resources/token.txt', webdriver_func=webdriver.Chrome) except Exception as exc: # Gets new token if previous token is expired client = client_from_login_flow(webdriver.Chrome(), api_key=client_id, redirect_url=redirect_url, token_path='resources/token.txt', redirect_wait_time_seconds=0.1, max_waits=3000, asyncio=False, token_write_func=None) traceback.print_exc(exc) def get_price_history(symbol, start, end, frequencyType, periodType, frequency): r = client.get_price_history(symbol, period_type=periodType, frequency=frequency,
import asyncio import psycopg2 from tda.auth import easy_client from tda.streaming import StreamClient import pandas as pd import config CONN = psycopg2.connect(host=config.DB_HOST, database=config.DB_NAME, user=config.DB_USER, password=config.DB_PASS) CURSOR = CONN.cursor() CLIENT = easy_client(api_key=config.api_key, redirect_uri=config.redirect_uri, token_path=config.token_path) STREAM_CLIENT = StreamClient(CLIENT, account_id=config.account_id) def order_book_handler(msg): """ This is the Message Handler, and store streaming Data in Timescale DB """ count = len(msg['content']) CONN.commit() try: for i in range(count): dict2 = {**msg['content'][i]}
def test_no_token_file_no_wd_func(self, client_from_token_file): webdriver_func = MagicMock() client_from_token_file.side_effect = FileNotFoundError() with self.assertRaises(FileNotFoundError): auth.easy_client(API_KEY, REDIRECT_URL, self.pickle_path)
from tda.auth import easy_client from tda.streaming import StreamClient import login.config as config #create the client to talk to td ameritrade #initialize a session client = easy_client(config.API_KEY, config.REDIRECT_URI, config.TOKEN_PATH) stream_client = StreamClient(client, account_id=config.ACCOUNT_ID) stream_client2 = StreamClient(client, account_id=config.ACCOUNT_ID)
def main(): # Easy client with user account variables c = easy_client(consumer_key, redirect_uri, token_path, make_webdriver) # Set options to be hedged symbols_to_hedge = ['SPY_041621C495'] # The threshold that an option's delta is allowed to move before # rehedging. For example, if threshold = 5, delta can increase/decrease # by 5 before rehedging, an effective range of 10 delta. This delta # is per 100 shares (delta * 100). The larger the threshold # the less hedged you may be at a given time, however this also reduces # transaction costs incurred by adjusting the hedge. threshold = 5 # Get positions for account account_info = c.get_account( account_id, fields=[c.Account.Fields.POSITIONS, c.Account.Fields.ORDERS]) account_info_json = account_info.json() # Seperate equity and option positions into seperate dataframes equity_positions_list = [] option_positions_list = [] for entry in account_info_json['securitiesAccount']['positions']: if entry['instrument']['assetType'] == 'EQUITY': equity_positions_list.append(entry) elif entry['instrument']['assetType'] == 'OPTION': option_positions_list.append(entry) if equity_positions_list: equity_positions = pd.DataFrame(equity_positions_list) equ_pos_ticker_list = [] equ_pos_cusip_list = [] equ_pos_assetType_list = [] for row in equity_positions['instrument']: equ_pos_ticker_list.append(row['symbol']) equ_pos_cusip_list.append(row['cusip']) equ_pos_assetType_list.append(row['assetType']) equity_positions['symbol'] = equ_pos_ticker_list equity_positions['cusip'] = equ_pos_cusip_list equity_positions['assetType'] = equ_pos_assetType_list equity_positions.drop(columns='instrument', inplace=True) equity_positions.set_index('symbol', inplace=True) if option_positions_list: option_positions = pd.DataFrame(option_positions_list) opt_pos_symbol_list = [] opt_pos_description_list = [] opt_pos_putCall_list = [] opt_pos_assetType_list = [] opt_pos_underlyingSymbol_list = [] for row in option_positions['instrument']: opt_pos_symbol_list.append(row['symbol']) opt_pos_description_list.append(row['description']) opt_pos_putCall_list.append(row['putCall']) opt_pos_assetType_list.append(row['assetType']) opt_pos_underlyingSymbol_list.append(row['underlyingSymbol']) option_positions['symbol'] = opt_pos_symbol_list option_positions['description'] = opt_pos_description_list option_positions['putCall'] = opt_pos_putCall_list option_positions['assetType'] = opt_pos_assetType_list option_positions['underlyingSymbol'] = opt_pos_underlyingSymbol_list option_positions.drop(columns='instrument', inplace=True) option_positions.set_index('symbol', inplace=True) # Calculate total quantity of holdings for both equities and options equity_positions['totalQuantity'] = equity_positions[ 'longQuantity'] + equity_positions['shortQuantity'] option_positions['totalQuantity'] = option_positions[ 'longQuantity'] + option_positions['shortQuantity'] # Check if the underlying of an option is in current positions, # if it is then add the underlying's quantity to the option # positions df. If it is not, then set quantity to 0 and # add to options positions df. for symbol in option_positions['underlyingSymbol']: if equity_positions.index.isin([symbol]).any(): underlyingQuantity = equity_positions.loc[ equity_positions.index == symbol, 'totalQuantity'].iloc[0] option_positions.loc[option_positions['underlyingSymbol'] == symbol, 'underlyingQuantity'] = underlyingQuantity else: option_positions.loc[option_positions['underlyingSymbol'] == symbol, 'underlyingQuantity'] = 0 # If option to hedge is in portfolio, then it is appended # to list, if it is not, it is appended to a different list # and a message is printed warning that you must purchase # the options before hedging them. symbols_to_hedge_in_holdings = [] symbols_to_hedge_not_in_holdings = [] for symbol in symbols_to_hedge: if option_positions.index.isin([symbol]).any(): symbols_to_hedge_in_holdings.append(symbol) else: symbols_to_hedge_not_in_holdings.append(symbol) print( 'Could not hedge the following options because they are not currently held in portfolio:', '\n', symbols_to_hedge_not_in_holdings) continue # Gets quotes for options that are in portfolio and # set to be hedged, then merges the quotes and option # positions df into a new option_positions_to_hedge df. option_quotes_resp = c.get_quotes(symbols=symbols_to_hedge_in_holdings) option_quotes_df = pd.DataFrame.from_dict(option_quotes_resp.json(), orient='index') option_positions_to_hedge = pd.merge(option_positions.loc[ option_positions.index.isin(symbols_to_hedge_in_holdings)], option_quotes_df, left_index=True, right_index=True) # Finds the total greek exposure for each option # by multiplying the quantity of an option by # the given greek then multiplying by 100 # and adds to the option_positions_to_hedge df greeks = ['delta', 'gamma', 'theta', 'vega'] for greek in greeks: option_positions_to_hedge['total' + greek.capitalize()] = abs( option_positions_to_hedge[greek] ) * option_positions_to_hedge['totalQuantity'] * 100 # A threaded function that places orders def place_orders(symbol): # Gets current date and time now = datetime.now().strftime('%d-%m-%y %I:%M:%S %p') # Finds the total deltas for options to be hedged on a particular underlying total_deltas_for_options_on_underlying = option_positions_to_hedge.loc[ option_positions_to_hedge['underlyingSymbol'] == symbol]['totalDelta'].sum() # Finds the total quantity for a particular underlying underlying_quantity = option_positions_to_hedge.loc[ option_positions_to_hedge['underlyingSymbol'] == symbol]['underlyingQuantity'] # If the stock underlying an option to be hedged # is not owned, then the underlying quantity is set to 0. # If it is owned, then the quantity is set from the series as an integer if underlying_quantity.empty: underlying_quantity = 0 else: underlying_quantity = int(underlying_quantity.iloc[0]) # Determines the number of shares needed to be bought/sold to be delta neutral. # This is done by multiplying the total number of deltas for an option by -1, # then subtracting the quantity of the underlying for the options. shares_needed_to_hedge = int(total_deltas_for_options_on_underlying * -1 - underlying_quantity) # Place Orders, due to shorts and longs having seperate functions, it # complicates the order process, and it can be hard to follow. # The process itself is fairly straightforward, the number of shares # owned should be equal to the inverse of the total deltas on a particular # underlying. So shares will either be purchased or sold to reach # this condition. Adjustment is made when the total deltas # for the options on an underlying move past the previously set threshold, # either above or below. if shares_needed_to_hedge > threshold: if underlying_quantity < 0 and underlying_quantity + shares_needed_to_hedge < 0: #Buy to cover shares_needed_to_hedge order_specs = equities.equity_buy_to_cover_market( symbol=symbol, quantity=shares_needed_to_hedge).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order = c.place_order(account_id, order_specs) pprint( pd.DataFrame(order_specs['orderLegCollection'], index=[now])) elif underlying_quantity < 0 and underlying_quantity + shares_needed_to_hedge > 0: #Buy to cover abs(underlying_quantity) order1_specs = equities.equity_buy_to_cover_market( symbol=symbol, quantity=abs(underlying_quantity)).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order1 = c.place_order(account_id, order1_specs) pprint( pd.DataFrame(order1_specs['orderLegCollection'], index=[now])) #Buy shares_needed_to_hedge - abs(underlying_quantity) order2_specs = equities.equity_buy_market( symbol=symbol, quantity=shares_needed_to_hedge - abs(underlying_quantity)).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order2 = c.place_order(account_id, order2_specs) pprint( pd.DataFrame(order2_specs['orderLegCollection'], index=[now])) elif underlying_quantity > 0: #Buy shares_needed_to_hedge order_specs = equities.equity_buy_market( symbol=symbol, quantity=shares_needed_to_hedge).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order = c.place_order(account_id, order_specs) pprint( pd.DataFrame(order_specs['orderLegCollection'], index=[now])) elif shares_needed_to_hedge < -threshold: if underlying_quantity > 0 and underlying_quantity + shares_needed_to_hedge > 0: #Sell abs(shares_needed_to_hedge) order_specs = equities.equity_sell_market( symbol=symbol, quantity=abs(shares_needed_to_hedge)).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order = c.place_order(account_id, order_specs) pprint( pd.DataFrame(order_specs['orderLegCollection'], index=[now])) elif underlying_quantity > 0 and underlying_quantity + shares_needed_to_hedge < 0: #Sell underlying_quantity order1_specs = equities.equity_sell_market( symbol=symbol, quantity=underlying_quantity).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order1 = c.place_order(account_id, order1_specs) pprint( pd.DataFrame(order1_specs['orderLegCollection'], index=[now])) #Sell short abs(underlying_quantity + shares_needed_to_hedge) order2_specs = equities.equity_sell_short_market( symbol=symbol, quantity=abs(underlying_quantity + shares_needed_to_hedge)).set_duration( Duration.DAY).set_session( Session.SEAMLESS).build() order2 = c.place_order(account_id, order2_specs) pprint( pd.DataFrame(order2_specs['orderLegCollection'], index=[now])) elif underlying_quantity < 0: #Sell to open abs(shares_needed_to_hedge) order_specs = equities.equity_sell_short_market( symbol=symbol, quantity=abs(shares_needed_to_hedge)).set_duration( Duration.DAY).set_session(Session.SEAMLESS).build() order = c.place_order(account_id, order_specs) pprint( pd.DataFrame(order_specs['orderLegCollection'], index=[now])) # Since each option has an underlying value in the # option_positions_to_hedge df, this can result in duplicated # symbols if there are multiple options on the same underlying # to be hedge. This finds the unique underlyings in the # option_positions_to_hedge df, and appends to list. unique_symbols = option_positions_to_hedge['underlyingSymbol'].unique() # Iterate through the unique symbols in the unique symbols list # pass each one in a threaded process to the place_orders df. # This means that each stock is bought/sold as needed to neutralize # the delta of the options to be hedged. By running as a # threaded process this should provide significant speed # increases if there are many equities to iterate through. thread_list = [] def thread_place_orders(): for symbol in unique_symbols: threadProcess = threading.Thread(name='simplethread', target=place_orders, args=[symbol]) thread_list.append(threadProcess) for thread in thread_list: thread.start() for thread in thread_list: thread.join() thread_place_orders()
geckodriver_path = r'/Users/haydenrose/Webdrivers/geckodriver' # Creates Webdriver for Selenium def make_webdriver(): # Import selenium here because it's slow to import from selenium import webdriver driver = webdriver.Firefox(executable_path=geckodriver_path) atexit.register(lambda: driver.quit()) return driver # Sets td-api Client Object. # Will Create Refresh Token with OAUTH and Grab With Selenium # if it Doesn't Exist in Working Folder. c = easy_client(consumer_key, redirect_uri, token_path, make_webdriver) def options_chain_cleaner(options_chain, only_type=False): """ Takes unformatted option chain csv and returns cleaned up df. Specify only_type='Calls' or 'Puts' if only wanting one or other, specify False if wanting both and 2 dataframes will be returned, calls first and puts second. i.e. calls, puts = func('file.csv') """ if only_type == 'Calls': Calls = options_chain['callExpDateMap'].values() call_option_list = []
import pandas as pd from tda.auth import easy_client from fybot.common import config from functions import * from IPython.utils import io from datetime import datetime, timedelta from time import sleep # from tda.client import client # Creates connection with TDA database c = easy_client(config.api_key, config.redirect_uri, config.token_path, make_webdriver) print("Client Authorization process complete.") #---------------------------------------------------------------- #downloads all 7-8k active tickers/symbols (review function for filters) df = import_symbols(reference_path="../pages/datasets/") symbols_list = df.index.to_list() #---------------------------------------------------------------- #if a sigle quote is needed s = 'AMD' quote_df = get_quote_info(s, c) print(quote_df) print(f"The last price for {s.upper()} is {quote_df.loc['lastPrice'][0]}.") #---------------------------------------------------------------- # for request with multiple symbols, breaks long lists into batches batch_size = 250 symbols_batches = split_symbol_list(symbols_list, batch_size)
from tda.auth import easy_client from tda.client import Client from tda.streaming import StreamClient import asyncio import json import config client = easy_client(api_key=config.API_KEY, redirect_uri=config.REDIRECT_URI, token_path=config.TOKEN_PATH) stream_client = StreamClient(client, account_id=config.ACCOUNT_ID) def order_book_handler(msg): print(json.dumps(msg, indent=4)) async def read_stream(): await stream_client.login() await stream_client.quality_of_service(StreamClient.QOSLevel.DELAYED) await stream_client.nasdaq_book_subs(['GOOG']) stream_client.add_nasdaq_book_handler(order_book_handler) while True: await stream_client.handle_message() asyncio.get_event_loop().run_until_complete(read_stream())