Giter Site home page Giter Site logo

areed1192 / td-ameritrade-python-api Goto Github PK

View Code? Open in Web Editor NEW
685.0 66.0 257.0 2.04 MB

Unofficial Python API client library for TD Ameritrade. This library allows for easy access of the Standard API and allows users to build data pipelines for the Streaming API.

License: MIT License

Python 99.52% HTML 0.48%
td-ameritrade-client python api-client finance td-ameritrade td-api td-library option-chains authentication-workflow consumer

td-ameritrade-python-api's Introduction

UPDATE

This repo will soon be updated to include the new https://github.com/areed1192/td-ameritrade-api library. The master branch will be overwritten and the old code will need to be updated to reflect the new changes. If you would like to start rewriting your old code, please refer to the new branch merge-new-repo or go the link above.

Unofficial TD Ameritrade Python API Library

Table of Contents

Overview

Current Version: 0.3.5

The unofficial Python API client library for TD Ameritrade allows individuals with TD Ameritrade accounts to manage trades, pull historical and real-time data, manage their accounts, create and modify orders all using the Python programming language.

To learn more about the TD Ameritrade API, please refer to the official documentation.

What's in the API

  • Authentication - access tokens, refresh tokens, request authentication.
  • Accounts & Trading
  • Market Hours
  • Instruments
  • Movers
  • Option Chains
  • Price History
  • Quotes
  • Transaction History
  • User Info & Preferences
  • Watchlist

Requirements

The following requirements must be met to use this API:

  • A TD Ameritrade account, you'll need your account password and account number to use the API.
  • A TD Ameritrade Developer Account
  • A TD Ameritrade Developer API Key
  • A Consumer ID
  • A Redirect URI, sometimes called Redirect URL
  • Python 3.7 or later.

API Key and Credentials

Each TD Ameritrade API request requires a TD Ameritrade Developer API Key, a consumer ID, an account password, an account number, and a redirect URI. API Keys, consumer IDs, and redirect URIs are generated from the TD Ameritrade developer portal. To set up and create your TD Ameritrade developer account, please refer to the official documentation.

Additionally, to authenticate yourself using this library, you will need to provide your account number and password for your main TD Ameritrade account.

Important: Your account number, an account password, consumer ID, and API key should be kept secret.

Installation

The project can be found at PyPI, if you'd like to view the project please use this link.

pip install td-ameritrade-python-api

To upgrade the library run the following command:

pip install --upgrade td-ameritrade-python-api

Usage

This example demonstrates how to login to the API and demonstrates sending a request using the get_quotes endpoint, using your API key.

Credentials: Please note, that the credentials_path is a file path that will house the credentials like your refresh token and access token. You must specify the credentials_path argument yourself so that you are aware of where the tokens will be stored. For example, if you specify the credentials_path as C:\Users\Public\Credentials\td_state.json it would store your tokens in a JSON file located in a folder called Credentials located under the Users profile.

# Import the client
from td.client import TDClient

# Create a new session, credentials path is required.
TDSession = TDClient(
    client_id='<CLIENT_ID>',
    redirect_uri='<REDIRECT_URI>',
    credentials_path='<PATH_TO_CREDENTIALS_FILE>'
)

# Login to the session
TDSession.login()

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

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

Features

Authentication Workflow Support

Automatically will handle the authentication workflow for new users, returning users, and users with expired tokens (refresh token or access token).

Request Validation

For certain requests, in a limited fashion, it will help validate your request when possible. For example, when using the get_movers endpoint, it will automatically validate that the market you're requesting data from is one of the valid options.

Customized Objects for Watchlists, Orders, and Option Chains

Requests for saved orders, regular orders, watchlists, and option chains can be a challenging process that has multiple opportunities to make mistakes. This library has built-in objects that will allow you to quickly build your request and then validate certain portions of your request when possible.

Library Requirements

The following requirements must be met before being able to use the TD Ameritrade Python API library.

  • You must have a TD Ameritrade Account.
  • You must have a TD Ameritrade Developer Account. Please go to following folder for instructions on how to create a Developer account.

Documentation and Resources

Official API Documentation

Unofficial Documentation

Support these Projects

Patreon: Help support this project and future projects by donating to my Patreon Page. I'm always looking to add more content for individuals like yourself, unfortuantely some of the APIs I would require me to pay monthly fees.

YouTube: If you'd like to watch more of my content, feel free to visit my YouTube channel Sigma Coding.

Hire Me: If you have a project, you think I can help you with feel free to reach out at [email protected] or fill out the contract request form

Authentication Workflow

Step 1 - Start the Script:

While in Visual Studio Code, right click anywhere in the code editor while in the file that contains your code. The following dropdown will appear:

Terminal Dropdown

From the dropdown, click Run Python file in Terminal, this will start the python script.

Step 2 - Go to Redirect URL:

The TD Library will automatically generate the redirect URL that will navigate you to the TD website for for you authentication. You can either copy the link and paste it into a browser manually or if you're using Visual Studio Code you can press CTRL + Click to have Visual Studio Code navigate you to the URL immeditately.

Redirect URI

Step 3 - Login to the TD API:

Once you've arrived at the login screen, you'll need to provide your credentials to authenticate the session. Please provide your Account Username and Account Password in the userform and then press enter. As a reminder these, are the same username/password combination you use to login to your regular TD Account.

"TD Login

Step 4 - Accept the Terms:

Accept the Terms of the API by clicking Allow, this will redirect you.

TD Terms

Step 5 - Copy the Authorization Code:

After accepting the terms, you'll be taken to the URL that you provided as your redirect URI. However, at the end of that URL will be authorization code. To complete the authentication workflow, copy the URL as it appears below. Don't worry if the numbers don't match, as you will have a different code.

Auth Code

Step 6 - Paste the Authorization Code in the Terminal:

