class tdAction(object): def __init__(self): """Constructor""" self.conKey = CONSUMER_KEY self.redirect = REDIRECT_URL self.acct = ACCT_NUM self.tdClient = TDClient(client_id=self.conKey, redirect_uri=self.redirect) self.tdClient.login() def quote(self, tickerList): """Grab quotes""" retDict = {} quotes = self.tdClient.get_quotes(instruments=tickerList) for key in quotes: if type(quotes[key]['lastPrice']) is not None: retDict[key] = quotes[key]['lastPrice'] return retDict def history(self, tickerList): """Create real time data for a given list of tickers""" retDict = {} for item in tickerList: tickerHistory = self.tdClient.get_price_history(symbol=item, period_type='year') priceHistory = [] for data in tickerHistory['candles']: priceHistory.append(data['close']) df = DataFrame({item: priceHistory}) retDict[item] = df return retDict
def history(symbol): quotes = TDClient.get_price_history(TDSession, symbol=symbol, period_type='day', period=1, frequency_type='minute', frequency=1, extended_hours=False) # start_date = 1606086000000, end_date = 1606341600000, return quotes
def history(symbol, period, p_type, freq, f_type): quotes = TDClient.get_price_history(TDSession, symbol=symbol, period=period, period_type=p_type, frequency=freq, frequency_type=f_type, extended_hours=False, start_date=1606086000000) # start_date=1606086000000, end_date = 1606341600000, return quotes
def dt_signal_prices(candle_minutes, symbols): TDSession = TDClient(client_id=config.client_id, redirect_uri='http://localhost/test', credentials_path='td_state.json') TDSession.login() cur_day = datetime.datetime.now(tz=pytz.timezone('US/Eastern')) price_end_date = str(int(round(cur_day.timestamp() * 1000))) price_start_date = str( int( round( datetime.datetime(cur_day.year, cur_day.month, cur_day.day - 1).timestamp() * 1000))) candle_list = [] for symbol in symbols: p_hist = TDSession.get_price_history(symbol, period_type='day', frequency_type='minute', frequency=str(candle_minutes), end_date=price_end_date, start_date=price_start_date) for candle in p_hist['candles']: candle_list.append([ symbol, datetime.datetime.fromtimestamp(candle['datetime'] / 1000), candle['open'], candle['close'], candle['high'], candle['low'] ]) df_dt = pd.DataFrame( candle_list, columns=['Symbol', 'Date', 'Open', 'Close', 'High', 'Low']) # Calculate moving average df_dt['SMA_9'] = df_dt.groupby('Symbol')['Close'].rolling( 9).mean().reset_index(0, drop=True) return df_dt
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_1_minute = TDSession.get_price_history( symbol=hist_symbol, period_type=hist_periodType, period=hist_period, frequency_type=hist_frequencyType, frequency=hist_frequency, extended_hours=hist_needExtendedHoursData) """ CUSTOM RANGE """ # The max look back period for minute data is 31 Days. lookback_period = 31 # Define today. today_00 = datetime.now() # Define 300 days ago. today_ago = datetime.now() - timedelta(days=lookback_period)
def request_data(): # Create a new session td_client = TDClient( client_id='AZ2BZPRDVDNFBHUB5ADYDAPMD2CLG9RG', redirect_uri='https://localhost/first', credentials_path='C:/Users/R/Desktop/code/2nd-tda-api/td_state.json') # Login to a new session td_client.login() print('td client logged in') # ... Backfill data ... ''' This is for filling in data from overnight or whenever the program hasn't been running during market hours ''' for symbol in symbols: print(symbol) ext_hours = True # extended hours period_type = 'month' period = 3 frequency_type = 'daily' frequency = 1 # Make request backfill = td_client.get_price_history(symbol=symbol, period_type=period_type, period=period, frequency_type=frequency_type, frequency=frequency, extended_hours=ext_hours) # returns a dictionary with 3 items: candles (a list), empty, and symbol # found a typo: http://prntscr.com/sw8dtq # Remove symbol prefix if present if symbol[0] == '$' or symbol[0] == '/': symbol = symbol[1:] # in case I get bad data that causes an error # (log something too) print('backfill requested') try: # Save the OHLC data s = backfill['candles'] new_data = pd.DataFrame(s) new_data['datetime'] = pd.to_datetime(new_data['datetime'], unit='ms', origin='unix') new_data.rename(columns={"datetime": "dt"}, inplace=True) # new_data.set_index('dt', inplace=True) new_data = new_data[[ 'dt', 'open', 'high', 'low', 'close', 'volume' ]] f = open( 'C:/Users/R/Desktop/code/2nd-tda-api/data/{}_1d.csv'.format( symbol), 'w+') # append to existing raw data and delete duplicates old_data = pd.DataFrame(f) df = old_data.append(new_data) df.drop_duplicates(inplace=True) df.fillna(method='ffill', inplace=True) df.to_csv( 'C:/Users/R/Desktop/code/2nd-tda-api/data/{}_1d.csv'.format( symbol), index=True) f.close() print('backfill saved!!!!') except Exception as e: print(e) #log someting maybe pass
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
def grab_candle_data(pull_from_td: bool) -> list[dict]: """A function that grabs candle data from TD Ameritrade, cleans up the data, and saves it to a JSON file, so we can use it later. ### Parameters ---------- pull_from_td : bool If `True`, pull fresh candles from the TD Ameritrade API. If `False`, load the data from the JSON file. ### Returns ------- list[dict] A list of candle dictionaries with cleaned dates, and additional values. """ if pull_from_td: # Grab configuration values. config = ConfigParser() config.read('config/config.ini') # Read the Config File. 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') # Create a new session TDSession = TDClient(client_id=CLIENT_ID, redirect_uri=REDIRECT_URI, credentials_path=JSON_PATH, account_number=ACCOUNT_NUMBER) # Login to the session TDSession.login() # Initialize the list to store candles. all_candles = [] # Loop through each Ticker. for ticker in ['AAPL', 'NIO', 'FIT', 'TSLA', 'MSFT', 'AMZN', 'IBM']: # Grab the Quotes. quotes = TDSession.get_price_history(symbol=ticker, period_type='day', period='10', frequency_type='minute', frequency=1, extended_hours=False) # Grab the Candles. candles = quotes['candles'] # Loop through each candle. for candle in candles: # Calculate the Range. candle['range'] = round(candle['high'] - candle['low'], 5) # Add the Symbol. candle['symbol'] = quotes['symbol'] # Convert to ISO String. candle['datetime_iso'] = datetime.fromtimestamp( candle['datetime'] / 1000).isoformat() # Conver to a Timestamp non-milliseconds. candle['datetime_non_milli'] = int(candle['datetime'] / 1000) all_candles.append((candle)) # Save it to a JSON File. with open(file='data/candles.json', mode='w+') as candle_file: json.dump(obj=all_candles, fp=candle_file, indent=4) elif pull_from_td is False and pathlib.Path('data/candles.json').exists(): # Save it to a JSON File. with open(file='data/candles.json', mode='r') as candle_file: all_candles = json.load(fp=candle_file) return all_candles