Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
from datetime import timedelta
from td.client import TDClient

# Create a new session
TDSession = TDClient(
    client_id='<CLIENT_ID>',
    redirect_uri='<REDIRECT_URI>',
    credentials_path='<CREDENTIALS_PATH>'
)


# Login to the session
TDSession.login()

# `get_quotes` endpoint with single value. Should not return an error.
quotes_single = TDSession.get_quotes(instruments=['SQ'])

# `get_quotes` with a Options Contract
quotes_option_contract = TDSession.get_quotes(instruments=['MSFT_041720C75'])

# `get_quotes` with a Futures Contract
quotes_futures = TDSession.get_quotes(instruments=['/ES'])

# `get_quotes` with Forex
quotes_forex = TDSession.get_quotes(instruments=['AUD/USD'])

# `get_quotes` endpoint with multiple values
quotes_multi = TDSession.get_quotes(instruments=['SQ', 'MSFT'])

# `search_instruments` Endpoint
instrument_search_data = TDSession.search_instruments(
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
#   to the same location.
#

# See the String Representation of the TDClient Session Object.
print(TDSession)

# ------------------
#
#   ENDPOINT TESTING - GET QUOTES
#
#   NOTES: The maximum number of quotes you may request at once is 500.
#
# ------------------

# TEST - `get_quotes` endpoint with single value. Should not return an error.
quotes_single = TDSession.get_quotes(instruments=['SQ'])

# TEST - `get_quotes` endpoint with multiple values. Should not return an error.
quotes_multi = TDSession.get_quotes(instruments=['SQ', 'MSFT'])

# PRINT - `get_quotes`
# pprint.pprint(quotes_single)
# pprint.pprint(quotes_multi)

# ------------------
#
#   ENDPOINT TESTING - HISTORICAL PRICES
#
#   NOTES:
#           1. For historical 1-minute bar data, you can get 1 day, 2 day, 3 day, 4 day, 5 day, or 10 day.
#
Ejemplo n.º 5
0
from pprint import pprint
from configparser import ConfigParser
from td.client import TDClient

# Grab configuration values.
config = ConfigParser()
config.read('config/config.ini')

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()

pprint(TDSession.get_quotes(instruments=['MSFT']))
Ejemplo n.º 6
0
# Import the client
from td.client import TDClient
from config import account_number, client_id

# Create a new session, credentials path is optional.
TDSession = TDClient(account_number=account_number,
                     client_id=client_id,
                     redirect_uri='http://localhost/TDtest',
                     credentials_path='credentials.json')

# Login to the session
TDSession.login()

# Grab real-time quotes for 'MSFT' (Microsoft)
msft_quotes = TDSession.get_quotes(instruments=['TSLA'])

# Grab real-time quotes for 'AMZN' (Amazon) and 'SQ' (Square)
multiple_quotes = TDSession.get_quotes(instruments=['AMZN,SQ'])

multiple_quotes['AMZN']

#print(msft_quotes)
print(multiple_quotes['AMZN'])
class AmeritradeRebalanceUtils:

    def __init__(self):
        self.session = None
        self.account = None
        self.account_id = None

    def auth(self, credentials_path='./td_state.json', client_path='./td_client_auth.json'):
        with open(client_path) as f:
            data = json.load(f)
        self.session = TDClient(
            client_id=data['client_id'],
            redirect_uri=data['callback_url'],
            credentials_path=credentials_path
        )
        self.session.login()
        
        # assuming only 1 account under management
        self.account = self.session.get_accounts(fields=['positions'])[0]
        self.account_id = self.account['securitiesAccount']['accountId']
        return self.session
    
    def get_portfolio(self):
        positions = self.account['securitiesAccount']['positions']
        portfolio = {}
        for position in positions:
            portfolio[position['instrument']['symbol']] = position['longQuantity']
        return portfolio

    def place_orders_dry_run(self, portfolio_diff: dict):
        result = portfolio_diff.copy()
        prices = self._get_last_prices(result)
        for ticker, qty in portfolio_diff.items():
            round_qty = round(qty)
            abs_rounded_qty = abs(round_qty)
            result[ticker] = {
            'instruction': ('BUY' if qty > 0 else 'SELL'),
            'qty': abs_rounded_qty,
            'money_movement': round_qty*prices[ticker]*-1
            }
        return result

    def place_orders(self, place_orders_dry_run: dict):
        result = []
        for ticker, order in place_orders_dry_run.items():
            res = self.session.place_order(account=self.account_id, order=self._get_market_order_payload(ticker, order['qty'], order['instruction']))
            result.append(res)
        return result

    def _get_market_order_payload(self, ticker, quantity, instruction='BUY'):
        return {
            "orderType": "MARKET",
            "session": "NORMAL",
            "duration": "DAY",
            "orderStrategyType": "SINGLE",
            "orderLegCollection": [
                {
                    "instruction": instruction,
                    "quantity": quantity,
                    "instrument": {
                    "symbol": ticker,
                    "assetType": "EQUITY"
                    }
                }
            ]
        }

    def _get_last_prices(self, portfolio: dict):
        quotes = self.session.get_quotes(instruments=portfolio.keys())
        portfolio_prices = portfolio.copy()
        for ticker, _ in portfolio_prices.items():
            portfolio_prices[ticker] = quotes[ticker]['lastPrice']
        return portfolio_prices
Ejemplo n.º 8
0
    My advice to you is to keep the your "TDAmeritradeState.json" in the same location and make sure any scripts that use it all point
    to the same location.
'''

# See the String Representation of the TDClient Session Object.
print(TDSession)
'''

  ENDPOINT TESTING - GET QUOTES
  NOTES: The maximum number of quotes you may request at once is 500.

'''

# TEST - `get_quotes` endpoint with single value. Should not return an error.
quotes_single = TDSession.get_quotes(instruments=['/ES'])

# TEST - `get_quotes` endpoint with multiple values. Should not return an error.
quotes_multi = TDSession.get_quotes(instruments=['SQ', 'MSFT'])

# PRINT - `get_quotes`
pprint.pprint(quotes_single)
pprint.pprint(quotes_multi)
'''

  ENDPOINT TESTING - HISTORICAL PRICES
  NOTES: 1. For historical 1-minute bar data, you can get 1 day, 2 day, 3 day, 4 day, 5 day, or 10 day.

'''

#