Take the URL and copy it into the Terminal, after you have pasted it, press Enter. The authentication workflow will complete and the script will start running. At this stage, we are exchanging your authorization code for an access token. That access token is valid only for 30 minutes. However, a refresh token is also stored that will refresh your access token when it expires.

Paste URL

After, that the script should run. Additionally, if you go to the location you specified in the credentials_path arugment you will now see td_state.json file. This file contains all the info used during a session. Please DO NOT DELETE THIS FILE OR ELSE YOU WILL NEED TO GO THROUGH THE STEPS ABOVE.

td-ameritrade-python-api's People

Contributors

areed1192 avatar dependabot[bot] avatar dvd9604 avatar eklipzgit avatar jacabreragt avatar robertsmd avatar saber-be avatar sampajano avatar themantalope avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

td-ameritrade-python-api's Issues

Streaming Account Activity issue(SUBS before LOGIN done?)

First of all, I would like to thank you for publishing your TD Ameritrade Python API!

When I try connect to Account Activity Stream with this code:

TDStreamingClient = TDSession.create_streaming_session()
TDStreamingClient.account_activity()
TDStreamingClient.stream(print_to_console=True)

sometimes it ends up with an error:

Connection established. Streaming will begin shortly.
====================
Message Recieved:

{'response': [{'service': 'ACCT_ACTIVITY', 'requestid': '1', 'command': 'SUBS', 'timestamp': 1590498667548, 'content': {'code': 20, 'msg': 'STREAM CONNECTION NOT FOUND - Please login again.'}}]}
--------------------

====================
Message Recieved:

{'response': [{'service': 'ADMIN', 'requestid': '0', 'command': 'LOGIN', 'timestamp': 1590498667548, 'content': {'code': 0, 'msg': '05-1'}}]}

or:

Connection established. Streaming will begin shortly.
====================
Message Recieved:

{'response': [{'service': 'ACCT_ACTIVITY', 'requestid': '1', 'command': 'SUBS', 'timestamp': 1590498947102, 'content': {'code': 3, 'msg': 'Login Denied. - Please login first.'}}]}
--------------------

====================
Message Recieved:

{'response': [{'service': 'ADMIN', 'requestid': '0', 'command': 'LOGIN', 'timestamp': 1590498947102, 'content': {'code': 0, 'msg': '06-3'}}]}
--------------------

Connection with server closed, beginning close process...

I guess first it should wait for ADMIN LOGIN response, then send ACCT_ACTIVITY SUBS?

I can't place order.

Hi, there.
I am very interested in your scripts.
I have run test scripts.
So all scripts works well
But the test_submit_order.py doesn't work right.
""""""""""""""""""
C:\Users\Administrator\AppData\Local\Programs\Python\Python37\python.exe F:/td-ameritrade-python-api-master/tests/test_submit_order.py
{'session': 'NORMAL', 'duration': 'GOOD_TILL_CANCEL', 'orderType': 'LIMIT', 'orderStrategyType': 'SINGLE', 'price': 12.0, 'orderLegCollection': [{'instruction': 'BUY_TO_OPEN', 'quantity': 1, 'instrument': {'assetType': 'OPTION', 'symbol': 'MSFT_031320C155'}}]}
{"orderType": "MARKET", "session": "NORMAL", "duration": "DAY", "orderStrategyType": "SINGLE", "orderLegCollection": [{"instruction": "BUY", "instrument": {"assetType": "EQUITY", "symbol": "GIS"}, "quantityType": "SHARES", "quantity": 1}]}
{'error': 'You do not have enough available cash/buying power for this order.'}

I have get the error "'error': 'You do not have enough available cash/buying power for this order.'"
Would you please fix this error for me?
I will wait for your quick and favorable reply.
Thanks.

Break out message parsing request

Hey @areed1192 ,

First, thanks for all the hard work figuring out all these undocumented endpoints and the whole api!!

I'm wondering though if we could break the csv saving, message parsing & building, and message flattening out of the stream and client classes?

Reasons for this would include:

  1. Easier for others to contribute to smaller pieces, with less merge conflicts
  2. Adds the possibility to create a moc stream and client to facilitate message parsing unit tests and to aid in their development, utilizing saved message streams to test with
  3. Easier for users to learn and look over the client and stream code if they want to sub class them, learn their use, or even just for their own peace of mind (especially as this grows, I imagine more people will want to do that with a financial api wrapper)

Take or leave it, but curious to hear any thoughts!

If it's needed, I've included some sudo py to hopefully add some clarity: Example_BreakOut.txt

write_behavior not working

Hiya, thanks again for publishing this awesome library!

I have been using test_streaming_client.py as a template to stream options locally; however, I believe the csv writer doesn't execute. I have added extra logging to try to debug the situation but the logs do not mention any attempts to write to csv.

I'm not sure if this is an issue with the existing code or my edits.

Here's the code:

from td.client import TDClient
import logging

logging.basicConfig(level=logging.DEBUG)

# Create a new session
TDSession = TDClient(account_number=MY_USERNAME
                     account_password=MY_PASS
                     consumer_id=MY_ID,
                     redirect_uri='http://localhost,
                     json_path=None)

# Login to the session
TDSession.login()

# Create a streaming sesion
TDStreamingClient = TDSession.create_streaming_session()

# Set the data dump location
TDStreamingClient.write_behavior(file_path = "raw_data.csv", append_mode = True)

# Quality of Service
TDStreamingClient.quality_of_service(qos_level='express')

# Level One Option
TDStreamingClient.level_one_options(symbols=['SPY_051520P260'],fields=list(range(0, 42)))

# Stream it.
TDStreamingClient.stream()

modify_order function missing JSON conversion, same as Issue #38

