class TDSession(TestCase): """Will perform a unit test for the TD session.""" def setUp(self) -> None: """Set up the `TDClient`.""" # Grab configuration values. config = ConfigParser() config.read('config/config.ini') # Load the values. CLIENT_ID = config.get('main', 'CLIENT_ID') REDIRECT_URI = config.get('main', 'REDIRECT_URI') JSON_PATH = config.get('main', 'JSON_PATH') ACCOUNT_NUMBER = config.get('main', 'ACCOUNT_NUMBER') # Initalize the session. self.td_session = TDClient(client_id=CLIENT_ID, redirect_uri=REDIRECT_URI, credentials_path=JSON_PATH, account_number=ACCOUNT_NUMBER) def test_creates_instance_of_session(self): """Create an instance and make sure it's a `TDClient` object.""" self.assertIsInstance(self.td_session, TDClient) def test_login(self): """Test whether the session is authenticated or not.""" self.assertTrue(self.td_session.login()) self.assertTrue(self.td_session.authstate) def test_state(self): """Make sure the state is updated.""" self.assertIsNotNone(self.td_session.state['refresh_token']) self.assertIsNotNone(self.td_session.state['access_token']) self.assertNotEqual(self.td_session.state['refresh_token_expires_at'], 0) self.assertNotEqual(self.td_session.state['access_token_expires_at'], 0) def test_single_get_quotes(self): """Test Getting a Single quote.""" # Grab a single quote. quotes = self.td_session.get_quotes(instruments=['MSFT']) # See if the Symbol is in the Quotes. self.assertIn('MSFT', quotes) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_single_quotes.jsonc', 'w+') as data_file: json.dump(obj=quotes, fp=data_file, indent=3) def test_get_quotes(self): """Test Getting Multiple Quotes.""" # Grab multiple Quotes. quotes = self.td_session.get_quotes(instruments=['MSFT', 'AAPL']) # See if the Symbols are in the Quotes. self.assertTrue(set(['MSFT', 'AAPL']).issuperset(set(quotes.keys()))) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_multiple_quotes.jsonc', 'w+') as data_file: json.dump(obj=quotes, fp=data_file, indent=3) def test_get_accounts(self): """Test Get Accounts.""" accounts = self.td_session.get_accounts(account='all', fields=['orders', 'positions']) self.assertIn('positions', accounts[0]['securitiesAccount']) self.assertIn('currentBalances', accounts[0]['securitiesAccount']) # self.assertIn('orderStrategies', accounts[0]['securitiesAccount']) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_accounts.jsonc', 'w+') as data_file: json.dump(obj=accounts, fp=data_file, indent=3) def test_create_stream_session(self): """Test Creating a new streaming session.""" stream_session = self.td_session.create_streaming_session() self.assertIsInstance(stream_session, TDStreamerClient) def test_get_transactions(self): """Test getting transactions.""" # `get_transactions` Endpoint. Should not return an error transaction_data_multi = self.td_session.get_transactions( account=self.td_session.account_number, transaction_type='ALL') # Make sure it's a list. self.assertIsInstance(transaction_data_multi, list) self.assertIn('type', transaction_data_multi[0]) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_transaction_data.jsonc', 'w+') as data_file: json.dump(obj=transaction_data_multi, fp=data_file, indent=3) def test_get_market_hours(self): """Test get market hours.""" # `get_market_hours` Endpoint with multiple values market_hours_multi = self.td_session.get_market_hours( markets=['EQUITY', 'FOREX'], date=datetime.today().isoformat()) # If it's a weekend nothing is returned, so raise an error. if datetime.today().weekday() in (5, 6): # Make sure it's a list. self.assertIsInstance(market_hours_multi, dict) self.assertIn('isOpen', market_hours_multi['equity']['equity']) else: # Make sure it's a list. self.assertIsInstance(market_hours_multi, dict) self.assertIn('isOpen', market_hours_multi['equity']['EQ']) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_market_hours.jsonc', 'w+') as data_file: json.dump(obj=market_hours_multi, fp=data_file, indent=3) def test_get_instrument(self): """Test getting an instrument.""" # `get_instruments` Endpoint. get_instrument = self.td_session.get_instruments(cusip='594918104') # Make sure it's a list. self.assertIsInstance(get_instrument, list) self.assertIn('cusip', get_instrument[0]) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_instrument.jsonc', 'w+') as data_file: json.dump(obj=get_instrument, fp=data_file, indent=3) def test_chart_history(self): """Test getting historical prices.""" # Define a list of all valid periods valid_values = { 'minute': { 'day': [1, 2, 3, 4, 5, 10] }, 'daily': { 'month': [1, 2, 3, 6], 'year': [1, 2, 3, 5, 10, 15, 20], 'ytd': [1] }, 'weekly': { 'month': [1, 2, 3, 6], 'year': [1, 2, 3, 5, 10, 15, 20], 'ytd': [1] }, 'monthly': { 'year': [1, 2, 3, 5, 10, 15, 20] } } # Define the static arguments. hist_symbol = 'MSFT' hist_needExtendedHoursData = False for frequency_type in valid_values.keys(): frequency_periods = valid_values[frequency_type] for frequency_period in frequency_periods.keys(): possible_values = frequency_periods[frequency_period] for value in possible_values: # Define the dynamic arguments - I want 5 DAYS of historical 1-minute bars. hist_periodType = frequency_period hist_period = value hist_frequencyType = frequency_type hist_frequency = 1 # make the request historical_prices = self.td_session.get_price_history( symbol=hist_symbol, period_type=hist_periodType, period=hist_period, frequency_type=hist_frequencyType, frequency=hist_frequency, extended_hours=hist_needExtendedHoursData) self.assertIsInstance(historical_prices, dict) self.assertFalse(historical_prices['empty']) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_historical_prices.jsonc', 'w+') as data_file: json.dump(obj=historical_prices, fp=data_file, indent=3) def test_custom_historical_prices(self): """Test getting historical prices for a custom date range.""" # The max look back period for minute data is 31 Days. lookback_period = 10 # Define today. today_00 = datetime.now() # Define 300 days ago. today_ago = datetime.now() - timedelta(days=lookback_period) # The TD API expects a timestamp in milliseconds. However, the timestamp() method only returns to seconds so multiply it by 1000. today_00 = str(int(round(today_00.timestamp() * 1000))) today_ago = str(int(round(today_ago.timestamp() * 1000))) # These values will now be our startDate and endDate parameters. hist_startDate = today_ago hist_endDate = today_00 # Define the dynamic arguments. hist_periodType = 'day' hist_frequencyType = 'minute' hist_frequency = 1 # Make the request historical_custom = self.td_session.get_price_history( symbol='MSFT', period_type=hist_periodType, frequency_type=hist_frequencyType, start_date=hist_startDate, end_date=hist_endDate, frequency=hist_frequency, extended_hours=True) self.assertIsInstance(historical_custom, dict) self.assertFalse(historical_custom['empty']) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_historical_prices.jsonc', 'w+') as data_file: json.dump(obj=historical_custom, fp=data_file, indent=3) def test_search_instruments(self): """Test Searching for Instruments.""" # `search_instruments` Endpoint instrument_search_data = self.td_session.search_instruments( symbol='MSFT', projection='symbol-search') self.assertIsInstance(instrument_search_data, dict) self.assertIn('MSFT', instrument_search_data) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_search_instrument.jsonc', 'w+') as data_file: json.dump(obj=instrument_search_data, fp=data_file, indent=3) def test_get_movers(self): """Test getting Market movers.""" # `get_movers` Endpoint movers_data = self.td_session.get_movers(market='$DJI', direction='up', change='value') if datetime.today().weekday() in (5, 6): self.assertIsInstance(movers_data, list) self.assertFalse(movers_data) else: self.assertIsInstance(movers_data, list) self.assertIn('symbol', movers_data[0]) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_movers.jsonc', 'w+') as data_file: json.dump(obj=movers_data, fp=data_file, indent=3) def test_get_user_preferences(self): """Test getting user preferences.""" # `get_preferences` endpoint. Should not return an error preference_data = self.td_session.get_preferences( account=self.td_session.account_number) self.assertIsInstance(preference_data, dict) self.assertIn('expressTrading', preference_data) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_account_preferences.jsonc', 'w+') as data_file: json.dump(obj=preference_data, fp=data_file, indent=3) def test_get_user_principals(self): """Test getting user principals.""" # `get_preferences` endpoint. Should not return an error user_principals = self.td_session.get_user_principals( fields=['preferences', 'surrogateIds']) self.assertIsInstance(user_principals, dict) self.assertIn('userId', user_principals) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_user_principals.jsonc', 'w+') as data_file: json.dump(obj=user_principals, fp=data_file, indent=3) def test_get_streamer_keys(self): """Test getting user preferences.""" # `get_subscription_keys` endpoint. Should not return an error streamer_keys = self.td_session.get_streamer_subscription_keys( accounts=[self.td_session.account_number]) self.assertIsInstance(streamer_keys, dict) self.assertIn('keys', streamer_keys) # Save the data. if SAVE_FLAG: with open('samples/responses/sample_streamer_keys.jsonc', 'w+') as data_file: json.dump(obj=streamer_keys, fp=data_file, indent=3) def tearDown(self) -> None: """Teardown the Robot.""" self.td_session = None
# `get_accounts` Endpoint with single values accounts_data_single = TDSession.get_accounts( account='<ACCOUNT_NUMBER>', fields=['orders'] ) # `get_accounts` Endpoint with single values accounts_data_multi = TDSession.get_accounts( account='all', fields=['orders'] ) # `get_transactions` Endpoint. Should not return an error transaction_data_multi = TDSession.get_transactions( account='<ACCOUNT_NUMBER>', transaction_type='ALL' ) # `get_preferences` endpoint. Should not return an error preference_data = TDSession.get_preferences(account='<ACCOUNT_NUMBER>') # `get_subscription_keys` endpoint. Should not return an error streamer_keys = TDSession.get_streamer_subscription_keys( accounts=['<ACCOUNT_NUMBER>'] ) # `get_user_ principals` endpoint. Should not return an error. prinicpals_data = TDSession.get_user_principals( fields=['preferences', 'surrogateIds'] )
# `get_instruments` Endpoint get_instrument_data = TDSession.get_instruments(cusip='594918104') # `get_market_hours` Endpoint with multiple values market_hours_multi = TDSession.get_market_hours( markets=['EQUITY', 'FOREX'], date=datetime.today().isoformat()) # `get_accounts` Endpoint with single values accounts_data_single = TDSession.get_accounts(account=config.ACCOUNT_NUMBER, fields=['orders']) # `get_accounts` Endpoint with single values accounts_data_multi = TDSession.get_accounts(account='all', fields=['orders']) # `get_transactions` Endpoint. Should not return an error transaction_data_multi = TDSession.get_transactions( account=config.ACCOUNT_NUMBER, transaction_type='ALL') # `get_preferences` endpoint. Should not return an error preference_data = TDSession.get_preferences(account=config.ACCOUNT_NUMBER) # `get_subscription_keys` endpoint. Should not return an error streamer_keys = TDSession.get_streamer_subscription_keys( accounts=[config.ACCOUNT_NUMBER]) # `get_user_ principals` endpoint. Should not return an error. prinicpals_data = TDSession.get_user_principals( fields=['preferences', 'surrogateIds']) # # `get_transactions` Endpoint with single values # transaction_data_single = TDSession.get_transactions(transaction_id= 'YOUR_TRANSACTION_ID')
account_number = ACCOUNT_NUMBER, account_password = ACCOUNT_PASSWORD, consumer_id = CONSUMER_ID, redirect_uri = REDIRECT_URI, secret_questions = SECRET_QUESTIONS ) sess.login() # run job every end of date before midnight # start date exclusive, end date inclusive # for daily job, endData should be today today = date.today() delta = dateutil.relativedelta.relativedelta(days=1) startDt = (today - delta).strftime("%Y-%m-%d") endDt = today.strftime("%Y-%m-%d") data = sess.get_transactions( account = ACCOUNT_ID, transaction_type = 'TRADE', start_date=startDt, end_date=endDt ) trades = list(filter(lambda entry: entry['type'] == 'TRADE', data)) optionTrades = filter(lambda entry: entry['transactionItem']['instrument']['assetType'] == 'OPTION', trades) df = pd.DataFrame(columns=orderedKeys, data=[processOptionTrade(entry) for entry in optionTrades]) df = df.sort_values(["orderId", "leg"]) # insert today's option trades into database from config import DB_USERNAME, DB_PASSWORD, DB_PORT, DB_HOST from util.DB import DB db = DB(username=DB_USERNAME, password=DB_PASSWORD, host=DB_HOST, port=DB_PORT, database="trading") df.to_sql('options', db.engine, if_exists='append', index=False)
# TEST - `get_market_hours` Endpoint with multiple values. Should not return an error market_hours_multi = TDSession.get_market_hours(markets=['EQUITY', 'FOREX'], date='2019-10-19') # TEST - `get_accounts` Endpoint with single values. Should not return an error accounts_data_single = TDSession.get_accounts(account=ACCOUNT_TRADING, fields=['orders']) # TEST - `get_accounts` Endpoint with single values. Should not return an error accounts_data_multi = TDSession.get_accounts(account='all', fields=['orders']) # TEST - `get_transactions` Endpoint with single values. Should not return an error # transaction_data_single = TDSession.get_transactions(transaction_id= TRANSACTION_ID) # TEST - `get_transactions` Endpoint. Should not return an error transaction_data_multi = TDSession.get_transactions(account=ACCOUNT_TRADING, transaction_type='ALL') # TEST - `get_preferences` endpoint. Should not return an error preference_data = TDSession.get_preferences(account=ACCOUNT_TRADING) # TEST - `get_subscription_keys` endpoint. Should not return an error streamer_keys = TDSession.get_streamer_subscription_keys( accounts=[ACCOUNT_TRADING]) # TEST - `get_user_ principals` endpoint. Should not return an error. prinicpals_data = TDSession.get_user_principals( fields=['preferences', 'surrogateIds']) print(get_instrument_data) print(movers_data)
row = cur.fetchone() if row[0] is not None: start_date = (datetime.strptime(row[0], "%Y-%m-%dT%H:%M:%S+0000") + timedelta(days=1)).strftime("%Y-%m-%d") # Create a new session, credentials path is required. TDSession = TDClient(client_id=os.environ.get('CLIENT_ID'), redirect_uri='https://localhost/callback', credentials_path='td_credentials.json') # Login to the session TDSession.login() # get transactions. If first run, start_date is empty. transaction_data_multi = TDSession.get_transactions( account=os.environ.get('ACCOUNT_ID'), transaction_type='TRADE', start_date=start_date) def key_val(element, name): try: return element[name] except KeyError: if name == 'underlyingSymbol': return element['symbol'] return '' # type, subAccount, orderId, netAmount, transactionDate, orderDate, transactionSubType, transactionId, amount, price, # cost, symbol, underlyingSymbol, optionExpirationDate, putCall, cusip, assetType
# 1 13 * * * /Users/shawlu/Documents/anaconda3/envs/analytics/bin/python3 /Users/shawlu/Documents/td-ameritrade-python-api/option_daily_trxn.py import pandas as pd from td.client import TDClient from td.enums import ORDER_SESSION, ORDER_TYPE from util.options import processOptionTrade, orderedKeys from config import ACCOUNT_ID, ACCOUNT_NUMBER, ACCOUNT_PASSWORD, CONSUMER_ID, REDIRECT_URI, SECRET_QUESTIONS # create a new session sess = TDClient(account_number=ACCOUNT_NUMBER, account_password=ACCOUNT_PASSWORD, consumer_id=CONSUMER_ID, redirect_uri=REDIRECT_URI, secret_questions=SECRET_QUESTIONS) sess.login() data = sess.get_transactions(account=ACCOUNT_ID, transaction_type='TRADE') trades = list(filter(lambda entry: entry['type'] == 'TRADE', data)) optionTrades = filter( lambda entry: entry['transactionItem']['instrument']['assetType'] == 'OPTION', trades) df = pd.DataFrame(columns=orderedKeys, data=[processOptionTrade(entry) for entry in optionTrades]) df = df.sort_values(["orderId", "leg"]) # insert today's option trades into database from config import DB_USERNAME, DB_PASSWORD, DB_PORT, DB_HOST from util.DB import DB db = DB(username=DB_USERNAME, password=DB_PASSWORD, host=DB_HOST, port=DB_PORT,