Skip to content
William Studer edited this page Mar 24, 2022 · 32 revisions

How To

Instantiate a Client

Client Properties

To create a client, there are two required properties (and a few optional ones that can be set).

  • tda.token.refresh (Required) - the refresh token for TDA OAuth. See Simple Auth for Local Apps to create it.
  • tda.client_id (Required) - Your TDA Client ID (sometimes referred to as consumer key in TDA's docs) is created when you register your app with TDA. See Getting Started. Note, you shouldn't append @AMER.OAUTHAP to the client id. It's only used when creating a refresh token.
  • tda.url (Optional) - URL root of the API which defaults to https://api.tdameritrade.com/v1.
  • tda.debug.bytes.length (Optional) - How many bytes does the logging interceptor debug to output? -1 is unlimited and is the default.

Using a Properties File and Default Constructor

Drop a file into the root of your classpath named tda-api.properties. With a default Maven project, the location is src/main/resources. Then instantiate a client using the default constructor:

TdaClient client = new HttpTdaClient();

Setting the Properties in Constructor:

Properties props = new Properties();
props.setProperty("tda.client_id", "...");
props.setProperty("tda.token.refresh", "...");

TdaClient client = new HttpTdaClient(props);

Note that you should not instantiate the HttpTdaClient more than once per context or app as each new instance will generate a new TDA OAuth token, and TDA will eventually blacklist or throttle your account if you continue to create many instances (and thus tokens) within some unknown period of time.

Be especially careful when using the client with Spring, Guice, or other DI frameworks i.e. ensure that your instance is a Singleton. The client is thread safe so can be safely shared in multiple threads.

Getting the Main Account ID

It's possible to have multiple accounts under a single login and thus OAuth credentials. Normally, though, small time investors will probably have a single account id. Many calls require this account id as a parameter.

You should verify that you do have only one account id, and if that's the case, you can get it and store it with the following call

List<SecuritiesAccount> accounts = client.getAccounts(false, false);
if (accounts.size() > 1) {
  throw new RuntimeException("I actually have multiple accounts...").
}

String accountId = accounts.get(0).getAccountId();
System.out.println("My account ID: " + accountId);

Fetch Market Quotes:

Quote quote = client.fetchQuote("MSFT");
EquityQuote equityQuote = (EquityQuote)quote;
System.out.println("Current price of MSFT: " + equityQuote.getAskPrice());

The TDA api allows fetching quotes for equities, mutual funds, futures, options, etc. The TdaClient always returns one or more Quote objects which can then be cast to the actual class based on the underlying AssetType. For example:

List<String> symbols = Arrays.asList("VTSAX", "MSFT", "NOK/JPY", "$SPX.X", "MSFT_061821P65", "SPY");
final List<Quote> quotes = client.fetchQuotes(symbols);

assertThat(quotes.get(0)).isInstanceOf(MutualFundQuote.class);
assertThat(quotes.get(1)).isInstanceOf(EquityQuote.class);
assertThat(quotes.get(2)).isInstanceOf(ForexQuote.class);
assertThat(quotes.get(3)).isInstanceOf(IndexQuote.class);
assertThat(quotes.get(4)).isInstanceOf(OptionQuote.class);
assertThat(quotes.get(5)).isInstanceOf(EtfQuote.class);

Get Price History

There are some more examples on the TDA site.

Get a price history for a single security using default parameters which is something like a single quote for every minute of the last ten days:

PriceHistory priceHistory = client.priceHistory("GOOG");

Use a PriceHistoryReq.Builder. For example, get history for VGIAX for the last week, for every one minute.

PriceHistReq request = Builder.priceHistReq()
        .withSymbol("VGIAX")
        .withStartDate(System.currentTimeMillis() - (1000 * 60 * 60 * 24 * 7))
        .withFrequencyType(FrequencyType.minute)
        .withFrequency(1)
        .build();

PriceHistory priceHistory = client.priceHistory(request);

Get Account Information

final List<SecuritiesAccount> accounts = client.getAccounts(true, true);

Trade

Make an Order

Create the Order Object

There are so many types of orders that can be placed, the Order is overkill for simple equity trades.

TDA put up some more examples on their developer site.

Order order = new Order();
order.setOrderType(OrderType.MARKET);
order.setSession(Session.NORMAL);
order.setDuration(Duration.DAY);
order.setOrderStrategyType(OrderStrategyType.SINGLE);

OrderLegCollection olc = new OrderLegCollection();
olc.setInstruction(Instruction.BUY);
olc.setQuantity(new BigDecimal("15.0"));
order.getOrderLegCollection().add(olc);

Instrument instrument = new EquityInstrument();
instrument.setSymbol("MSFT");
olc.setInstrument(instrument);

Once the order is created, place it with the client:

client.placeOrder("<account_id>", order);

If you've used the client successfully with more complex orders e.g. stops and limits and multi-leg option orders, I'd love if you could provide some code examples for this wiki as a lot of new users get tripped up with this part of the API. I use the API mostly for reading data and not making simple automated market buy orders, and so I have little experience with more complex calls.

Cancel an Order

client.cancelOrder("<account_id>", "<order_id>");

Fetch Order(s)

Fetch a specific order by ID under a specific account.

Order order = client.fetchOrder("<account_id>", "<order_id>");

Fetch all Orders, including cancelled, under all your accounts:

List<Order> client.fetchOrders();

Fetch Orders using criteria:

Last 10 days:

OrderRequest req = new OrderRequest(ZonedDateTime.now().minusDays(10), ZonedDateTime.now());
List<Order> client.fetchOrders(orderRequest);

Symbol Lookup

Lookup all symbols using a regex:

Query query = new Query("ms.*", QueryType.SYMBOL_REGEX);
final List<Instrument> instruments =client.queryInstruments(query);

Lookup all instruments (equities, forex, bonds, options, etc.) by description regex:

Query query = new Query("bank", QueryType.DESCRIPTION_SEARCH);
List<Instrument> instruments = client.queryInstruments(query);

Lookup a bond by explicit CUSIP:

List<String> cusips = Arrays.asList("70153RJT6", "33616CGC8", "06405VDP1", "61690UNX4");
cusips.forEach(cusip -> {
  Instrument instrument = client.getBond(cusip);
  assertThat(instrument.getAssetType()).isEqualTo(AssetType.BOND);
  assertThat(instrument.getBondPrice()).isNotNull();
});

Get Full Fundamentals on an Instrument

final FullInstrument instrument = client.getFundamentalData("msft");
assertThat(instrument.getAssetType()).isEqualTo(AssetType.EQUITY);
assertThat(instrument.getSymbol()).isEqualTo("MSFT");
assertThat(instrument.getExchange()).isEqualTo("NASDAQ");
Fundamental fundamental = instrument.getFundamental();
assertThat(fundamental.getMarketCapFloat()).isGreaterThan(new BigDecimal("1"));
assertThat(fundamental.getDividendDate()).isNotEmpty();

Fetch Transactions

Transactions can be anything from buying and selling equities, options, etc. to money market interest and mutual fund dividends.

// Fetch transactions using default criteria from TDA
List<Transaction> transactions = client.fetchTransactions(<account_id>, new TransactionRequest());
transaction.forEach(t -> System.out.println(t.toString()); 

Or you can build up a specific request based on dates and other criteria.

//Get Microsoft transactions for the last year
TransactionRequest request = new TransactionRequest(
  "MSFT",
  LocalDate.now().minusYears(1),
  LocalDate.now()
);

List<Transaction> transactions = client.fetchTransactions(<account_id>, request);

Fetch Market Movers

Retrieve mover information by index symbol, direction type and change. By default, it will receive the top / bottom ten equities of the day.

MoversReq moversReq = new MoversReq(Index.NASDAQ, Direction.down, Change.VALUE);
final List<Mover> movers = client.fetchMovers(moversReq);
movers.forEach(m -> System.out.println(m.toString());

Lookup Option Chains

Look up an option chain. TDA response is somewhat verbose. This eventually gets the PUT for MSFT expiring on 2020-01-10 @ $135 strike price.

OptionChain optionChain = client.getOptionChain("MSFT");
Map<String, Map<BigDecimal, List<Option>>> putExpDateMap = optionChain.getPutExpDateMap();

Map<BigDecimal, List<Option>> bigDecimalListMap = putExpDateMap.get("2020-01-10:42");

Option option = bigDecimalListMap.get(new BigDecimal("135.0")).get(0);

System.out.println("Bid Price: " + option.getBidPrice());

//MSFT Jan 10 2020 135 Put (Weekly)
System.out.println("Description: " + option.getDescription());

//MSFT_011020P135
System.out.println("TDA Symbol: " + option.getSymbol());

Get User Account Preferences

User Preferences include things like default equity order types, duration, etc.

Preferences prefs = client.getPreferences();
System.out.println("My User Preferences: " + prefs.toString());

Get User Principals

This is used for streaming and includes settings such as primary account id, login info, token and authentication codes and expiration times, delayed quotes, professional status, etc.

UserPrincipals userPrincipals = client.getUserPrincipals();
System.out.println("My User Principals: " + userPrincipals.toString());

To Get extended attributes, use one or more UserPrincipals.Field parameters

final UserPrincipals userPrincipals = httpTdaClient
        .getUserPrincipals(
            Field.streamerConnectionInfo,
            Field.surrogateIds,
            Field.streamerSubscriptionKeys,
            Field.preferences
        );

assertThat(userPrincipals).isNotNull();
assertThat(userPrincipals.getStreamerSubscriptionKeys()).isNotNull();
assertThat(userPrincipals.getStreamerInfo()).isNotNull();
assertThat(userPrincipals.getAccounts().get(0).getSurrogateIds()).isNotNull();
assertThat(userPrincipals.getAccounts().get(0).getPreferences()).isNotNull();

System.out.println("My User Principals: " + userPrincipals.toString());