HI!,
Hope you and everyone in your family is well. As @anontrader pointed out in issue #38, the following code is also missing within the order modification function. Placing the code below in line 1796 of the client.py allowed me to modify existing orders.

        if isinstance(order, Order):
            order = order._saved_order_to_json()
            order = json.loads(order)                                    
        else:
            order = order

Thanks for all your help!

Bug in place_order

The existing client.place_order function has a bug that makes it return a 400 bad request error. The issue is that the JSON payload for this order is being sent in the 'json' variable in self._make_request(). It looks like the function will only work if instead you send the data in the 'data' field.

I fixed this temporarily in my code by creating a client class that extends TDClient and overrides the place_order function to do this correctly. My class looks like this:

class CustomTDClient(TDClient):
    def place_order(self, account: str, order: dict) -> dict:
        print("In CustomTDClient place_order")
        # check to see if it's an order object.
        if isinstance(order, Order):
            order = order._saved_order_to_json()
        else:
            order = order

        # make the request
        endpoint = 'accounts/{}/orders'.format(account)
        return self._make_request(method='post', endpoint=endpoint, mode='json', data=order, order_details=True)

You probably want to fix this in the repo code.

Get_option_chain

get_options_chain method in TDClient class expects a dictionary, so the OptionChain object recommended to be used in the code isn't accepted unless you explicitly reference the query_parameters dictionary object.

Recommend EITHER updating the code comments to reflect this OR having the get_options_chain method test for an OptionChain object and proceed accordingly.

def get_options_chain(self, option_chain: Dict) -> Dict:

ModuleNotFoundError: No module named 'config.credentials'

Hi, i'm upgrading from 0.2.3 to 0.2.6 and ran into the following error when running test_regular_client.py

ModuleNotFoundError: No module named 'config.credentials'

Do i need any other pip install?

test_regular_client.py ran fine in 0.2.3.

Thanks.

What is the value of self.library_directory in the defaults.py?

In the StatePath class, we have that

def __init__(self, credentials_file: str = None):

        """Initalizes the StatePath Class"""        
        self.python_version = sys.version_info
        self.credenitals_file_name = 'td_state.json'
        self.settings_location = {}

        if credentials_file and isinstance(credentials_file, str):
            self.credentials_file: pathlib.Path = pathlib.Path(credentials_file)
        else:
            self.credentials_file: pathlib.Path = self.library_directory

32c9b61#diff-e03670d854f5b6539e3fe0b8e7c84c82R31

What is the value of self.library_directory? Is it inherited from the parent path class?

place_order() validation error

I'll start by echoing others and saying thank you for this great work.

I'm trying to submit an order but keep getting {'error': 'A validation error occurred while processing the request.'}

I know the TDClient credentials are correct because I can connect to my account with TDSession.get_accounts() without issue. Can you help point to which part of this Order or OrderLeg is incorrect?

Here is the code:

from td.orders import Order, OrderLeg
from td.client import TDClient
import config  # personal info
from td.enums import ORDER_TYPE, ORDER_SESSION, DURATION, ORDER_STRATEGY_TYPE, ORDER_INSTRUCTIONS, ORDER_ASSET_TYPE, QUANTITY_TYPE

### Initalize a new Order Object.
new_order = Order()
new_order.order_type(order_type = ORDER_TYPE.MARKET)
new_order.order_session(session = ORDER_SESSION.NORMAL)
new_order.order_duration(duration = DURATION.DAY)
new_order.order_strategy_type(order_strategy_type = ORDER_STRATEGY_TYPE.SINGLE)

### Define a new OrderLeg Object.
new_order_leg = OrderLeg()
new_order_leg.order_leg_instruction(instruction = ORDER_INSTRUCTIONS.BUY)
new_order_leg.order_leg_asset(asset_type = ORDER_ASSET_TYPE.EQUITY, symbol = 'GIS')
new_order_leg.order_leg_quantity_type(quantity_type = QUANTITY_TYPE.SHARES)
new_order_leg.order_leg_quantity(quantity=1)

new_order.add_order_leg(order_leg = new_order_leg)

### create a new session
TDSession = TDClient(account_number = config.account_number,
                     account_password = config.account_password,
                     consumer_id = config.consumer_id,
                     redirect_uri = config.redirect_uri)

### Testing connection - works
principals_data = TDSession.get_accounts()
print(principals_data)

### Fails with {'error': 'A validation error occurred while processing the request.'}
print(TDSession.place_order(account = config.account_number, order = new_order))

Missing Streaming Quotes

I did a subscription from TD for dow 30 stocks. I noticed only a small portion of streaming data is provided. I got the data stream every second, But most field is NaN and the volume is not continuos as well. Is that normal for everyone?

pip install not working

This client library looks like exactly what I need! However pip install td-ameritrade-python-api doesn't work for me.

ERROR: Could not find a version that satisfies the requirement td-ameritrade-python-api (from versions: none)
ERROR: No matching distribution found for td-ameritrade-python-api

It seems to be unavailable on PyPI.

Error retrieving options chain

I am trying to retrieve option chain for an optionable sotck, for example, DD.
TDSessions has get_options_chains method, but I am probably no using it correctly. Could you please provide an example around retrieving option chains?

TDSession.get_options_chain({'symbol': 'DD', 'strikeCount': 5, 'toDate': '2020-02-15'})

Returns

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-13-d85b4ef1ae8a> in <module>
      1 TDSession.get_options_chain({'symbol': 'DD',
      2                              'strikeCount': 5,
----> 3                              'toDate': '2020-02-15'})

~/Documents/SGXCode/DWPA/td/client.py in get_options_chain(self, option_chain)
    930 
    931         # this request requires an API key, so let's add that.
--> 932         option_chain.add_chain_key(
    933             key_name="apikey", key_value=self.config["consumer_id"]
    934         )

AttributeError: 'dict' object has no attribute 'add_chain_key'

