Skip to content

Latest commit

 

History

History
379 lines (287 loc) · 12.5 KB

client.rst

File metadata and controls

379 lines (287 loc) · 12.5 KB

python

HTTP Client

A naive, unopinionated wrapper around the TD Ameritrade HTTP API. This client provides access to all endpoints of the API in as easy and direct a way as possible. For example, here is how you can fetch the past 20 years of data for Apple stock:

Do not attempt to use more than one Client object per token file, as this will likely cause issues with the underlying OAuth2 session management

from tda.auth import easy_client
from tda.client import Client

c = easy_client(
        api_key='APIKEY',
        redirect_uri='https://localhost',
        token_path='/tmp/token.json')

resp = c.get_price_history('AAPL',
        period_type=Client.PriceHistory.PeriodType.YEAR,
        period=Client.PriceHistory.Period.TWENTY_YEARS,
        frequency_type=Client.PriceHistory.FrequencyType.DAILY,
        frequency=Client.PriceHistory.Frequency.DAILY)
assert resp.status_code == httpx.codes.OK
history = resp.json()

Note we we create a new client using the auth package as described in auth. Creating a client directly is possible, but not recommended.

Asyncio Support

An asynchronous variant is available through a keyword to the client constructor. This allows for higher-performance API usage, at the cost of slightly increased application complexity.

from tda.auth import easy_client
from tda.client import Client

async def main():
    c = easy_client(
            api_key='APIKEY',
            redirect_uri='https://localhost',
            token_path='/tmp/token.json',
            asyncio=True)

    resp = await c.get_price_history('AAPL',
            period_type=Client.PriceHistory.PeriodType.YEAR,
            period=Client.PriceHistory.Period.TWENTY_YEARS,
            frequency_type=Client.PriceHistory.FrequencyType.DAILY,
            frequency=Client.PriceHistory.Frequency.DAILY)
    assert resp.status_code == httpx.codes.OK
    history = resp.json()

if __name__ == '__main__':
    import asyncio
    asyncio.run_until_complete(main())

For more examples, please see the examples/async directory in GitHub.

Calling Conventions

Function parameters are categorized as either required or optional. Required parameters, such as 'AAPL' in the example above, are passed as positional arguments. Optional parameters, like period_type and the rest, are passed as keyword arguments.

Parameters which have special values recognized by the API are represented by Python enums. This is because the API rejects requests which pass unrecognized values, and this enum wrapping is provided as a convenient mechanism to avoid consternation caused by accidentally passing an unrecognized value.

By default, passing values other than the required enums will raise a ValueError. If you believe the API accepts a value that isn't supported here, you can use set_enforce_enums to disable this behavior at your own risk. If you do find a supported value that isn't listed here, please open an issue describing it or submit a PR adding the new functionality.

Return Values

All methods return a response object generated under the hood by the HTTPX module. For a full listing of what's possible, read that module's documentation. Most if not all users can simply use the following pattern:

r = client.some_endpoint()
assert r.status_code == httpx.codes.OK, r.raise_for_status()
data = r.json()

The API indicates errors using the response status code, and this pattern will raise the appropriate exception if the response is not a success. The data can be fetched by calling the .json() method.

This data will be pure python data structures which can be directly accessed. You can also use your favorite data analysis library's dataframe format using the appropriate library. For instance you can create a pandas dataframe using its conversion method <https://pandas.pydata.org/pandas-docs/stable/reference/api/ pandas.DataFrame.from_dict.html>__.

Note: Because the author has no relationship whatsoever with TD Ameritrade, this document makes no effort to describe the structure of the returned JSON objects. TDA might change them at any time, at which point this document will become silently out of date. Instead, each of the methods described below contains a link to the official documentation. For endpoints that return meaningful JSON objects, it includes a JSON schema which describes the return value. Please use that documentation or your own experimentation when figuring out how to use the data returned by this API.

Creating a New Client

99.9% of users should not create their own clients, and should instead follow the instructions outlined in auth.

For users who want to disable the strict enum type checking on http client, just pass enforce_enums=False in any of the client creation functions described in auth. Just note that for most users, it is advised they stick with the default behavior.

For those brave enough to build their own, the constructor looks like this:

tda.client.Client.__init__

Timeout Management

Timeouts for HTTP calls are managed under the hood by the httpx library. tda-api defaults to 30 seconds, which experience has shown should be more than enough to allow even the slowest API calls to complete. A different timeout specification can be set using this method:

tda.client.Client.set_timeout

Orders

Placing New Orders

Placing new orders can be a complicated task. The Client.place_order method is used to create all orders, from equities to options. The precise order type is defined by a complex order spec. TDA provides some example order specs to illustrate the process and provides a schema in the place order documentation <https://developer.tdameritrade.com/account-access/apis/post/accounts/ %7BaccountId%7D/orders-0>__, but beyond that we're on our own.

tda-api includes some helpers, described in order_templates, which provide an incomplete utility for creating various order types. While it only scratches the surface of what's possible, we encourage you to use that module instead of creating your own order specs.

tda.client.Client.place_order

Accessing Existing Orders

tda.client.Client.get_orders_by_path

tda.client.Client.get_orders_by_query

tda.client.Client.get_order

tda.client.Client.Order

Editing Existing Orders

Endpoints for canceling and replacing existing orders. Annoyingly, while these endpoints require an order ID, it seems that when placing new orders the API does not return any metadata about the new order. As a result, if you want to cancel or replace an order after you've created it, you must search for it using the methods described in accessing_existing_orders.

tda.client.Client.cancel_order

tda.client.Client.replace_order

Account Info

These methods provide access to useful information about accounts. An incomplete list of the most interesting bits:

  • Account balances, including available trading balance
  • Positions
  • Order history

See the official documentation for each method for a complete response schema.

tda.client.Client.get_account

tda.client.Client.get_accounts

tda.client.Client.Account

Instrument Info

Note: symbol fundamentals (P/E ratios, number of shares outstanding, dividend yield, etc.) is available using the Instrument.Projection.FUNDAMENTAL projection.

tda.client.Client.search_instruments

tda.client.Client.get_instrument

tda.client.Client.Instrument

Option Chain

Unfortunately, option chains are well beyond the ability of your humble author. You are encouraged to read the official API documentation to learn more.

If you are knowledgeable enough to write something more substantive here, please follow the instructions in contributing to send in a patch.

tda.client.Client.get_option_chain

tda.client.Client.Options

Price History

TDA provides price history for equities and ETFs. It does not provide price history for options, futures, or any other instruments.

In the raw API, fetching price history is somewhat complicated: the API offers a single endpoint Client.get_price_history that accepts a complex variety of inputs, but fails to document them in any meaningful way.

Thankfully, we've reverse engineered this endpoint and built some helpful utilities for fetching prices by minute, day, week, etc. Each method can be called with or without date bounds. When called without date bounds, it returns all data available. Each method offers a different lookback period, so make sure to read the documentation below to learn how much data is available.

tda.client.Client.get_price_history_every_minute

tda.client.Client.get_price_history_every_five_minutes

tda.client.Client.get_price_history_every_ten_minutes

tda.client.Client.get_price_history_every_fifteen_minutes

tda.client.Client.get_price_history_every_thirty_minutes

tda.client.Client.get_price_history_every_day

tda.client.Client.get_price_history_every_week

For the sake of completeness, here is the documentation for the raw price history endpoint, in all its complexity.

tda.client.Client.get_price_history

tda.client.Client.PriceHistory

Current Quotes

tda.client.Client.get_quote

tda.client.Client.get_quotes

Other Endpoints

Note If your account limited to delayed quotes, these quotes will also be delayed.

Transaction History

tda.client.Client.get_transaction

tda.client.Client.get_transactions

tda.client.Client.Transactions

Saved Orders

tda.client.Client.create_saved_order

tda.client.Client.delete_saved_order

tda.client.Client.get_saved_order

tda.client.Client.get_saved_orders_by_path

tda.client.Client.replace_saved_order

Market Hours

tda.client.Client.get_hours_for_multiple_markets

tda.client.Client.get_hours_for_single_market

tda.client.Client.Markets

Movers

tda.client.Client.get_movers

tda.client.Client.Movers

User Info and Preferences

tda.client.Client.get_preferences

tda.client.Client.get_user_principals

tda.client.Client.update_preferences

tda.client.Client.UserPrincipals

Watchlists

Note: These methods only support static watchlists, i.e. they cannot access dynamic watchlists.

tda.client.Client.create_watchlist

tda.client.Client.delete_watchlist

tda.client.Client.get_watchlist

tda.client.Client.get_watchlists_for_multiple_accounts

tda.client.Client.get_watchlists_for_single_account

tda.client.Client.replace_watchlist

tda.client.Client.update_watchlist