I can retrieve stock quotes w/o problems, so the authentications for my account is working fine.

IsADirectoryError with or without credentials_path supplied

Traceback (most recent call last):
  File "Ameritrade.py", line 96, in <module>
    account_number=args.acct_number)
  File "/home/pi/.local/lib/python3.7/site-packages/td/client.py", line 119, in __init__
    self._state_manager('init')
  File "/home/pi/.local/lib/python3.7/site-packages/td/client.py", line 207, in _state_manager
    with open(file=credentials_file_path, mode='r') as json_file:
IsADirectoryError: [Errno 21] Is a directory: '/home/pi/.local/lib/python3.7/site-packages/td'

I only just started to debug it, but not matter if I pass a credential file path or not to the Client instance I receive this error.
I can see in defaults.py the StatePath class initiates by taking an optional path but the filename itelsef is hardcoded, but I could not follow where it ever gets concatted to the path when being opened for reading on line 207 of client.py

I am running on 4hours of sleep so I could jsut be missing a step somewhere. I do have valid access and refresh tokens when tried on the td dev api site.

my code is simple at this point - I'm just starting to play with this module (library.)

if __name__ == '__main__':
    try:
        # start
        start_time = datetime.now()
        
        args = get_arguments()
 
        TDSession = TDClient(
          client_id=args.consumer_id,
          redirect_uri=args.redirect_url,
          account_number=args.acct_number)

        TDSession.login()


# end
        finish_time = datetime.now()
        logger.debug(finish_time)
        logger.debug(
          'Execution time: {time}'.format(
            time=(finish_time - start_time)))
        logger.debug("#"*20 + " END EXECUTION " + "#"*20)

        # bye
        sys.exit(0)

my args are read using the configargparse module and is being used the same way in other working projects. I have verified the config values are correctly being read in.
I have tried it while also not supplying the account_number as in my code above for the sake of rounding it out.

td/client.py -> update_watchlist bug

Tried to run a method (update_watchlist) that passes a Patch request, found a bug with the way the request is generated. In line 484 I updated โ€œdata=dataโ€ to โ€œjson=dataโ€. This update resolved the issue for me.

Shoutout to you @areed1192 for taking the time to provide a great library!

I would like to get open,high,low and close price in real-time.

I am very interested in this Github projects.
I am going to get AAPL open, high, low and close price in real-time.
So I am using level_one_quotes function for it.

TDStreamingClient.level_one_quotes(symbols=['AAPL'], fields=[0, 1, 2, 3, 4, 12, 13, 15, 28])
By the way, I can't get the prices now.
image
I can get 1,2,3,4(ask,bid price) value correctly but I can't get 12,13,15,28(open,high,low and close price).
The prices doesn't come.
Can you help me?

Some suggestions for restructuring

Hi @areed1192 this is a really nice repo! Have a couple suggestions for you

  1. I would recommend keeping all user-specific data (so any config information and the State.json file) in a directory for the user. Pretty simple way to set that up in the setup.py file would be to do something like:
import os
home_dir = os.path.expanduser('~')
td_dir = os.path.join(home_dir, '.tdunofficial')
if not os.path.isdir(td_dir): os.makedirs(td_dir)

Then you should save anything the user needs or wants to use in here. Removes the problem of saving user-specific information in the repo.

  1. Use a config file. I would set up a config file (the .ini file with the python configparser tends to be used for many python projects, and is shipped with python). You can set up a default config file, which the TDClient object loads during __init__, ships with the package and gets installed to the td_dir as discussed above. The user can then edit the config file as they please. Would also recommend that a path to a config file get supplied to the __init__ method, with the default one as discussed above.

Anyways, take them or leave them. I submitted a PR for another thing I wanted to add to. Let me know if you need a hand implementing these.

-themantalope

Can data of level2 total view be saved?

Hi

I tried to run TDStreamingClient.level_two_total_view
But somehow data were not be saved to the csv file. I used the following scripts,
TDStreamingClient.write_behavior(
write='csv',
file_path=r"./raw_data_20200709_apple.csv",
append_mode=True
)
TDStreamingClient.level_two_total_view(symbols = ['AAPL'], fields = [0,1,2])
TDStreamingClient.stream(print_to_console=False)
await TDStreamingClient.build_pipeline()

And is it possible to save the output of level_two_total_view to a python variable instead writing it to a csv file?

{'error': 'A validation error occurred while processing the request.'}

I tried submitting a new place_order but I always get code 400 error. Do you know what minimum information I need to pass for a LIMIT order?

new_order = Order()
new_order.order_session(session=ORDER_SESSION.NORMAL)
new_order.order_duration(duration=DURATION.DAY)
new_order.order_type(order_type=ORDER_TYPE.LIMIT)
new_order.order_strategy_type(order_strategy_type=ORDER_STRATEGY_TYPE.SINGLE)
new_order.complex_order_type(complex_order_strategy_type=COMPLEX_ORDER_STRATEGY_TYPE.NONE)
new_order.order_price(price=200.00)

new_order_leg = OrderLeg()
new_order_leg.order_leg_instruction(instruction=ORDER_INSTRUCTIONS.BUY)
new_order_leg.order_leg_quantity(quantity=1)
new_order_leg.order_leg_asset(asset_type=ORDER_ASSET_TYPE.EQUITY, symbol="AAPL")
new_order.add_order_leg(order_leg=new_order_leg)

order_result = TDSession.place_order(account = ACCOUNT_NUMBER, order = new_order)`

__init__() got an unexpected keyword argument 'consumer_id'

I received the below error when trying to use the usage example code

``# Import the client
from td.client import TDClient

Create a new session, credentials path is optional.

TDSession = TDClient(
account_number='ACCOUNT_NUMBER',
consumer_id='CONSUMER_ID',
redirect_uri='REDIRECT_URI'
)

Login to the session

TDSession.login()

Grab real-time quotes for 'MSFT' (Microsoft)

msft_quotes = TDSession.get_quotes(instruments='MSFT')``


TypeError Traceback (most recent call last)
in
9 # )
10
---> 11 TDSession = TDClient(
12 account_number='ACCOUNT_NUMBER',
13 consumer_id='CONSUMER_ID',

TypeError: init() got an unexpected keyword argument 'consumer_id'

Streaming Data saving and reading issue

I am trying to create a streaming session with three tickers. I do see the message in terminal. But nothing saved in the csv file. Also How could I read the streaming message and process the data? Thanks!

`# Login to the session
TDSession.login()

Create a streaming sesion

TDStreamingClient = TDSession.create_streaming_session()
print(TDStreamingClient.websocket_url)

TDStreamingClient.write_behavior(write='csv',file_path = 'E:\TD\samples\raw.csv', append_mode = True)

TDStreamingClient.level_one_quotes(symbols=['APA','BKR','COG','COP'], fields=list(range(0,8)))

Stream it.

TDStreamingClient.stream()
TDStreamingClient.approved_writes()
`

Gethistory Problem

I ran the get_price_history yesterday using 10 days parameters and downloaded 10 days ending 4/13/2020. Today I rerun the same code. I assume that I could get 10 days ending 4/14/2020.
But I still get the same data as yesterday. I restarted Pycharm and still the same. I have to specify startdate and enddate as shown in the second part of the code.

`TDSession.login()
histdata=TDSession.get_price_history(symbol='C',periodType='day',period=10,frequencyType='minute',frequency=1,needExtendedHoursData='false')

endtimestamp = int (datetime.datetime(2020, 4, 14, 23, 59).timestamp())*1000
starttimestamp = int (datetime.datetime(2020, 4, 4, 23, 59).timestamp())*1000
histdata=TDSession.get_price_history(symbol='C', periodType='day', startDate=starttimestamp, endDate=endtimestamp,frequencyType='minute',frequency=1,needExtendedHoursData='false')
`

Correct symbol names for $DJI, /CL and SPY.IV (indices, commodities and ETF intraday values)?

In the standard Ameritrade thinkorswim software, one can get quotes for indices, for example $DJI, commodity prices, for example oil, symbol /CL, as well as intraday values of ETFs, for example SPY.IV is the name for the intraday value of the SPY ETF. But such symbols do not seem to work in the API. If I specify strings $DJI, /CL or SPY.IV I get an error, whereas a simple stock symbol like MSFT works fine.

So: Does anyone know what is the correct symbol name, in the API, for fetching these types of quotes?

Handle more errors using exceptions

Add more exceptions to handle the common error code.
Fir example, I saw this error a lot when trying out the queries:

RESPONSE STATUS CODE: 429
RESPONSE URL: https://api.tdameritrade.com/v1/marketdata/chains?symbol=VOOG
RESPONSE HEADERS: {'Date': 'Thu, 09 Jul 2020 21:09:31 GMT', 'Content-Type': 'application/json', 'Content-Length': '157', 'Connection': 'keep-alive', 'Cache-Control': 'no-cache,no-store,must-revalidate', 'Access-Control-Allow-Origin': '', 'Access-Control-Allow-Headers': 'origin, x-requested-with, accept, authorization, content-type', 'Access-Control-Max-Age': '3628800', 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS, HEAD, PATCH', 'X-Xss-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Security-Policy': "frame-ancestors 'self'", 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains, max-age=31536000'}
RESPONSE PARAMS: {}
RESPONSE TEXT: 
          {
        "error":"Individual App's transactions per seconds restriction reached. Please contact us with further questions"
      	   }

Hard wired td_state.json credential file

File: defaults.py
Line: 22
Issue:
Even as user passed in a valid credential file name with full path, the code is still looking for '/library_path/td_state.json' file for credential.

e.g.
Call

TDSession = TDClient(
    client_id=CONSUMER_KEY,
    redirect_uri=REDIRECT_URL,
    credentials_path='/home/user/td_dev/credential.json'
)

Error:

Exception has occurred: FileNotFoundError
[Errno 2] No such file or directory: '/path/to/the/github/folder/td/td_state.json'
  File "/path/to/the/github/folder/td/client.py", line 212, in _state_manager
    with open(file=credentials_file_path, mode='r') as json_file:
  File "/path/to/the/github/folder/td/client.py", line 119, in __init__
    self._state_manager('init')
  File "/home/user/td_dev/test.py", line 32, in <module>
    credentials_path=CREDENTIALS_PATH

The calling and usage of pathlib.Path(credentials_file) cannot handle user defined credential file correctly.

Which order do I must place for my condition?

I am a beginner in TD Ameritrade python API and am learning many things from this Github.
By the way, I have some problems.
So for example,
When the price > 60 USD, open Buy Order and when the price > 80USD stop or close this order.
Which order function do I must use for this order?
Would you please teach me the order function in detail?
Thank you very much!

Error when trying to use create_saved_order

I am trying to use create_saved_order to debug my app since can't paper trade. When I use below

limit_order = {
    "orderType": "LIMIT",
    "session": "NORMAL",
    "duration": "DAY",
    "price": 20.00,
    "orderStrategyType": "SINGLE",
    "orderLegCollection": [
      {
        "instruction": "SELL",
        "quantity": 1,
        "instrument": {
          "symbol": "AA",
          "assetType": "EQUITY"
        }
      }
    ]
}
new_order_response = td_client.create_saved_order(account=TD_ACCOUNT, saved_order=limit_order)

receive: UnboundLocalError: local variable 'order' referenced before assignment

but if I use
new_order_response = td_client.place_order(account=TD_ACCOUNT, order=limit_order)
everything works as expected.

How to get real-time open prices?

Screenshot_1
I would like to get this plot in real-time.
Can you help me?
How to get this open prices via TD Ameritrade python API?
Best regards!

How to run through proxy?

Test the sample script at home is good. But when using the internet in company office, the script not connect. Gives error 'TimeoutError: [Errno 110] Connect call failed ('198.200.171.147', 443)'

So this maybe a proxy issue. I set the system proxy env to http_proxy = http://proxy.XXXX:port
but still not working. Any thoughts?

BTW, I can run ThinkOrSwim desktop app after setting proxy, but not the python script.

Default _token_validation nseconds = 5 is not enough

There might be situations like:

  1. User's system time is not in perfect sync with TD Ameritrade system time.

  2. User's network has unpredictable delay

When requesting, the unfreshed access token is not throwing out EXCEPTION. It is just printing the following message:

================================================================================
RESPONSE STATUS CODE: 401
RESPONSE URL: https://api.tdameritrade.com/v1/marketdata/chains?symbol=MSFT
RESPONSE HEADERS: {'Date': 'Sat, 04 Jul 2020 15:18:02 GMT', 'Content-Type': 'application/json', 'Content-Length': '108', 'Connection': 'keep-alive', 'WWW-Authenticate': 'Bearer realm="null",error="invalid_token",error_description="keymanagement.service.access_token_expired: Access Token expired"', 'Cache-Control': 'no-cache,no-store,must-revalidate', 'Access-Control-Allow-Origin': '', 'Access-Control-Allow-Headers': 'origin, x-requested-with, accept, authorization, content-type', 'Access-Control-Max-Age': '3628800', 'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS, HEAD, PATCH', 'X-Xss-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Security-Policy': "frame-ancestors 'self'", 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains, max-age=31536000'}
RESPONSE PARAMS: {}
RESPONSE TEXT: 
          {
        "error":"The access token being passed has expired or is invalid."
      		}
          
--------------------------------------------------------------------------------

Without throwing out refresh token expiration EXCEPTION, user cannot try and catch it and the code will fail in downstream data extraction steps.

Suggestion:

  1. increase the nseconds default in the _token_validation method to something like 60.
  2. Throw EXCEPTION for response code 401 so the user can catch it and refresh the token himself/herself and post the request again. This would dramatically improve code robusticity.
  3. Change the comparison criteria in _token_seconds method to also allow 60 seconds safe margin.

I created Pull request #57 to resolve this issue.

How to dynamically add streams?

Hi @areed1192, first and foremost, thank you very much for writing this code, and making it available. I started it using a couple days ago, and it works very well for me.

I have a question for you: how would you go about dynamically changing the streams that we are subscribed to? I am looking at subscribing to ATM calls for a given stock, so as the stock price changes, I want to unsubscribe from the no-longer-ATM call, and subscribe to the new ATM call.

I presume I would need to close the stream, and open it again with the new stream; but because the stream call is blocking, then my program logic halts. I would need to be able to "fork" the streaming start so that is not blocking.

Curious to hear your thoughts... :)

Cannot install with pip

ERROR: Could not find a version that satisfies the requirement td-ameritrade-python-api (from versions: none)
ERROR: No matching distribution found for td-ameritrade-python-api

not quite sure if it's only me, I can install other packages like tensorflow normally though

Login process: how do I get consumer_id and redirect_uri ?

I don't understand the login process. I used the example script from README.md, and filled in
account_number and account_password for my ameritrade account, but I apparently I do not understand where consumer_id and redirect_uri are supposed to come from.

First, if I run the script with just the dummy values for consumer_id and redirect_uri, the script produces a a redirect_url that includes said dummy values and the browser (after pasting that URL) just says

A third-party application may be attempting to make unauthorized access to your account. For help with your account, contact us. For information on securing your account, visit the TD Ameritrade Security page. (*)

Second, if I try instead to generate an Oauth recipe at
https://developer.tdameritrade.com/account-access/apis/get/accounts/%7BaccountId%7D-0
then I get a login window pop-up, and can login and run commands on the webpage. But again I do not understand how I should set the consumer_id and redirect_uri variables from the OAuth "curl" values. I made some GUESS about this but when I plug the values into the script all I get when running is the same error message above (*).

I realize this must be a dumb question but I simply do not understand the logic of the recipe. Can you please help? I need to understand both consumer_id and redirect_uri, please.

Account number and password

Hi, just wondering what are account number and password used for? Didn't see anywhere in the code that needs it? So can I not put those in?

Validation Error, Similar to Issue #11

Hello everyone,
Hope everyone and your loved ones are healthy. I am having a similar problem targeted in issue #11 the validation error 400. I have read all closed related issues and also copied the code in the referenced issue and I get the same results I am experiencing with the code below. I am unsure this is related to the fact that I was trying this code after the market has closed, but I am able to place this trade via the gui without an issue.

Grateful for your help
Code below:

from td.client import TDClient
from td.orders import Order, OrderLeg
from td.enums import ORDER_SESSION, DURATION, ORDER_INSTRUCTIONS, ORDER_ASSET_TYPE, ORDER_TYPE, ORDER_STRATEGY_TYPE, QUANTITY_TYPE

TDSession = TDClient(
    client_id=config.api_key,
    redirect_uri=config.redirect_uri,
    credentials_path= config.token_path
)

# Login to the session
# TDSession.login()

new_order = Order()
new_order.order_type(order_type=ORDER_TYPE.MARKET)
new_order.order_session(session=ORDER_SESSION.NORMAL)
new_order.order_duration(duration=DURATION.GOOD_TILL_CANCEL)
# new_order.order_price(price=62.79)
new_order.order_strategy_type(order_strategy_type=ORDER_STRATEGY_TYPE.SINGLE)

new_order_leg = OrderLeg()
new_order_leg.order_leg_instruction(instruction=ORDER_INSTRUCTIONS.BUY)
new_order_leg.order_leg_asset(asset_type=ORDER_ASSET_TYPE.EQUITY, symbol="CHGG")
new_order_leg.order_leg_quantity_type(quantity_type=QUANTITY_TYPE.SHARES)
new_order_leg.order_leg_quantity(quantity=1)

new_order.add_order_leg(order_leg=new_order_leg)

TDSession.place_order(account=config.account_id,order=new_order)

Streaming issues: CHART_EQUITY not working

while using:
TDStreamingClient.chart(service='CHART_EQUITY', symbols=["AAPL"],fields=[0,1,2,3,4,5,6,7])

receives an error:
new_key = self.fields_keys_write[service_name][old_key]
KeyError: 'seq'

calling cancel_order got a huge error

So I run:
cancel_result = TDSession.cancel_order(account=ACCOUNT_NUMBER,
order_id=positionRegister[key]['orderId'])

So the cancel order went through but then a huge error happens:

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Godwin\AppData\Local\Programs\Python\Python38-32\lib\tkinter_init_.py", line 1883, in call
return self.func(*args)
File "C:\Users\Godwin\AppData\Local\Programs\Python\Python38-32\lib\tkinter_init_.py", line 804, in callit
func(*args)
File "C:/Users/Godwin/PycharmProjects/Autobot/autobot_v0_1_8.py", line 870, in updateLoop
cancel_result = TDSession.cancel_order(account=ACCOUNT_NUMBER,
File "C:\Users\Godwin\PycharmProjects\Autobot\venv\lib\site-packages\td_mod\client.py", line 1902, in cancel_order
return requests.delete(url=url, headers=merged_headers, verify=True).json()
File "C:\Users\Godwin\PycharmProjects\Autobot\venv\lib\site-packages\requests\models.py", line 897, in json
return complexjson.loads(self.text, **kwargs)
File "C:\Users\Godwin\AppData\Local\Programs\Python\Python38-32\lib\json_init_.py", line 357, in loads
return _default_decoder.decode(s)
File "C:\Users\Godwin\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\Godwin\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Could not find a version that satisfies the requirement

When trying to install using pip I get the following message:
Could not find a version that satisfies the requirement td-ameritrade-python-api==0.2.8 (from versions: )
No matching distribution found for td-ameritrade-python-api==0.2.8

Not sure if this is because I am on a mac or not.

async error

I tried to run the test file and got this error. I'm using phyton 3.8.

causes this error

C:\Users\Godwin\PycharmProjects\Autobot\venv\Scripts\python.exe C:/Users/Godwin/PycharmProjects/Autobot/test_td.client.py
Traceback (most recent call last):
File "C:/Users/Godwin/PycharmProjects/Autobot/test_td.client.py", line 3, in
from td.client import TDClient
File "C:\Users\Godwin\PycharmProjects\Autobot\venv\lib\site-packages\td\client.py", line 8, in
from td.stream import TDStreamerClient
File "C:\Users\Godwin\PycharmProjects\Autobot\venv\lib\site-packages\td\stream.py", line 148
await asyncio.sleep(1)
^
SyntaxError: 'await' outside async function

Process finished with exit code 1

Cant seem to place an options order

First of all thank you for picking up where the Ameritrade API leaves off and making this awesome repo.
Second off I'm trying to place an order and it just won't take. Can you look at my order process and let me know if I'm missing anything? I'm using MATLAB to call python so some of the commands look a little funny, but I've done it before and I don't think it's the problem. Ty

Csymbol = 'MSFT_031320C155';
new_order = py.td.orders.Order();
new_order.order_session(pyargs('session', 'NORMAL'));
new_order.order_duration(pyargs('duration','GOOD_TILL_CANCEL'));
new_order.order_type(pyargs('order_type', 'MARKET'));
new_order_leg = py.td.orders.OrderLeg();
new_order_leg.order_leg_instruction(pyargs('instruction','BUY_TO_OPEN'));
quant = py.int(1);
new_order_leg.order_leg_quantity(pyargs('quantity',quant));
new_order_leg.order_leg_asset(pyargs('asset_type','OPTION','symbol',Csymbol));
new_order.add_order_leg(pyargs('order_leg',new_order_leg));
TDSession.place_order(pyargs('account',myaccountid, 'order', new_order));

Account balances change after hours?

I have observed that some of the account variables, for example "marginBalance" and "shortBalance" are not constant after market closing time, but rather are affected by after hours securities prices.
It also seems that Ameritrade does some final update of balances later in the evening, maybe around midnight EST, and I'm not even sure that these updates are consistent with the closing prices.

That seems a bit illogical to me. There should at least be an option that today's values reflect closing prices. One of the things I wanted to script was to check whether I need to sell something or transfer cash depending on margin balances (say 1 minute before closing), and it is aggravating that is hard to tell what the margin balance actually is (meaning: so I need to take action to avoid paying margin interest) because the numbers do not reflect closing prices and keep changing, AFAICT.

I realize that balances not reflecting closing is not the fault of this library, but rather a "feature" of the Ameritrade API. But does anyone else have any thoughts about how to fix this problem?

async ouch

Hi Alex.

Spent the last few hours tracking down what I think is a bug.

stream() at
https://github.com/areed1192/td-ameritrade-python-api/blob/master/samples/api_streaming.py#L78
ends up passing pipeline_start=False to _connect at
https://github.com/areed1192/td-ameritrade-python-api/blob/master/td/stream.py#L533

The problem is that stream() sends the subsequent data commands without waiting for the connect to finish.
On my machine, I end up with the commands being received out of order, leading to an error/disconnect.

Connection established. Streaming will begin shortly.
====================
Message Recieved:

{'response': [{'service': 'LEVELONE_FUTURES', 'requestid': '1', 'command': 'SUBS', 'timestamp': 1591951833155, 'content': {'code': 3, 'msg': 'Login Denied. - Please login first.'}}]}
--------------------

====================
Message Recieved:

{'response': [{'service': 'ADMIN', 'requestid': '0', 'command': 'LOGIN', 'timestamp': 1591951833155, 'content': {'code': 0, 'msg': '05-2'}}]}
--------------------

Connection with server closed, beginning close process...
Event loop was not closed.

It's unclear to me why you even have that pipeline_start arg, so I did not try to submit a fix, but by just always waiting for the login command, it now works for me.

uggg

PS Recieved is spelled wrong :)

Ethan

Streaming issues: local variables and message formatting

Hello, I'm using the test_streaming_client.py as a template, and getting a few errors. To start off, here is my code (I'm using v0.2.2):

import requests
from td.client import TDClient
import config

# Create a new session
TDSession = TDClient(account_number = config.account_number,
                     account_password = config.account_password,
                     consumer_id = config.consumer_id,
                     redirect_uri = config.redirect_uri)

# Login to the session
TDSession.login()
# Create a streaming sesion
TDStreamingClient = TDSession.create_streaming_session()
# Define the CSV Append Mode. Needs to be rewritten it's kind of awkward to call it like this.
TDStreamingClient.CSV_APPEND_MODE = True
# Actives
TDStreamingClient.actives(service='ACTIVES_NASDAQ', venue='NASDAQ', duration='ALL')
# Quality of Service
TDStreamingClient.quality_of_service(qos_level='express')
# Level One Quote
TDStreamingClient.level_one_quotes(symbols=["VOO"],  fields=list(range(0,8)))
# Stream it.
TDStreamingClient.stream()

And I'm getting the following error:

Traceback (most recent call last):
  File "streaming.py", line 92, in <module>
    TDStreamingClient.quality_of_service(qos_level='express')
  File "/Users/mattsonthieme/miniconda3/envs/tdameritrade/lib/python3.7/site-packages/td/stream.py", line 427, in quality_of_service
    qos_level = self._validate_argument(argument=qos_level, endpoint='qos_request')
  File "/Users/mattsonthieme/miniconda3/envs/tdameritrade/lib/python3.7/site-packages/td/stream.py", line 412, in _validate_argument
    arg_list.append(key_value)
UnboundLocalError: local variable 'arg_list' referenced before assignment

It appears that arg_list is defined in the if block on line 386 of td/stream.py and not visible in the else block. Moving the arg_list initialization outside the if statement to line 381 fixes the UnboundLocalError issue but then produces another. It looks like the formatting of the messages (at least for level_one_quotes) may be a bit off, as I get the following error:

Connection established. Streaming will begin shortly.
--------------------
Received message from server: {'response': [{'service': 'ADMIN', 'requestid': '0', 'command': 'LOGIN', 'timestamp': 1584972659701, 'content': {'code': 0, 'msg': '02-2'}}]}
--------------------
Received message from server: {'response': [{'service': 'ADMIN', 'requestid': '0', 'command': 'LOGOUT', 'timestamp': 1584972659701, 'content': {'code': 21, 'msg': 'Bad command formatting'}}]}
Connection with server closed

I'm reading TDA's docs online but not sure exactly what about the request is incorrect.

PermissionError: [Errno 13] Permission denied

### PermissionError: [Errno 13] Permission denied?

I dint use credentials path.

Traceback (most recent call last):
File "c:/Personal/Trade/td-ameritrade-python-api-master/tests/unit/test_oauth.py", line 4, in
TDSession = TDClient(
File "C:\Users\rp\AppData\Local\Programs\Python\Python38-32\lib\site-packages\td\client.py", line 119, in init
self._state_manager('init')
File "C:\Users\rp\AppData\Local\Programs\Python\Python38-32\lib\site-packages\td\client.py", line 207, in _state_manager
with open(file=credentials_file_path, mode='r') as json_file:
PermissionError: [Errno 13] Permission denied: 'C:\Users\rp\AppData\Local\Programs\Python\Python38-32\lib\site-packages\td'

problem with place_order when passing <order>

When I created the order class and its order leg, then try to call place_order, I get TypeError: Object of type Order is not JSON serializable

It seems the order leg is stored as object in the order which json refuses to dump. Am I thinking this correctly?

CODE:
new_order = Order()
new_order.order_session(session=ORDER_SESSION.NORMAL)
new_order.order_duration(duration=DURATION.DAY)
new_order.order_type(order_type=ORDER_TYPE.LIMIT)
new_order.order_strategy_type(order_strategy_type=ORDER_STRATEGY_TYPE.SINGLE)

new_order_leg = OrderLeg()
new_order_leg.order_leg_instruction(instruction=ORDER_INSTRUCTIONS.BUY)
new_order_leg.order_leg_price(price=100.0)
new_order_leg.order_leg_quantity(quantity=1)
new_order_leg.order_leg_asset(asset_type=ORDER_ASSET_TYPE.EQUITY, symbol='MSFT')

add to new_order

new_order.add_order_leg(order_leg=new_order_leg)

pprint prints fine

pprint.pprint(new_order._grab_order())
print('-'*80)

submit order

order_result = TDSession.place_order(account = ACCOUNT_NUMBER, order = new_order)

the place_order returns TypeError: Object of type Order is not JSON serializable

create_saved_order bug

In client.py -> create_saved_order function, the following lines have typo:

check to see if it's an order object.

    if isinstance(saved_order, Order):
        order = order._saved_order_to_json()
    else:
        order = order

which need to be changed to:

check to see if it's an order object.

    if isinstance(saved_order, Order):
        order = saved_order._saved_order_to_json()
    else:
        order = saved_order

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.