├── .eslintrc.json ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── apidocsarchive ├── accountstrading │ ├── accounts_getaccount.txt │ ├── accounts_getaccounts.txt │ ├── orders_cancelorder.txt │ ├── orders_getorder.txt │ ├── orders_getorderquery.txt │ ├── orders_getordersbypath.txt │ ├── orders_placeorder.txt │ ├── orders_replaceorder.txt │ ├── saved_createsaved.txt │ ├── saved_deletesaved.txt │ ├── saved_getsavedbyid.txt │ ├── saved_getsavedbypath.txt │ └── saved_replacesaved.txt ├── authentication │ └── authentication_accesstoken.txt ├── instruments │ ├── instruments_getinstrument.txt │ └── instruments_searchinstruments.txt ├── markethours │ ├── markethours_getmultiple.txt │ └── markethours_getsingle.txt ├── movers │ └── movers_getmovers.txt ├── optionchains │ └── optionchains_getchain.txt ├── pricehistory │ └── pricehistory_getpricehistory.txt ├── quotes │ ├── quotes_getquote.txt │ └── quotes_getquotes.txt ├── streamingdata │ └── streamdata.txt ├── transactionhistory │ ├── transactions_gettransaction.txt │ └── transactions_gettransactions.txt ├── userinfo │ ├── userinfo_getpreferences.txt │ ├── userinfo_getstreamersubkeys.txt │ ├── userinfo_updatepreferences.txt │ └── userinfo_userprincipals.txt └── watchlist │ ├── watchlist_createwatchlist.txt │ ├── watchlist_deletewatchlist.txt │ ├── watchlist_getwatchlist.txt │ ├── watchlist_getwatchlistsmultiacct.txt │ ├── watchlist_getwatchlistssingleacct.txt │ ├── watchlist_replacewatchlist.txt │ └── watchlist_updatewatchlist.txt ├── authREADME.md ├── babel.config.js ├── codesamplesREADME.md ├── config └── tdaclientauth.json ├── jest.config.ts ├── package-lock.json ├── package.json ├── sampledata ├── instruments-getFundamentals.txt ├── instruments-getInstrument.txt ├── instruments-searchInstruments.txt ├── marketdata-getMultipleMarketHours.txt ├── marketdata-getSingleMarketHours.txt ├── movers-getmovers.txt ├── optionschain-getoptions.txt ├── orders-getOrder.txt ├── orders-placeorder.txt ├── pricehistory-getPriceHistory.txt ├── quotes_getQuote.txt ├── quotes_getQuotes.txt ├── stream_ACCT_ACTIVITY.txt ├── stream_CHART_EQUITY.txt ├── stream_CHART_FUTURES.txt ├── stream_LEVELONE_FOREX.txt ├── stream_LEVELONE_FUTURES.txt ├── stream_LEVELONE_FUTURES_OPTIONS.txt ├── stream_NEWS_HEADLINE.txt ├── stream_OPTION.txt ├── stream_QUOTE.txt ├── transactions-getTransaction.txt ├── transactions-getTransactions.txt ├── userinfo-getPreferences.txt ├── userinfo-getStreamerSubKeys.txt ├── userinfo-getUserPrincipals.txt ├── userinfo-updatePreferences.txt ├── watchlist-createwatchlist.txt ├── watchlist-deletewatchlist.txt ├── watchlist-getwatchlist.txt ├── watchlist-replacewatchlist.txt └── watchlist-updatewatchlist.txt ├── samples └── inputJSON │ ├── order.json │ ├── userpreferences.json │ └── watchlist.json ├── src ├── accounts.test.ts ├── accounts.ts ├── cli │ ├── accounts-cli.ts │ ├── authentication-cli.ts │ ├── instruments-cli.ts │ ├── markethours-cli.ts │ ├── movers-cli.ts │ ├── optionschain-cli.ts │ ├── orders-cli.ts │ ├── pricehistory-cli.ts │ ├── quotes-cli.ts │ ├── savedorders-cli.ts │ ├── transactions-cli.ts │ ├── userinfo-cli.ts │ └── watchlists-cli.ts ├── cli_index.ts ├── index.ts ├── instruments.test.ts ├── instruments.ts ├── license.ts ├── markethours.test.ts ├── markethours.ts ├── movers.test.ts ├── movers.ts ├── optionschain.test.ts ├── optionschain.ts ├── orders.test.ts ├── orders.ts ├── pricehistory.test.ts ├── pricehistory.ts ├── quotes.test.ts ├── quotes.ts ├── savedorders.ts ├── sharedTypes.ts ├── streamDataTDA.test.ts ├── streamDataTDA.ts ├── streamingdatatypes.ts ├── streamingutils.ts ├── tdapiinterface.test.ts ├── tdapiinterface.ts ├── transactions.test.ts ├── transactions.ts ├── userinfo.test.ts ├── userinfo.ts ├── watchlists.test.ts └── watchlists.ts ├── streamingREADME.md └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": 12 14 | }, 15 | "plugins": [ 16 | "@typescript-eslint" 17 | ], 18 | "rules": { 19 | "@typescript-eslint/no-explicit-any": "off", 20 | "@typescript-eslint/explicit-module-boundary-types": [ 21 | "error", 22 | { 23 | "allowArgumentsExplicitlyTypedAsAny": true 24 | } 25 | ], 26 | "@typescript-eslint/no-unused-vars": "off", 27 | "@typescript-eslint/ban-ts-comment": "off", 28 | "@typescript-eslint/no-non-null-assertion": "off", 29 | "indent": [ 30 | "error", 31 | 4 32 | ], 33 | "linebreak-style": [ 34 | "error", 35 | "unix" 36 | ], 37 | "quotes": [ 38 | "error", 39 | "double", 40 | { "allowTemplateLiterals": true } 41 | ], 42 | "semi": [ 43 | "error", 44 | "always" 45 | ], 46 | "eol-last": [ 47 | "error", 48 | "always" 49 | ], 50 | "comma-dangle": [ 51 | "error", 52 | "always-multiline" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | dist/ 4 | indexnew.ts 5 | troubleshoot.js 6 | *.tgz 7 | temp/ 8 | streamingtest.ts 9 | test* 10 | dist/*test* 11 | *indexnew* 12 | src/test_tdaclientauth.json 13 | coverage/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | streamingtest.ts 2 | *.tgz 3 | test* 4 | indexnew.ts 5 | dist/*test* 6 | /.idea 7 | troubleshoot.js 8 | *indexnew* -------------------------------------------------------------------------------- /apidocsarchive/accountstrading/accounts_getaccounts.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/account-access/apis/get/accounts-0 4 | 5 | Accounts and Trading Documentation Get Accounts 6 | GETGet Accounts 7 | Account balances, positions, and orders for all linked accounts. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts 11 | 12 | Query Parameters 13 | Name Values Description 14 | fields 15 | Balances displayed by default, additional fields can be added here by adding positions or orders 16 | 17 | Example: 18 | fields=positions,orders 19 | 20 | Header Parameters 21 | Name Values Description 22 | Authorization 23 | Supply an access token to make an authenticated request. The format is Bearer . 24 | 25 | Resource Summary 26 | Security 27 | 28 | OAuth 2.0 29 | 30 | Response Summary 31 | JSON 32 | Schema 33 | [ 34 | //Account: 35 | { 36 | "securitiesAccount": "The type has the following subclasses [MarginAccount, CashAccount] descriptions are listed below" 37 | } 38 | ] 39 | 40 | //The class has the 41 | //following subclasses: 42 | //-MarginAccount 43 | //-CashAccount 44 | //JSON for each are listed below: 45 | 46 | //MarginAccount: 47 | { 48 | "type": "'CASH' or 'MARGIN'", 49 | "accountId": "string", 50 | "roundTrips": 0, 51 | "isDayTrader": false, 52 | "isClosingOnlyRestricted": false, 53 | "positions": [ 54 | { 55 | "shortQuantity": 0, 56 | "averagePrice": 0, 57 | "currentDayProfitLoss": 0, 58 | "currentDayProfitLossPercentage": 0, 59 | "longQuantity": 0, 60 | "settledLongQuantity": 0, 61 | "settledShortQuantity": 0, 62 | "agedQuantity": 0, 63 | "instrument": "The type has the following subclasses [Equity, FixedIncome, MutualFund, CashEquivalent, Option] descriptions are listed below\"", 64 | "marketValue": 0 65 | } 66 | ], 67 | "orderStrategies": [ 68 | { 69 | "session": "'NORMAL' or 'AM' or 'PM' or 'SEAMLESS'", 70 | "duration": "'DAY' or 'GOOD_TILL_CANCEL' or 'FILL_OR_KILL'", 71 | "orderType": "'MARKET' or 'LIMIT' or 'STOP' or 'STOP_LIMIT' or 'TRAILING_STOP' or 'MARKET_ON_CLOSE' or 'EXERCISE' or 'TRAILING_STOP_LIMIT' or 'NET_DEBIT' or 'NET_CREDIT' or 'NET_ZERO'", 72 | "cancelTime": { 73 | "date": "string", 74 | "shortFormat": false 75 | }, 76 | "complexOrderStrategyType": "'NONE' or 'COVERED' or 'VERTICAL' or 'BACK_RATIO' or 'CALENDAR' or 'DIAGONAL' or 'STRADDLE' or 'STRANGLE' or 'COLLAR_SYNTHETIC' or 'BUTTERFLY' or 'CONDOR' or 'IRON_CONDOR' or 'VERTICAL_ROLL' or 'COLLAR_WITH_STOCK' or 'DOUBLE_DIAGONAL' or 'UNBALANCED_BUTTERFLY' or 'UNBALANCED_CONDOR' or 'UNBALANCED_IRON_CONDOR' or 'UNBALANCED_VERTICAL_ROLL' or 'CUSTOM'", 77 | "quantity": 0, 78 | "filledQuantity": 0, 79 | "remainingQuantity": 0, 80 | "requestedDestination": "'INET' or 'ECN_ARCA' or 'CBOE' or 'AMEX' or 'PHLX' or 'ISE' or 'BOX' or 'NYSE' or 'NASDAQ' or 'BATS' or 'C2' or 'AUTO'", 81 | "destinationLinkName": "string", 82 | "releaseTime": "string", 83 | "stopPrice": 0, 84 | "stopPriceLinkBasis": "'MANUAL' or 'BASE' or 'TRIGGER' or 'LAST' or 'BID' or 'ASK' or 'ASK_BID' or 'MARK' or 'AVERAGE'", 85 | "stopPriceLinkType": "'VALUE' or 'PERCENT' or 'TICK'", 86 | "stopPriceOffset": 0, 87 | "stopType": "'STANDARD' or 'BID' or 'ASK' or 'LAST' or 'MARK'", 88 | "priceLinkBasis": "'MANUAL' or 'BASE' or 'TRIGGER' or 'LAST' or 'BID' or 'ASK' or 'ASK_BID' or 'MARK' or 'AVERAGE'", 89 | "priceLinkType": "'VALUE' or 'PERCENT' or 'TICK'", 90 | "price": 0, 91 | "taxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'AVERAGE_COST' or 'SPECIFIC_LOT'", 92 | "orderLegCollection": [ 93 | { 94 | "orderLegType": "'EQUITY' or 'OPTION' or 'INDEX' or 'MUTUAL_FUND' or 'CASH_EQUIVALENT' or 'FIXED_INCOME' or 'CURRENCY'", 95 | "legId": 0, 96 | "instrument": "\"The type has the following subclasses [Equity, FixedIncome, MutualFund, CashEquivalent, Option] descriptions are listed below\"", 97 | "instruction": "'BUY' or 'SELL' or 'BUY_TO_COVER' or 'SELL_SHORT' or 'BUY_TO_OPEN' or 'BUY_TO_CLOSE' or 'SELL_TO_OPEN' or 'SELL_TO_CLOSE' or 'EXCHANGE'", 98 | "positionEffect": "'OPENING' or 'CLOSING' or 'AUTOMATIC'", 99 | "quantity": 0, 100 | "quantityType": "'ALL_SHARES' or 'DOLLARS' or 'SHARES'" 101 | } 102 | Resource Error Codes 103 | HTTP Code 104 | 105 | Description 106 | 107 | 400 108 | 109 | An error message indicating the validation problem with the request. 110 | 111 | 401 112 | 113 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 114 | 115 | 500 116 | 117 | An error message indicating there was an unexpected server error. 118 | 119 | 403 120 | 121 | An error message indicating the caller is forbidden from accessing this page. 122 | 123 | 207 124 | 125 | Indicates there was a problem getting account data for one or more linked accounts, but the accounts who's data returned successfully is in the response. Do not aggregate balances and positions for this case. 126 | -------------------------------------------------------------------------------- /apidocsarchive/accountstrading/orders_cancelorder.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/account-access/apis/delete/accounts/%7BaccountId%7D/orders/%7BorderId%7D-0 4 | 5 | 6 | Accounts and Trading Documentation Cancel Order 7 | DELETECancel Order 8 | Cancel a specific order for a specific account. 9 | 10 | Resource URL 11 | https://api.tdameritrade.com/v1/accounts/{accountId}/orders/{orderId} 12 | 13 | Header Parameters 14 | Name Values Description 15 | Authorization 16 | Supply an access token to make an authenticated request. The format is Bearer . 17 | 18 | Try it out !! 19 | OAuth 2.0 20 | 21 | Set...SENDRESET 22 | RequestResponsecURL 23 | Make a request and see the response. 24 | 25 | Resource Summary 26 | Security 27 | 28 | OAuth 2.0 29 | 30 | Resource Error Codes 31 | HTTP Code 32 | 33 | Description 34 | 35 | 400 36 | 37 | An error message indicating the validation problem with the request. 38 | 39 | 401 40 | 41 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 42 | 43 | 500 44 | 45 | An error message indicating there was an unexpected server error. 46 | 47 | 403 48 | 49 | An error message indicating the caller is forbidden from accessing this page. 50 | 51 | 404 52 | 53 | An error message if the order was not found. 54 | -------------------------------------------------------------------------------- /apidocsarchive/accountstrading/saved_deletesaved.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/account-access/apis/delete/accounts/%7BaccountId%7D/savedorders/%7BsavedOrderId%7D-0 4 | 5 | Accounts and Trading Documentation Delete Saved Order 6 | DELETEDelete Saved Order 7 | Delete a specific saved order for a specific account. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/savedorders/{savedOrderId} 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | OAuth 2.0 19 | 20 | Set...SENDRESET 21 | RequestResponsecURL 22 | Make a request and see the response. 23 | 24 | Resource Summary 25 | Security 26 | 27 | OAuth 2.0 28 | 29 | Resource Error Codes 30 | HTTP Code 31 | 32 | Description 33 | 34 | 400 35 | 36 | An error message indicating the validation problem with the request. 37 | 38 | 401 39 | 40 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 41 | 42 | 500 43 | 44 | An error message indicating there was an unexpected server error. 45 | 46 | 403 47 | 48 | An error message indicating the caller is forbidden from accessing this page. 49 | 50 | 404 51 | 52 | An error message if the order was not found. 53 | -------------------------------------------------------------------------------- /apidocsarchive/authentication/authentication_accesstoken.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | Post Access Token 4 | https://api.tdameritrade.com/v1/oauth2/token 5 | 6 | Body Parameters 7 | Name Values Description 8 | grant_type (required) 9 | The grant type of the oAuth scheme. Possible values are authorization_code, refresh_token 10 | 11 | refresh_token 12 | Required if using refresh token grant 13 | 14 | access_type 15 | Set to offline to receive a refresh token 16 | 17 | code 18 | Required if trying to use authorization code grant 19 | 20 | client_id 21 | (required) 22 | OAuth User ID of your application 23 | 24 | redirect_uri 25 | Required if trying to use authorization code grant 26 | 27 | RESPONSE OBJECT 28 | //EASObject: 29 | { 30 | "access_token": "string", 31 | "refresh_token": "string", 32 | "token_type": "string", 33 | "expires_in": 0, 34 | "scope": "string", 35 | "refresh_token_expires_in": 0 36 | } 37 | 38 | Resource Error Codes 39 | 400 40 | An error message indicating the validation problem with the request. 41 | 401 42 | An error message indicating the caller must pass valid credentials in the request body. 43 | 500 44 | An error message indicating there was an unexpected server error. 45 | 403 46 | An error message indicating the caller doesn't have access to the account in the request. 47 | 503 48 | An error message indicating there is a temporary problem responding. 49 | -------------------------------------------------------------------------------- /apidocsarchive/markethours/markethours_getmultiple.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/market-hours/apis/get/marketdata/hours 4 | 5 | Market Hours Documentation Get Hours for Multiple Markets 6 | GETGet Hours for Multiple Markets 7 | Retrieve market hours for specified markets 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/marketdata/hours 11 | 12 | Query Parameters 13 | Name Values Description 14 | apikey 15 | (Optional) Pass your Client ID if making an unauthenticated request 16 | 17 | markets 18 | The markets for which you're requesting market hours, comma-separated. Valid markets are EQUITY, OPTION, FUTURE, BOND, or FOREX. 19 | 20 | date 21 | "The date for which market hours information is requested. Valid ISO-8601 formats are : yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz." 22 | 23 | Header Parameters 24 | Name Values Description 25 | Authorization 26 | Supply an access token to make an authenticated request. The format is Bearer . 27 | 28 | Try it out !! 29 | OAuth 2.0 30 | 31 | Set...SENDRESET 32 | RequestResponsecURL 33 | Make a request and see the response. 34 | 35 | Resource Summary 36 | Security 37 | 38 | OAuth 2.0 39 | 40 | Content Type 41 | 42 | application/json 43 | 44 | Response Summary 45 | JSON 46 | //Hours: 47 | { 48 | "category": "string", 49 | "date": "string", 50 | "exchange": "string", 51 | "isOpen": false, 52 | "marketType": "'BOND' or 'EQUITY' or 'ETF' or 'FOREX' or 'FUTURE' or 'FUTURE_OPTION' or 'INDEX' or 'INDICATOR' or 'MUTUAL_FUND' or 'OPTION' or 'UNKNOWN'", 53 | "product": "string", 54 | "productName": "string", 55 | "sessionHours": "object" 56 | } 57 | 58 | Schema 59 | //Hours: 60 | { 61 | "category": { 62 | "type": "string" 63 | }, 64 | "date": { 65 | "type": "string" 66 | }, 67 | "exchange": { 68 | "type": "string" 69 | }, 70 | "isOpen": { 71 | "type": "boolean" 72 | }, 73 | "marketType": { 74 | "type": "string", 75 | "enum": [ 76 | "BOND", 77 | "EQUITY", 78 | "ETF", 79 | "FOREX", 80 | "FUTURE", 81 | "FUTURE_OPTION", 82 | "INDEX", 83 | "INDICATOR", 84 | "MUTUAL_FUND", 85 | "OPTION", 86 | "UNKNOWN" 87 | ] 88 | }, 89 | "product": { 90 | "type": "string" 91 | }, 92 | "productName": { 93 | "type": "string" 94 | }, 95 | "sessionHours": { 96 | "type": "object", 97 | "additionalProperties": { 98 | "type": "array", 99 | "items": { 100 | "type": "string" 101 | } 102 | } 103 | } 104 | } 105 | 106 | Resource Error Codes 107 | HTTP Code 108 | 109 | Description 110 | 111 | 401 112 | 113 | Unauthorized 114 | 115 | 403 116 | 117 | Forbidden 118 | 119 | 404 120 | 121 | Not Found 122 | -------------------------------------------------------------------------------- /apidocsarchive/markethours/markethours_getsingle.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/market-hours/apis/get/marketdata/%7Bmarket%7D/hours 4 | 5 | Market Hours Documentation Get Hours for a Single Market 6 | GETGet Hours for a Single Market 7 | Retrieve market hours for specified single market 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/marketdata/{market}/hours 11 | 12 | Query Parameters 13 | Name Values Description 14 | apikey 15 | Pass your OAuth User ID to make an unauthenticated request for delayed data. 16 | 17 | date 18 | "The date for which market hours information is requested. Valid ISO-8601 formats are : yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz." 19 | 20 | Header Parameters 21 | Name Values Description 22 | Authorization 23 | Supply an access token to make an authenticated request. The format is Bearer . 24 | 25 | Try it out !! 26 | OAuth 2.0 27 | 28 | Set...SENDRESET 29 | RequestResponsecURL 30 | Make a request and see the response. 31 | 32 | Resource Summary 33 | Security 34 | 35 | OAuth 2.0 36 | 37 | Content Type 38 | 39 | application/json 40 | 41 | Response Summary 42 | JSON 43 | Schema 44 | //Hours: 45 | { 46 | "category": "string", 47 | "date": "string", 48 | "exchange": "string", 49 | "isOpen": false, 50 | "marketType": "'BOND' or 'EQUITY' or 'ETF' or 'FOREX' or 'FUTURE' or 'FUTURE_OPTION' or 'INDEX' or 'INDICATOR' or 'MUTUAL_FUND' or 'OPTION' or 'UNKNOWN'", 51 | "product": "string", 52 | "productName": "string", 53 | "sessionHours": "object" 54 | } 55 | Resource Error Codes 56 | HTTP Code 57 | 58 | Description 59 | 60 | 401 61 | 62 | Unauthorized 63 | 64 | 403 65 | 66 | Forbidden 67 | 68 | 404 69 | 70 | Not Found 71 | -------------------------------------------------------------------------------- /apidocsarchive/movers/movers_getmovers.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/movers/apis/get/marketdata/%7Bindex%7D/movers 4 | 5 | Movers Documentation Get Movers 6 | GETGet Movers 7 | Top 10 (up or down) movers by value or percent for a particular market 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/marketdata/{index}/movers 11 | 12 | Query Parameters 13 | Name Values Description 14 | apikey 15 | Pass your OAuth User ID to make an unauthenticated request for delayed data. 16 | 17 | direction 18 | (no value) 19 | To return movers with the specified directions of up or down 20 | 21 | change 22 | percent 23 | To return movers with the specified change types of percent or value 24 | 25 | Header Parameters 26 | Name Values Description 27 | Authorization 28 | Supply an access token to make an authenticated request. The format is Bearer . 29 | 30 | Try it out !! 31 | OAuth 2.0 32 | 33 | Set...SENDRESET 34 | RequestResponsecURL 35 | Make a request and see the response. 36 | 37 | Resource Summary 38 | Security 39 | 40 | OAuth 2.0 41 | 42 | Content Type 43 | 44 | application/json 45 | 46 | Response Summary 47 | JSON 48 | //Mover: 49 | { 50 | "change": 0, 51 | "description": "string", 52 | "direction": "'up' or 'down'", 53 | "last": 0, 54 | "symbol": "string", 55 | "totalVolume": 0 56 | } 57 | 58 | Schema 59 | //Mover: 60 | { 61 | "change": { 62 | "type": "number", 63 | "format": "double" 64 | }, 65 | "description": { 66 | "type": "string" 67 | }, 68 | "direction": { 69 | "type": "string", 70 | "enum": [ 71 | "up", 72 | "down" 73 | ] 74 | }, 75 | "last": { 76 | "type": "number", 77 | "format": "double" 78 | }, 79 | "symbol": { 80 | "type": "string" 81 | }, 82 | "totalVolume": { 83 | "type": "integer", 84 | "format": "int64" 85 | } 86 | } 87 | 88 | Resource Error Codes 89 | HTTP Code 90 | 91 | Description 92 | 93 | 400 94 | 95 | An error message indicating the caller must pass a correct value in the parameter. 96 | 97 | 401 98 | 99 | Unauthorized 100 | 101 | 403 102 | 103 | Forbidden 104 | 105 | 404 106 | 107 | An error message indicating movers for the instrument was not found. 108 | -------------------------------------------------------------------------------- /apidocsarchive/pricehistory/pricehistory_getpricehistory.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/price-history/apis/get/marketdata/%7Bsymbol%7D/pricehistory 4 | 5 | RESOURCE URL: https://api.tdameritrade.com/v1/marketdata/{symbol}/pricehistory 6 | 7 | Query Parameters 8 | 9 | apikey 10 | Pass your OAuth User ID to make an unauthenticated request for delayed data. 11 | 12 | periodType 13 | The type of period to show. Valid values are day, month, year, or ytd (year to date). Default is day. 14 | 15 | period 16 | The number of periods to show. 17 | 18 | Example: For a 2 day / 1 min chart, the values would be: 19 | 20 | period: 2 21 | periodType: day 22 | frequency: 1 23 | frequencyType: min 24 | 25 | Valid periods by periodType (defaults marked with an asterisk): 26 | 27 | day: 1, 2, 3, 4, 5, 10* 28 | month: 1*, 2, 3, 6 29 | year: 1*, 2, 3, 5, 10, 15, 20 30 | ytd: 1* 31 | 32 | frequencyType 33 | The type of frequency with which a new candle is formed. 34 | 35 | Valid frequencyTypes by periodType (defaults marked with an asterisk): 36 | 37 | day: minute* 38 | month: daily, weekly* 39 | year: daily, weekly, monthly* 40 | ytd: daily, weekly* 41 | 42 | frequency 43 | The number of the frequencyType to be included in each candle. 44 | 45 | Valid frequencies by frequencyType (defaults marked with an asterisk): 46 | 47 | minute: 1*, 5, 10, 15, 30 48 | daily: 1* 49 | weekly: 1* 50 | monthly: 1* 51 | 52 | endDate 53 | End date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided. Default is previous trading day. 54 | 55 | startDate 56 | Start date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided. 57 | 58 | needExtendedHoursData 59 | true to return extended hours data, false for regular market hours only. Default is true 60 | 61 | 62 | Header Parameters 63 | Authorization 64 | Supply an access token to make an authenticated request. The format is Bearer . 65 | 66 | 67 | */ 68 | 69 | 70 | /* 71 | RESPONSE 72 | //CandleList: 73 | { 74 | "candles": [ 75 | { 76 | "close": 0, 77 | "datetime": 0, 78 | "high": 0, 79 | "low": 0, 80 | "open": 0, 81 | "volume": 0 82 | } 83 | ], 84 | "empty": false, 85 | "symbol": "string" 86 | } 87 | */ 88 | 89 | /* 90 | Resource Error Codes 91 | HTTP Code 92 | 93 | Description 94 | 95 | 401 96 | 97 | Unauthorized 98 | 99 | 403 100 | 101 | Forbidden 102 | 103 | 404 104 | 105 | Not Found 106 | -------------------------------------------------------------------------------- /apidocsarchive/userinfo/userinfo_getpreferences.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/user-principal/apis/get/accounts/%7BaccountId%7D/preferences-0 4 | 5 | User Info and Preferences Documentation Get Preferences 6 | GETGet Preferences 7 | Preferences for a specific account. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/preferences 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | OAuth 2.0 19 | 20 | Set...SENDRESET 21 | RequestResponsecURL 22 | Make a request and see the response. 23 | 24 | Resource Summary 25 | Security 26 | 27 | OAuth 2.0 28 | 29 | Response Summary 30 | JSON 31 | //Preferences: 32 | { 33 | "expressTrading": false, 34 | "directOptionsRouting": false, 35 | "directEquityRouting": false, 36 | "defaultEquityOrderLegInstruction": "'BUY' or 'SELL' or 'BUY_TO_COVER' or 'SELL_SHORT' or 'NONE'", 37 | "defaultEquityOrderType": "'MARKET' or 'LIMIT' or 'STOP' or 'STOP_LIMIT' or 'TRAILING_STOP' or 'MARKET_ON_CLOSE' or 'NONE'", 38 | "defaultEquityOrderPriceLinkType": "'VALUE' or 'PERCENT' or 'NONE'", 39 | "defaultEquityOrderDuration": "'DAY' or 'GOOD_TILL_CANCEL' or 'NONE'", 40 | "defaultEquityOrderMarketSession": "'AM' or 'PM' or 'NORMAL' or 'SEAMLESS' or 'NONE'", 41 | "defaultEquityQuantity": 0, 42 | "mutualFundTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 43 | "optionTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 44 | "equityTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 45 | "defaultAdvancedToolLaunch": "'TA' or 'N' or 'Y' or 'TOS' or 'NONE' or 'CC2'", 46 | "authTokenTimeout": "'FIFTY_FIVE_MINUTES' or 'TWO_HOURS' or 'FOUR_HOURS' or 'EIGHT_HOURS'" 47 | } 48 | 49 | Schema 50 | //Preferences: 51 | { 52 | "expressTrading": { 53 | "type": "boolean", 54 | "default": false, 55 | "required": true 56 | }, 57 | "directOptionsRouting": { 58 | "type": "boolean", 59 | "default": false 60 | }, 61 | "directEquityRouting": { 62 | "type": "boolean", 63 | "default": false 64 | }, 65 | "defaultEquityOrderLegInstruction": { 66 | "type": "string", 67 | "enum": [ 68 | "BUY", 69 | "SELL", 70 | "BUY_TO_COVER", 71 | "SELL_SHORT", 72 | "NONE" 73 | ], 74 | "required": true 75 | }, 76 | "defaultEquityOrderType": { 77 | "type": "string", 78 | "enum": [ 79 | "MARKET", 80 | "LIMIT", 81 | "STOP", 82 | "STOP_LIMIT", 83 | "TRAILING_STOP", 84 | "MARKET_ON_CLOSE", 85 | "NONE" 86 | ], 87 | "required": true 88 | }, 89 | "defaultEquityOrderPriceLinkType": { 90 | "type": "string", 91 | "enum": [ 92 | "VALUE", 93 | "PERCENT", 94 | "NONE" 95 | ], 96 | "required": true 97 | }, 98 | "defaultEquityOrderDuration": { 99 | "type": "string", 100 | "enum": [ 101 | "DAY", 102 | "GOOD_TILL_CANCEL", 103 | "NONE" 104 | ], 105 | "required": true 106 | }, 107 | "defaultEquityOrderMarketSession": { 108 | "type": "string", 109 | "enum": [ 110 | "AM", 111 | "PM", 112 | "NORMAL", 113 | "SEAMLESS", 114 | "NONE" 115 | ], 116 | "required": true 117 | }, 118 | "defaultEquityQuantity": { 119 | "type": "integer", 120 | "format": "int32", 121 | "minimum": 0, 122 | "required": true 123 | }, 124 | "mutualFundTaxLotMethod": { 125 | "type": "string", 126 | "enum": [ 127 | "FIFO", 128 | "LIFO", 129 | "HIGH_COST", 130 | "LOW_COST", 131 | "MINIMUM_TAX", 132 | "AVERAGE_COST", 133 | "NONE" 134 | ], 135 | "required": true 136 | }, 137 | "optionTaxLotMethod": { 138 | "type": "string", 139 | "enum": [ 140 | "FIFO", 141 | "LIFO", 142 | "HIGH_COST", 143 | "LOW_COST", 144 | "MINIMUM_TAX", 145 | "AVERAGE_COST", 146 | "NONE" 147 | ], 148 | "required": true 149 | }, 150 | "equityTaxLotMethod": { 151 | "type": "string", 152 | "enum": [ 153 | "FIFO", 154 | "LIFO", 155 | "HIGH_COST", 156 | "LOW_COST", 157 | "MINIMUM_TAX", 158 | "AVERAGE_COST", 159 | "NONE" 160 | ], 161 | "required": true 162 | }, 163 | "defaultAdvancedToolLaunch": { 164 | "type": "string", 165 | "enum": [ 166 | "TA", 167 | "N", 168 | "Y", 169 | "TOS", 170 | "NONE", 171 | "CC2" 172 | ], 173 | "required": true 174 | }, 175 | "authTokenTimeout": { 176 | "type": "string", 177 | "enum": [ 178 | "FIFTY_FIVE_MINUTES", 179 | "TWO_HOURS", 180 | "FOUR_HOURS", 181 | "EIGHT_HOURS" 182 | ], 183 | "required": true 184 | } 185 | } 186 | 187 | Resource Error Codes 188 | HTTP Code 189 | 190 | Description 191 | 192 | 400 193 | 194 | An error message indicating the validation problem with the request. 195 | 196 | 401 197 | 198 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 199 | 200 | 500 201 | 202 | An error message indicating there was an unexpected server error. 203 | 204 | 503 205 | 206 | An error message indicating there is a temporary problem responding. 207 | -------------------------------------------------------------------------------- /apidocsarchive/userinfo/userinfo_getstreamersubkeys.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/user-principal/apis/get/userprincipals/streamersubscriptionkeys-0 4 | 5 | User Info and Preferences Documentation Get Streamer Subscription Keys 6 | GETGet Streamer Subscription Keys 7 | SubscriptionKey for provided accounts or default accounts. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/userprincipals/streamersubscriptionkeys 11 | 12 | Query Parameters 13 | Name Values Description 14 | accountIds 15 | A comma separated string of account IDs, to fetch subscription keys for each of them. 16 | 17 | Header Parameters 18 | Name Values Description 19 | Authorization 20 | Supply an access token to make an authenticated request. The format is Bearer . 21 | 22 | Try it out !! 23 | OAuth 2.0 24 | 25 | Set...SENDRESET 26 | RequestResponsecURL 27 | Make a request and see the response. 28 | 29 | Resource Summary 30 | Security 31 | 32 | OAuth 2.0 33 | 34 | Response Summary 35 | JSON 36 | //SubscriptionKey: 37 | { 38 | "keys": [ 39 | { 40 | "key": "string" 41 | } 42 | ] 43 | } 44 | 45 | Schema 46 | //SubscriptionKey: 47 | { 48 | "keys": { 49 | "type": "array", 50 | "items": { 51 | "type": "object", 52 | "properties": { 53 | "key": { 54 | "type": "string" 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | Resource Error Codes 62 | HTTP Code 63 | 64 | Description 65 | 66 | 400 67 | 68 | An error message indicating the validation problem with the request. 69 | 70 | 401 71 | 72 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 73 | 74 | 500 75 | 76 | An error message indicating there was an unexpected server error. 77 | 78 | 503 79 | 80 | An error message indicating there is a temporary problem responding. 81 | -------------------------------------------------------------------------------- /apidocsarchive/userinfo/userinfo_updatepreferences.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | //https://developer.tdameritrade.com/account-access/apis/put/accounts/%7BaccountId%7D/orders/%7BorderId%7D-0 4 | 5 | User Info and Preferences Documentation Update Preferences 6 | PUTUpdate Preferences 7 | Update preferences for a specific account. 8 | 9 | Please note that the directOptionsRouting and directEquityRouting values cannot be modified via this operation. 10 | 11 | Resource URL 12 | https://api.tdameritrade.com/v1/accounts/{accountId}/preferences 13 | 14 | Header Parameters 15 | Name Values Description 16 | Authorization 17 | Supply an access token to make an authenticated request. The format is Bearer . 18 | 19 | Try it out !! 20 | Value 21 | { 22 | "expressTrading": false, 23 | "directOptionsRouting": false, 24 | "directEquityRouting": false, 25 | "defaultEquityOrderLegInstruction": "'BUY' or 'SELL' or 'BUY_TO_COVER' or 'SELL_SHORT' or 'NONE'", 26 | "defaultEquityOrderType": "'MARKET' or 'LIMIT' or 'STOP' or 'STOP_LIMIT' or 'TRAILING_STOP' or 'MARKET_ON_CLOSE' or 'NONE'", 27 | "defaultEquityOrderPriceLinkType": "'VALUE' or 'PERCENT' or 'NONE'", 28 | "defaultEquityOrderDuration": "'DAY' or 'GOOD_TILL_CANCEL' or 'NONE'", 29 | "defaultEquityOrderMarketSession": "'AM' or 'PM' or 'NORMAL' or 'SEAMLESS' or 'NONE'", 30 | "defaultEquityQuantity": 0, 31 | "mutualFundTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 32 | "optionTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 33 | "equityTaxLotMethod": "'FIFO' or 'LIFO' or 'HIGH_COST' or 'LOW_COST' or 'MINIMUM_TAX' or 'AVERAGE_COST' or 'NONE'", 34 | "defaultAdvancedToolLaunch": "'TA' or 'N' or 'Y' or 'TOS' or 'NONE' or 'CC2'", 35 | "authTokenTimeout": "'FIFTY_FIVE_MINUTES' or 'TWO_HOURS' or 'FOUR_HOURS' or 'EIGHT_HOURS'" 36 | } 37 | 38 | Schema 39 | { 40 | "expressTrading": { 41 | "type": "boolean", 42 | "default": false 43 | }, 44 | "directOptionsRouting": { 45 | "type": "boolean", 46 | "default": false 47 | }, 48 | "directEquityRouting": { 49 | "type": "boolean", 50 | "default": false 51 | }, 52 | "defaultEquityOrderLegInstruction": { 53 | "type": "string", 54 | "enum": [ 55 | "BUY", 56 | "SELL", 57 | "BUY_TO_COVER", 58 | "SELL_SHORT", 59 | "NONE" 60 | ] 61 | }, 62 | "defaultEquityOrderType": { 63 | "type": "string", 64 | "enum": [ 65 | "MARKET", 66 | "LIMIT", 67 | "STOP", 68 | "STOP_LIMIT", 69 | "TRAILING_STOP", 70 | "MARKET_ON_CLOSE", 71 | "NONE" 72 | ] 73 | }, 74 | "defaultEquityOrderPriceLinkType": { 75 | "type": "string", 76 | "enum": [ 77 | "VALUE", 78 | "PERCENT", 79 | "NONE" 80 | ] 81 | }, 82 | "defaultEquityOrderDuration": { 83 | "type": "string", 84 | "enum": [ 85 | "DAY", 86 | "GOOD_TILL_CANCEL", 87 | "NONE" 88 | ] 89 | }, 90 | "defaultEquityOrderMarketSession": { 91 | "type": "string", 92 | "enum": [ 93 | "AM", 94 | "PM", 95 | "NORMAL", 96 | "SEAMLESS", 97 | "NONE" 98 | ] 99 | }, 100 | "defaultEquityQuantity": { 101 | "type": "integer", 102 | "format": "int32", 103 | "minimum": 0 104 | }, 105 | "mutualFundTaxLotMethod": { 106 | "type": "string", 107 | "enum": [ 108 | "FIFO", 109 | "LIFO", 110 | "HIGH_COST", 111 | "LOW_COST", 112 | "MINIMUM_TAX", 113 | "AVERAGE_COST", 114 | "NONE" 115 | ] 116 | }, 117 | "optionTaxLotMethod": { 118 | "type": "string", 119 | "enum": [ 120 | "FIFO", 121 | "LIFO", 122 | "HIGH_COST", 123 | "LOW_COST", 124 | "MINIMUM_TAX", 125 | "AVERAGE_COST", 126 | "NONE" 127 | ] 128 | }, 129 | "equityTaxLotMethod": { 130 | "type": "string", 131 | "enum": [ 132 | "FIFO", 133 | "LIFO", 134 | "HIGH_COST", 135 | "LOW_COST", 136 | "MINIMUM_TAX", 137 | "AVERAGE_COST", 138 | "NONE" 139 | ] 140 | }, 141 | "defaultAdvancedToolLaunch": { 142 | "type": "string", 143 | "enum": [ 144 | "TA", 145 | "N", 146 | "Y", 147 | "TOS", 148 | "NONE", 149 | "CC2" 150 | ] 151 | }, 152 | "authTokenTimeout": { 153 | "type": "string", 154 | "enum": [ 155 | "FIFTY_FIVE_MINUTES", 156 | "TWO_HOURS", 157 | "FOUR_HOURS", 158 | "EIGHT_HOURS" 159 | ] 160 | } 161 | } 162 | 163 | OAuth 2.0 164 | 165 | Set...SENDRESET 166 | RequestResponsecURL 167 | Make a request and see the response. 168 | 169 | Resource Summary 170 | Security 171 | 172 | OAuth 2.0 173 | 174 | Content Type 175 | 176 | application/json 177 | 178 | Resource Error Codes 179 | HTTP Code 180 | 181 | Description 182 | 183 | 400 184 | 185 | An error message indicating the validation problem with the request. 186 | 187 | 401 188 | 189 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 190 | 191 | 500 192 | 193 | An error message indicating there was an unexpected server error. 194 | 195 | 403 196 | 197 | An error message indicating the caller is forbidden from accessing this resource. 198 | 199 | 503 200 | 201 | An error message indicating there is a temporary problem responding. 202 | -------------------------------------------------------------------------------- /apidocsarchive/userinfo/userinfo_userprincipals.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/user-principal/apis/get/userprincipals-0 4 | 5 | User Info and Preferences Documentation Get User Principals 6 | GET Get User Principals 7 | User Principal details. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/userprincipals 11 | 12 | Query Parameters 13 | Name Values Description 14 | fields 15 | A comma separated String which allows one to specify additional fields to return. None of these fields are returned by default. Possible values in this String can be: 16 | 17 | streamerSubscriptionKeys 18 | streamerConnectionInfo 19 | preferences 20 | surrogateIds 21 | 22 | Example: 23 | fields=streamerSubscriptionKeys,streamerConnectionInfo 24 | 25 | Header Parameters 26 | Name Values Description 27 | Authorization 28 | Supply an access token to make an authenticated request. The format is Bearer . 29 | 30 | Try it out !! 31 | OAuth 2.0 32 | 33 | Set...SENDRESET 34 | RequestResponsecURL 35 | Make a request and see the response. 36 | 37 | Resource Summary 38 | Security 39 | 40 | OAuth 2.0 41 | 42 | Response Summary 43 | JSON 44 | Schema 45 | //UserPrincipal: 46 | { 47 | "authToken": "string", 48 | "userId": "string", 49 | "userCdDomainId": "string", 50 | "primaryAccountId": "string", 51 | "lastLoginTime": "string", 52 | "tokenExpirationTime": "string", 53 | "loginTime": "string", 54 | "accessLevel": "string", 55 | "stalePassword": false, 56 | "streamerInfo": { 57 | "streamerBinaryUrl": "string", 58 | "streamerSocketUrl": "string", 59 | "token": "string", 60 | "tokenTimestamp": "string", 61 | "userGroup": "string", 62 | "accessLevel": "string", 63 | "acl": "string", 64 | "appId": "string" 65 | }, 66 | "professionalStatus": "'PROFESSIONAL' or 'NON_PROFESSIONAL' or 'UNKNOWN_STATUS'", 67 | "quotes": { 68 | "isNyseDelayed": false, 69 | "isNasdaqDelayed": false, 70 | "isOpraDelayed": false, 71 | "isAmexDelayed": false, 72 | "isCmeDelayed": false, 73 | "isIceDelayed": false, 74 | "isForexDelayed": false 75 | }, 76 | "streamerSubscriptionKeys": { 77 | "keys": [ 78 | { 79 | "key": "string" 80 | } 81 | ] 82 | }, 83 | "accounts": [ 84 | { 85 | "accountId": "string", 86 | "description": "string", 87 | "displayName": "string", 88 | "accountCdDomainId": "string", 89 | "company": "string", 90 | "segment": "string", 91 | "surrogateIds": "object", 92 | "preferences": { 93 | "expressTrading": false, 94 | "directOptionsRouting": false, 95 | "directEquityRouting": false, 96 | "defaultEquityOrderLegInstruction": "'BUY' or 'SELL' or 'BUY_TO_COVER' or 'SELL_SHORT' or 'NONE'", 97 | "defaultEquityOrderType": "'MARKET' or 'LIMIT' or 'STOP' or 'STOP_LIMIT' or 'TRAILING_STOP' or 'MARKET_ON_CLOSE' or 'NONE'", 98 | "defaultEquityOrderPriceLinkType": "'VALUE' or 'PERCENT' or 'NONE'", 99 | "defaultEquityOrderDuration": "'DAY' or 'GOOD_TILL_CANCEL' or 'NONE'", 100 | Resource Error Codes 101 | HTTP Code 102 | 103 | Description 104 | 105 | 400 106 | 107 | An error message indicating invalid userId , password or source provided with the request. 108 | 109 | 401 110 | 111 | An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header. 112 | 113 | 500 114 | 115 | An error message indicating there was an unexpected server error. 116 | 117 | 503 118 | 119 | An error message indicating there is a temporary problem responding. 120 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_createwatchlist.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/post/accounts/%7BaccountId%7D/watchlists-0 4 | 5 | Watchlist Documentation Create Watchlist 6 | POSTCreate Watchlist 7 | Create watchlist for specific account.This method does not verify that the symbol or asset type are valid. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | Value 19 | { 20 | "name": "string", 21 | "watchlistItems": [ 22 | { 23 | "quantity": 0, 24 | "averagePrice": 0, 25 | "commission": 0, 26 | "purchasedDate": "DateParam\"", 27 | "instrument": { 28 | "symbol": "string", 29 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 30 | } 31 | } 32 | ] 33 | } 34 | 35 | Description 36 | The new watchlist object to be created. 37 | 38 | Schema 39 | { 40 | "name": { 41 | "type": "string" 42 | }, 43 | "watchlistItems": { 44 | "type": "array", 45 | "items": { 46 | "type": "object", 47 | "properties": { 48 | "quantity": { 49 | "type": "number", 50 | "format": "double" 51 | }, 52 | "averagePrice": { 53 | "type": "number", 54 | "format": "double", 55 | "minimum": 0 56 | }, 57 | "commission": { 58 | "type": "number", 59 | "format": "double", 60 | "minimum": 0 61 | }, 62 | "purchasedDate": { 63 | "type": "object" 64 | }, 65 | "instrument": { 66 | "type": "object", 67 | "properties": { 68 | "symbol": { 69 | "type": "string" 70 | }, 71 | "assetType": { 72 | "type": "string", 73 | "enum": [ 74 | "EQUITY", 75 | "OPTION", 76 | "MUTUAL_FUND", 77 | "FIXED_INCOME", 78 | "INDEX" 79 | ] 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | OAuth 2.0 89 | 90 | Set...SENDRESET 91 | RequestResponsecURL 92 | Make a request and see the response. 93 | 94 | Resource Summary 95 | Security 96 | 97 | OAuth 2.0 98 | 99 | Content Type 100 | 101 | application/json 102 | 103 | Category 104 | 105 | Watchlist 106 | 107 | Resource Error Codes 108 | HTTP Code 109 | 110 | Description 111 | 112 | 400 113 | 114 | An error message indicating the validation problem with the request. 115 | 116 | 401 117 | 118 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 119 | 120 | 500 121 | 122 | An error message indicating there was an unexpected server error. 123 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_deletewatchlist.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/delete/accounts/%7BaccountId%7D/watchlists/%7BwatchlistId%7D-0 4 | 5 | Watchlist Documentation Delete Watchlist 6 | DELETEDelete Watchlist 7 | Delete watchlist for a specific account. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists/{watchlistId} 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | OAuth 2.0 19 | 20 | Set...SENDRESET 21 | RequestResponsecURL 22 | Make a request and see the response. 23 | 24 | Resource Summary 25 | Security 26 | 27 | OAuth 2.0 28 | 29 | Category 30 | 31 | Watchlist 32 | 33 | Resource Error Codes 34 | HTTP Code 35 | 36 | Description 37 | 38 | 400 39 | 40 | An error message indicating the validation problem with the request. 41 | 42 | 401 43 | 44 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 45 | 46 | 500 47 | 48 | An error message indicating there was an unexpected server error. 49 | 50 | 204 51 | 52 | Watchlist deleted. 53 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_getwatchlist.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/get/accounts/%7BaccountId%7D/watchlists/%7BwatchlistId%7D-0 4 | 5 | Watchlist Documentation Get Watchlist 6 | GETGet Watchlist 7 | Specific watchlist for a specific account. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists/{watchlistId} 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | OAuth 2.0 19 | 20 | Set...SENDRESET 21 | RequestResponsecURL 22 | Make a request and see the response. 23 | 24 | Resource Summary 25 | Security 26 | 27 | OAuth 2.0 28 | 29 | Category 30 | 31 | Watchlist 32 | 33 | Response Summary 34 | JSON 35 | [ 36 | //Watchlist: 37 | { 38 | "name": "string", 39 | "watchlistId": "string", 40 | "accountId": "string", 41 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'", 42 | "watchlistItems": [ 43 | { 44 | "sequenceId": 0, 45 | "quantity": 0, 46 | "averagePrice": 0, 47 | "commission": 0, 48 | "purchasedDate": "DateParam\"", 49 | "instrument": { 50 | "symbol": "string", 51 | "description": "string", 52 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 53 | }, 54 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'" 55 | } 56 | ] 57 | } 58 | ] 59 | 60 | Schema 61 | [ 62 | //Watchlist: 63 | { 64 | "name": { 65 | "type": "string" 66 | }, 67 | "watchlistId": { 68 | "type": "string" 69 | }, 70 | "accountId": { 71 | "type": "string" 72 | }, 73 | "status": { 74 | "type": "string", 75 | "enum": [ 76 | "UNCHANGED", 77 | "CREATED", 78 | "UPDATED", 79 | "DELETED" 80 | ] 81 | }, 82 | "watchlistItems": { 83 | "type": "array", 84 | "items": { 85 | "type": "object", 86 | "properties": { 87 | "sequenceId": { 88 | "type": "integer", 89 | "format": "int32", 90 | "minimum": 0 91 | }, 92 | "quantity": { 93 | "type": "number", 94 | "format": "double" 95 | }, 96 | "averagePrice": { 97 | "type": "number", 98 | "format": "double", 99 | "minimum": 0 100 | }, 101 | "commission": { 102 | "type": "number", 103 | "format": "double", 104 | "minimum": 0 105 | }, 106 | "purchasedDate": { 107 | "type": "object" 108 | }, 109 | "instrument": { 110 | "type": "object", 111 | "properties": { 112 | "symbol": { 113 | "type": "string" 114 | }, 115 | "description": { 116 | "type": "string" 117 | }, 118 | "assetType": { 119 | "type": "string", 120 | "enum": [ 121 | "EQUITY", 122 | "OPTION", 123 | "MUTUAL_FUND", 124 | "FIXED_INCOME", 125 | "INDEX" 126 | ] 127 | } 128 | } 129 | }, 130 | "status": { 131 | "type": "string", 132 | "enum": [ 133 | "UNCHANGED", 134 | "CREATED", 135 | "UPDATED", 136 | "DELETED" 137 | ] 138 | } 139 | } 140 | }, 141 | "required": true 142 | } 143 | } 144 | ] 145 | 146 | Resource Error Codes 147 | HTTP Code 148 | 149 | Description 150 | 151 | 400 152 | 153 | An error message indicating the validation problem with the request. 154 | 155 | 401 156 | 157 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 158 | 159 | 500 160 | 161 | An error message indicating there was an unexpected server error. 162 | 163 | 404 164 | 165 | An error message indicating the account or the watchlist ID does not exist. 166 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_getwatchlistsmultiacct.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/get/accounts/watchlists-0 4 | 5 | Watchlist Documentation Get Watchlists for Multiple Accounts 6 | GETGet Watchlists for Multiple Accounts 7 | All watchlists for all of the user's linked accounts. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/watchlists 11 | 12 | Try it out !! 13 | OAuth 2.0 14 | 15 | Set...SENDRESET 16 | RequestResponsecURL 17 | Make a request and see the response. 18 | 19 | Resource Summary 20 | Security 21 | 22 | OAuth 2.0 23 | 24 | Category 25 | 26 | Watchlist 27 | 28 | Response Summary 29 | JSON 30 | [ 31 | //Watchlist: 32 | { 33 | "name": "string", 34 | "watchlistId": "string", 35 | "accountId": "string", 36 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'", 37 | "watchlistItems": [ 38 | { 39 | "sequenceId": 0, 40 | "quantity": 0, 41 | "averagePrice": 0, 42 | "commission": 0, 43 | "purchasedDate": "DateParam\"", 44 | "instrument": { 45 | "symbol": "string", 46 | "description": "string", 47 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 48 | }, 49 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'" 50 | } 51 | ] 52 | } 53 | ] 54 | 55 | Schema 56 | [ 57 | //Watchlist: 58 | { 59 | "name": { 60 | "type": "string" 61 | }, 62 | "watchlistId": { 63 | "type": "string" 64 | }, 65 | "accountId": { 66 | "type": "string" 67 | }, 68 | "status": { 69 | "type": "string", 70 | "enum": [ 71 | "UNCHANGED", 72 | "CREATED", 73 | "UPDATED", 74 | "DELETED" 75 | ] 76 | }, 77 | "watchlistItems": { 78 | "type": "array", 79 | "items": { 80 | "type": "object", 81 | "properties": { 82 | "sequenceId": { 83 | "type": "integer", 84 | "format": "int32", 85 | "minimum": 0 86 | }, 87 | "quantity": { 88 | "type": "number", 89 | "format": "double" 90 | }, 91 | "averagePrice": { 92 | "type": "number", 93 | "format": "double", 94 | "minimum": 0 95 | }, 96 | "commission": { 97 | "type": "number", 98 | "format": "double", 99 | "minimum": 0 100 | }, 101 | "purchasedDate": { 102 | "type": "object" 103 | }, 104 | "instrument": { 105 | "type": "object", 106 | "properties": { 107 | "symbol": { 108 | "type": "string" 109 | }, 110 | "description": { 111 | "type": "string" 112 | }, 113 | "assetType": { 114 | "type": "string", 115 | "enum": [ 116 | "EQUITY", 117 | "OPTION", 118 | "MUTUAL_FUND", 119 | "FIXED_INCOME", 120 | "INDEX" 121 | ] 122 | } 123 | } 124 | }, 125 | "status": { 126 | "type": "string", 127 | "enum": [ 128 | "UNCHANGED", 129 | "CREATED", 130 | "UPDATED", 131 | "DELETED" 132 | ] 133 | } 134 | } 135 | }, 136 | "required": true 137 | } 138 | } 139 | ] 140 | 141 | Resource Error Codes 142 | HTTP Code 143 | 144 | Description 145 | 146 | 401 147 | 148 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 149 | 150 | 500 151 | 152 | An error message indicating there was an unexpected server error. 153 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_getwatchlistssingleacct.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/get/accounts/%7BaccountId%7D/watchlists-0 4 | 5 | Watchlist Documentation Get Watchlists for Single Account 6 | GETGet Watchlists for Single Account 7 | All watchlists of an account. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | OAuth 2.0 19 | 20 | Set...SENDRESET 21 | RequestResponsecURL 22 | Make a request and see the response. 23 | 24 | Resource Summary 25 | Security 26 | 27 | OAuth 2.0 28 | 29 | Category 30 | 31 | Watchlist 32 | 33 | Response Summary 34 | JSON 35 | [ 36 | //Watchlist: 37 | { 38 | "name": "string", 39 | "watchlistId": "string", 40 | "accountId": "string", 41 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'", 42 | "watchlistItems": [ 43 | { 44 | "sequenceId": 0, 45 | "quantity": 0, 46 | "averagePrice": 0, 47 | "commission": 0, 48 | "purchasedDate": "DateParam\"", 49 | "instrument": { 50 | "symbol": "string", 51 | "description": "string", 52 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 53 | }, 54 | "status": "'UNCHANGED' or 'CREATED' or 'UPDATED' or 'DELETED'" 55 | } 56 | ] 57 | } 58 | ] 59 | 60 | Schema 61 | [ 62 | //Watchlist: 63 | { 64 | "name": { 65 | "type": "string" 66 | }, 67 | "watchlistId": { 68 | "type": "string" 69 | }, 70 | "accountId": { 71 | "type": "string" 72 | }, 73 | "status": { 74 | "type": "string", 75 | "enum": [ 76 | "UNCHANGED", 77 | "CREATED", 78 | "UPDATED", 79 | "DELETED" 80 | ] 81 | }, 82 | "watchlistItems": { 83 | "type": "array", 84 | "items": { 85 | "type": "object", 86 | "properties": { 87 | "sequenceId": { 88 | "type": "integer", 89 | "format": "int32", 90 | "minimum": 0 91 | }, 92 | "quantity": { 93 | "type": "number", 94 | "format": "double" 95 | }, 96 | "averagePrice": { 97 | "type": "number", 98 | "format": "double", 99 | "minimum": 0 100 | }, 101 | "commission": { 102 | "type": "number", 103 | "format": "double", 104 | "minimum": 0 105 | }, 106 | "purchasedDate": { 107 | "type": "object" 108 | }, 109 | "instrument": { 110 | "type": "object", 111 | "properties": { 112 | "symbol": { 113 | "type": "string" 114 | }, 115 | "description": { 116 | "type": "string" 117 | }, 118 | "assetType": { 119 | "type": "string", 120 | "enum": [ 121 | "EQUITY", 122 | "OPTION", 123 | "MUTUAL_FUND", 124 | "FIXED_INCOME", 125 | "INDEX" 126 | ] 127 | } 128 | } 129 | }, 130 | "status": { 131 | "type": "string", 132 | "enum": [ 133 | "UNCHANGED", 134 | "CREATED", 135 | "UPDATED", 136 | "DELETED" 137 | ] 138 | } 139 | } 140 | }, 141 | "required": true 142 | } 143 | } 144 | ] 145 | 146 | Resource Error Codes 147 | HTTP Code 148 | 149 | Description 150 | 151 | 401 152 | 153 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 154 | 155 | 500 156 | 157 | An error message indicating there was an unexpected server error. 158 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_replacewatchlist.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/put/accounts/%7BaccountId%7D/watchlists/%7BwatchlistId%7D-0 4 | 5 | Watchlist Documentation Replace Watchlist 6 | PUTReplace Watchlist 7 | Replace watchlist for a specific account. 8 | 9 | This method does not verify that the symbol or asset type are valid. 10 | 11 | Resource URL 12 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists/{watchlistId} 13 | 14 | Header Parameters 15 | Name Values Description 16 | Authorization 17 | Supply an access token to make an authenticated request. The format is Bearer . 18 | 19 | Try it out !! 20 | Value 21 | { 22 | "name": "string", 23 | "watchlistId": "string", 24 | "watchlistItems": [ 25 | { 26 | "quantity": 0, 27 | "averagePrice": 0, 28 | "commission": 0, 29 | "purchasedDate": "DateParam\"", 30 | "instrument": { 31 | "symbol": "string", 32 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 33 | }, 34 | "sequenceId": 0 35 | } 36 | ] 37 | } 38 | 39 | Description 40 | The new watchlist object to be created. 41 | 42 | Schema 43 | { 44 | "name": { 45 | "type": "string" 46 | }, 47 | "watchlistItems": { 48 | "type": "array", 49 | "items": { 50 | "type": "object", 51 | "properties": { 52 | "quantity": { 53 | "type": "number", 54 | "format": "double" 55 | }, 56 | "averagePrice": { 57 | "type": "number", 58 | "format": "double", 59 | "minimum": 0 60 | }, 61 | "commission": { 62 | "type": "number", 63 | "format": "double", 64 | "minimum": 0 65 | }, 66 | "purchasedDate": { 67 | "type": "object" 68 | }, 69 | "instrument": { 70 | "type": "object", 71 | "properties": { 72 | "symbol": { 73 | "type": "string" 74 | }, 75 | "assetType": { 76 | "type": "string", 77 | "enum": [ 78 | "EQUITY", 79 | "OPTION", 80 | "MUTUAL_FUND", 81 | "FIXED_INCOME", 82 | "INDEX" 83 | ] 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | OAuth 2.0 93 | 94 | Set...SENDRESET 95 | RequestResponsecURL 96 | Make a request and see the response. 97 | 98 | Resource Summary 99 | Security 100 | 101 | OAuth 2.0 102 | 103 | Content Type 104 | 105 | application/json 106 | 107 | Category 108 | 109 | Watchlist 110 | 111 | Resource Error Codes 112 | HTTP Code 113 | 114 | Description 115 | 116 | 400 117 | 118 | An error message indicating the validation problem with the request. 119 | 120 | 401 121 | 122 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 123 | 124 | 500 125 | 126 | An error message indicating there was an unexpected server error. 127 | 128 | 204 129 | 130 | Watchlist updated. 131 | -------------------------------------------------------------------------------- /apidocsarchive/watchlist/watchlist_updatewatchlist.txt: -------------------------------------------------------------------------------- 1 | Last checked Sept 10 2020 2 | 3 | https://developer.tdameritrade.com/watchlist/apis/put/accounts/%7BaccountId%7D/watchlists/%7BwatchlistId%7D-0 4 | 5 | Watchlist Documentation Update Watchlist 6 | PATCHUpdate Watchlist 7 | Partially update watchlist for a specific account: change watchlist name, add to the beginning/end of a watchlist, update or delete items in a watchlist. This method does not verify that the symbol or asset type are valid. 8 | 9 | Resource URL 10 | https://api.tdameritrade.com/v1/accounts/{accountId}/watchlists/{watchlistId} 11 | 12 | Header Parameters 13 | Name Values Description 14 | Authorization 15 | Supply an access token to make an authenticated request. The format is Bearer . 16 | 17 | Try it out !! 18 | Value 19 | { 20 | "name": "string", 21 | "watchlistId": "string", 22 | "watchlistItems": [ 23 | { 24 | "quantity": 0, 25 | "averagePrice": 0, 26 | "commission": 0, 27 | "purchasedDate": "DateParam\"", 28 | "instrument": { 29 | "symbol": "string", 30 | "assetType": "'EQUITY' or 'OPTION' or 'MUTUAL_FUND' or 'FIXED_INCOME' or 'INDEX'" 31 | }, 32 | "sequenceId": 0 33 | } 34 | ] 35 | } 36 | 37 | Description 38 | The new version of the watchlist. 39 | 40 | Schema 41 | { 42 | "name": { 43 | "type": "string" 44 | }, 45 | "watchlistId": { 46 | "type": "string" 47 | }, 48 | "watchlistItems": { 49 | "type": "array", 50 | "items": { 51 | "type": "object", 52 | "properties": { 53 | "quantity": { 54 | "type": "number", 55 | "format": "double" 56 | }, 57 | "averagePrice": { 58 | "type": "number", 59 | "format": "double", 60 | "minimum": 0 61 | }, 62 | "commission": { 63 | "type": "number", 64 | "format": "double", 65 | "minimum": 0 66 | }, 67 | "purchasedDate": { 68 | "type": "object" 69 | }, 70 | "instrument": { 71 | "type": "object", 72 | "properties": { 73 | "symbol": { 74 | "type": "string" 75 | }, 76 | "assetType": { 77 | "type": "string", 78 | "enum": [ 79 | "EQUITY", 80 | "OPTION", 81 | "MUTUAL_FUND", 82 | "FIXED_INCOME", 83 | "INDEX" 84 | ] 85 | } 86 | } 87 | }, 88 | "sequenceId": { 89 | "type": "integer", 90 | "format": "int32", 91 | "minimum": 0 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | OAuth 2.0 99 | 100 | Set...SENDRESET 101 | RequestResponsecURL 102 | Make a request and see the response. 103 | 104 | Resource Summary 105 | Security 106 | 107 | OAuth 2.0 108 | 109 | Content Type 110 | 111 | application/json 112 | 113 | Category 114 | 115 | Watchlist 116 | 117 | Resource Error Codes 118 | HTTP Code 119 | 120 | Description 121 | 122 | 400 123 | 124 | An error message indicating the validation problem with the request. 125 | 126 | 401 127 | 128 | An error message indicating the caller must pass a valid Authorization in the HTTP authorization request header. 129 | 130 | 500 131 | 132 | An error message indicating there was an unexpected server error. 133 | 134 | 204 135 | 136 | Watchlist updated. 137 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | // module.exports = { 2 | // presets: [["@babel/preset-env", {targets: {node: "current"}}]], 3 | // }; 4 | module.exports = api => { 5 | const isTest = api.env("test"); 6 | // You can use isTest to determine what presets and plugins to use. 7 | 8 | return { 9 | presets: [["@babel/preset-env", {targets: {node: "current"}}], 10 | "@babel/preset-typescript", 11 | ], 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /config/tdaclientauth.json: -------------------------------------------------------------------------------- 1 | { 2 | "refresh_token":"REPLACEME", 3 | "client_id":"EXAMPLE@AMER.OAUTHAP" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tda-api-client", 3 | "version": "2.1.3", 4 | "description": "A client library for the TD Ameritrade API", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "prepublish": "tsc", 8 | "scripts": { 9 | "test": "jest --runInBand --bail --forceExit", 10 | "lint": "eslint src --ext .ts,.js", 11 | "lint:fix": "eslint --fix src --ext .ts,.js", 12 | "build:npm": "tsc && cp *.md dist/ && cp -r config/ dist/ && cat package.json | jq 'del(.devDependencies)|del(.prepublish)|del(.scripts)|del(.files)|setpath([\"main\"]; \"index.js\")|setpath([\"types\"]; \"index.d.ts\")' > dist/package.json" 13 | }, 14 | "files": [ 15 | "dist/*", 16 | "cli_index.js" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/Sainglend/tda-api-client.git" 21 | }, 22 | "keywords": [ 23 | "tda", 24 | "td", 25 | "ameritrade", 26 | "api", 27 | "stonks", 28 | "client" 29 | ], 30 | "author": "Aaron Satterlee ", 31 | "license": "GPL-3.0-or-later", 32 | "bugs": { 33 | "url": "https://github.com/Sainglend/tda-api-client/issues" 34 | }, 35 | "homepage": "https://github.com/Sainglend/tda-api-client#readme", 36 | "dependencies": { 37 | "axios": "^0.21.1", 38 | "moment": "^2.29.1", 39 | "qs": "^6.10.2", 40 | "ws": "^7.4.3", 41 | "xml-js": "^1.6.11", 42 | "yargs": "^17.3.1" 43 | }, 44 | "devDependencies": { 45 | "@babel/core": "^7.16.5", 46 | "@babel/preset-env": "^7.16.5", 47 | "@babel/preset-typescript": "^7.16.5", 48 | "@types/axios": "^0.14.0", 49 | "@types/jest": "^27.0.3", 50 | "@types/node": "^14.14.32", 51 | "@types/qs": "^6.9.7", 52 | "@types/ws": "^8.2.0", 53 | "@types/yargs": "^16.0.4", 54 | "@typescript-eslint/eslint-plugin": "^4.15.2", 55 | "@typescript-eslint/parser": "^4.15.2", 56 | "babel-jest": "^27.4.5", 57 | "eslint": "^7.20.0", 58 | "jest": "^27.4.5", 59 | "ts-node": "^10.4.0", 60 | "typescript": "^4.2.2" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sampledata/instruments-getFundamentals.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/instruments?apikey=insertkeyhere&symbol=TSLA&projection=fundamental" 2 | 3 | REQUEST 4 | 5 | GET /v1/instruments?apikey=insertkeyhere&symbol=TSLA&projection=fundamental HTTP/1.1 6 | 7 | Accept: 8 | */* 9 | Accept-Encoding: 10 | gzip 11 | Accept-Language: 12 | en-US 13 | Authorization: 14 | Host: 15 | api.tdameritrade.com 16 | NS-Proxy-Client-IP: 17 | 24.24.24.24 18 | Sec-Fetch-Dest: 19 | empty 20 | Sec-Fetch-Mode: 21 | cors 22 | Sec-Fetch-Site: 23 | same-site 24 | User-Agent: 25 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 26 | X-Forwarded-For: 27 | 10.152.4.23 28 | X-Forwarded-Port: 29 | 59002 30 | X-Forwarded-Proto: 31 | http 32 | 33 | 34 | RESPONSE 35 | 36 | HTTP/1.1 200 OK 37 | 38 | Access-Control-Allow-Headers: 39 | origin 40 | Access-Control-Allow-Methods: 41 | GET 42 | Access-Control-Allow-Origin: 43 | https://developer.tdameritrade.com 44 | Access-Control-Max-Age: 45 | 3628800 46 | Cache-Control: 47 | no-cache 48 | Connection: 49 | keep-alive 50 | Content-Length: 51 | 1237 52 | Content-Security-Policy: 53 | frame-ancestors 'self' 54 | Content-Type: 55 | application/json;charset=UTF-8 56 | Date: 57 | Tue, 07 Dec 2021 08:02:34 GMT 58 | Strict-Transport-Security: 59 | max-age=31536000; includeSubDomains 60 | X-Application-Context: 61 | application:8080 62 | X-Content-Type-Options: 63 | nosniff 64 | X-Frame-Options: 65 | SAMEORIGIN 66 | X-Xss-Protection: 67 | 1; mode=block 68 | 69 | { 70 | "TSLA": { 71 | "fundamental": { 72 | "symbol": "TSLA", 73 | "high52": 1243.49, 74 | "low52": 539.49, 75 | "dividendAmount": 0, 76 | "dividendYield": 0, 77 | "dividendDate": " ", 78 | "peRatio": 329.3561, 79 | "pegRatio": 0.657245, 80 | "pbRatio": 37.66791, 81 | "prRatio": 21.75757, 82 | "pcfRatio": 162.3604, 83 | "grossMarginTTM": 23.10664, 84 | "grossMarginMRQ": 26.60464, 85 | "netProfitMarginTTM": 7.67802, 86 | "netProfitMarginMRQ": 12.05932, 87 | "operatingMarginTTM": 9.57351, 88 | "operatingMarginMRQ": 14.56713, 89 | "returnOnEquity": 16.09878, 90 | "returnOnAssets": 6.94905, 91 | "returnOnInvestment": 10.38665, 92 | "quickRatio": 1.09706, 93 | "currentRatio": 1.38508, 94 | "interestCoverage": 16.57258, 95 | "totalDebtToCapital": 22.24951, 96 | "ltDebtToEquity": 23.79773, 97 | "totalDebtToEquity": 30.14083, 98 | "epsTTM": 3.08168, 99 | "epsChangePercentTTM": 501.1158, 100 | "epsChangeYear": 430.6936, 101 | "epsChange": 0, 102 | "revChangeYear": 0, 103 | "revChangeTTM": 66.26917, 104 | "revChangeIn": 15.04432, 105 | "sharesOutstanding": 1004264852, 106 | "marketCapFloat": 811.8643, 107 | "marketCap": 1019299, 108 | "bookValuePerShare": 69.61395, 109 | "shortIntToFloat": 0, 110 | "shortIntDayToCover": 0, 111 | "divGrowthRate3Year": 0, 112 | "dividendPayAmount": 0, 113 | "dividendPayDate": " ", 114 | "beta": 2.05101, 115 | "vol1DayAvg": 24914380, 116 | "vol10DayAvg": 24976442, 117 | "vol3MonthAvg": 534816470 118 | }, 119 | "cusip": "88160R101", 120 | "symbol": "TSLA", 121 | "description": "Tesla, Inc. - Common Stock", 122 | "exchange": "NASDAQ", 123 | "assetType": "EQUITY" 124 | } 125 | } -------------------------------------------------------------------------------- /sampledata/instruments-getInstrument.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/instruments/Q8881G103?apikey=insertkeyhere" 2 | 3 | REQUEST 4 | 5 | GET /v1/instruments/Q8881G103?apikey=insertkeyhere HTTP/1.1 6 | 7 | Accept: 8 | */* 9 | Accept-Encoding: 10 | gzip 11 | Accept-Language: 12 | en-US 13 | Authorization: 14 | Host: 15 | api.tdameritrade.com 16 | NS-Proxy-Client-IP: 17 | 24.24.24.24 18 | Sec-Fetch-Dest: 19 | empty 20 | Sec-Fetch-Mode: 21 | cors 22 | Sec-Fetch-Site: 23 | same-site 24 | User-Agent: 25 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 26 | X-Forwarded-For: 27 | 10.152.4.23 28 | X-Forwarded-Port: 29 | 59002 30 | X-Forwarded-Proto: 31 | http 32 | 33 | 34 | RESPONSE 35 | 36 | HTTP/1.1 200 OK 37 | 38 | Access-Control-Allow-Headers: 39 | origin 40 | Access-Control-Allow-Methods: 41 | GET 42 | Access-Control-Allow-Origin: 43 | https://developer.tdameritrade.com 44 | Access-Control-Max-Age: 45 | 3628800 46 | Cache-Control: 47 | no-cache 48 | Connection: 49 | keep-alive 50 | Content-Length: 51 | 146 52 | Content-Security-Policy: 53 | frame-ancestors 'self' 54 | Content-Type: 55 | application/json;charset=UTF-8 56 | Date: 57 | Tue, 07 Dec 2021 08:38:09 GMT 58 | Strict-Transport-Security: 59 | max-age=31536000; includeSubDomains 60 | X-Application-Context: 61 | application:8080 62 | X-Content-Type-Options: 63 | nosniff 64 | X-Frame-Options: 65 | SAMEORIGIN 66 | X-Xss-Protection: 67 | 1; mode=block 68 | 69 | [ 70 | { 71 | "cusip": "Q8881G103", 72 | "symbol": "TSLLF", 73 | "description": "Tassal Group Ltd Ordinary Shares (Australia)", 74 | "exchange": "Pink Sheet", 75 | "assetType": "EQUITY" 76 | } 77 | ] -------------------------------------------------------------------------------- /sampledata/instruments-searchInstruments.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/instruments?apikey=insertkeyhere&symbol=TSL.*&projection=symbol-regex" 2 | 3 | REQUEST 4 | 5 | GET /v1/instruments?apikey=insertkeyhere&symbol=TSL.*&projection=symbol-regex HTTP/1.1 6 | 7 | Accept: 8 | */* 9 | Accept-Encoding: 10 | gzip 11 | Accept-Language: 12 | en-US 13 | Authorization: 14 | Host: 15 | api.tdameritrade.com 16 | NS-Proxy-Client-IP: 17 | 24.24.24.24 18 | Sec-Fetch-Dest: 19 | empty 20 | Sec-Fetch-Mode: 21 | cors 22 | Sec-Fetch-Site: 23 | same-site 24 | User-Agent: 25 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 26 | X-Forwarded-For: 27 | 10.152.4.23 28 | X-Forwarded-Port: 29 | 59002 30 | X-Forwarded-Proto: 31 | http 32 | 33 | 34 | RESPONSE 35 | 36 | HTTP/1.1 200 OK 37 | 38 | Access-Control-Allow-Headers: 39 | origin 40 | Access-Control-Allow-Methods: 41 | GET 42 | Access-Control-Allow-Origin: 43 | https://developer.tdameritrade.com 44 | Access-Control-Max-Age: 45 | 3628800 46 | Cache-Control: 47 | no-cache 48 | Connection: 49 | keep-alive 50 | Content-Length: 51 | 1067 52 | Content-Security-Policy: 53 | frame-ancestors 'self' 54 | Content-Type: 55 | application/json;charset=UTF-8 56 | Date: 57 | Tue, 07 Dec 2021 07:59:03 GMT 58 | Strict-Transport-Security: 59 | max-age=31536000; includeSubDomains 60 | X-Application-Context: 61 | application:8080 62 | X-Content-Type-Options: 63 | nosniff 64 | X-Frame-Options: 65 | SAMEORIGIN 66 | X-Xss-Protection: 67 | 1; mode=block 68 | 69 | { 70 | "TSLLF": { 71 | "cusip": "Q8881G103", 72 | "symbol": "TSLLF", 73 | "description": "Tassal Group Ltd Ordinary Shares (Australia)", 74 | "exchange": "Pink Sheet", 75 | "assetType": "EQUITY" 76 | }, 77 | "TSLTF": { 78 | "cusip": "89346D727", 79 | "symbol": "TSLTF", 80 | "description": "Transalta Corp 1st Pfd Ser E (Canada)", 81 | "exchange": "Pink Sheet", 82 | "assetType": "EQUITY" 83 | }, 84 | "TSLRF": { 85 | "cusip": "Y85778101", 86 | "symbol": "TSLRF", 87 | "description": "TESCO LOTUS RETAIL GROWTH FREEHOLD & LEASEHOLD PPTY FD Unit", 88 | "exchange": "Pink Sheet", 89 | "assetType": "EQUITY" 90 | }, 91 | "TSLMF": { 92 | "cusip": "Q9030P143", 93 | "symbol": "TSLMF", 94 | "description": "Thinksmart Ltd, West Perth Ordinary Shares (Australia)", 95 | "exchange": "Pink Sheet", 96 | "assetType": "EQUITY" 97 | }, 98 | "TSLVF": { 99 | "cusip": "88651M108", 100 | "symbol": "TSLVF", 101 | "description": "Tier One Silver Inc Common Shares (Canada)", 102 | "exchange": "Pink Sheet", 103 | "assetType": "EQUITY" 104 | }, 105 | "TSLA": { 106 | "cusip": "88160R101", 107 | "symbol": "TSLA", 108 | "description": "Tesla, Inc. - Common Stock", 109 | "exchange": "NASDAQ", 110 | "assetType": "EQUITY" 111 | }, 112 | "TSLX": { 113 | "cusip": "83012A109", 114 | "symbol": "TSLX", 115 | "description": "Sixth Street Specialty Lending, Inc. Common Stock", 116 | "exchange": "NYSE", 117 | "assetType": "EQUITY" 118 | } 119 | } -------------------------------------------------------------------------------- /sampledata/marketdata-getMultipleMarketHours.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/marketdata/hours?apikey=insertkeyhere&markets=EQUITY%2COPTION&date=2022-02-23" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/marketdata/hours?apikey=insertkeyhere&markets=EQUITY%2COPTION&date=2022-02-23 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Host: 16 | api.tdameritrade.com 17 | NS-Proxy-Client-IP: 18 | 24.24.24.24 19 | Sec-Fetch-Dest: 20 | empty 21 | Sec-Fetch-Mode: 22 | cors 23 | Sec-Fetch-Site: 24 | same-site 25 | User-Agent: 26 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 27 | X-Forwarded-For: 28 | 10.152.4.23 29 | X-Forwarded-Port: 30 | 59002 31 | X-Forwarded-Proto: 32 | http 33 | 34 | 35 | RESPONSE 36 | 37 | HTTP/1.1 200 OK 38 | 39 | Access-Control-Allow-Headers: 40 | origin 41 | Access-Control-Allow-Methods: 42 | GET 43 | Access-Control-Allow-Origin: 44 | https://developer.tdameritrade.com 45 | Access-Control-Max-Age: 46 | 3628800 47 | Cache-Control: 48 | no-cache 49 | Connection: 50 | keep-alive 51 | Content-Security-Policy: 52 | frame-ancestors 'self' 53 | Content-Type: 54 | application/json;charset=UTF-8 55 | Date: 56 | Wed, 08 Dec 2021 06:20:12 GMT 57 | Strict-Transport-Security: 58 | max-age=31536000; includeSubDomains 59 | Transfer-Encoding: 60 | chunked 61 | X-Content-Type-Options: 62 | nosniff 63 | X-Frame-Options: 64 | SAMEORIGIN 65 | X-Vcap-Request-Id: 66 | 6bdf0ce6-9a18-4acd-7e87-a0a6a63bc771 67 | X-Xss-Protection: 68 | 1; mode=block 69 | 70 | { 71 | "equity": { 72 | "EQ": { 73 | "date": "2022-02-23", 74 | "marketType": "EQUITY", 75 | "exchange": "NULL", 76 | "category": "NULL", 77 | "product": "EQ", 78 | "productName": "equity", 79 | "isOpen": true, 80 | "sessionHours": { 81 | "preMarket": [ 82 | { 83 | "start": "2022-02-23T07:00:00-05:00", 84 | "end": "2022-02-23T09:30:00-05:00" 85 | } 86 | ], 87 | "regularMarket": [ 88 | { 89 | "start": "2022-02-23T09:30:00-05:00", 90 | "end": "2022-02-23T16:00:00-05:00" 91 | } 92 | ], 93 | "postMarket": [ 94 | { 95 | "start": "2022-02-23T16:00:00-05:00", 96 | "end": "2022-02-23T20:00:00-05:00" 97 | } 98 | ] 99 | } 100 | } 101 | }, 102 | "option": { 103 | "EQO": { 104 | "date": "2022-02-23", 105 | "marketType": "OPTION", 106 | "exchange": "NULL", 107 | "category": "NULL", 108 | "product": "EQO", 109 | "productName": "equity option", 110 | "isOpen": true, 111 | "sessionHours": { 112 | "regularMarket": [ 113 | { 114 | "start": "2022-02-23T09:30:00-05:00", 115 | "end": "2022-02-23T16:00:00-05:00" 116 | } 117 | ] 118 | } 119 | }, 120 | "IND": { 121 | "date": "2022-02-23", 122 | "marketType": "OPTION", 123 | "exchange": "NULL", 124 | "category": "NULL", 125 | "product": "IND", 126 | "productName": "index option", 127 | "isOpen": true, 128 | "sessionHours": { 129 | "regularMarket": [ 130 | { 131 | "start": "2022-02-23T09:30:00-05:00", 132 | "end": "2022-02-23T16:15:00-05:00" 133 | } 134 | ] 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /sampledata/marketdata-getSingleMarketHours.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/marketdata/EQUITY/hours?apikey=insertkeyhere&date=2022-02-23" 2 | 3 | REQUEST 4 | 5 | GET /v1/marketdata/EQUITY/hours?apikey=insertkeyhere&date=2022-02-23 HTTP/1.1 6 | 7 | Accept: 8 | */* 9 | Accept-Encoding: 10 | gzip 11 | Accept-Language: 12 | en-US 13 | Authorization: 14 | Host: 15 | api.tdameritrade.com 16 | NS-Proxy-Client-IP: 17 | 24.24.24.24 18 | Sec-Fetch-Dest: 19 | empty 20 | Sec-Fetch-Mode: 21 | cors 22 | Sec-Fetch-Site: 23 | same-site 24 | User-Agent: 25 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 26 | X-Forwarded-For: 27 | 10.152.4.23 28 | X-Forwarded-Port: 29 | 59002 30 | X-Forwarded-Proto: 31 | http 32 | 33 | RESPONSE 34 | 35 | HTTP/1.1 200 OK 36 | 37 | Access-Control-Allow-Headers: 38 | origin 39 | Access-Control-Allow-Methods: 40 | GET 41 | Access-Control-Allow-Origin: 42 | https://developer.tdameritrade.com 43 | Access-Control-Max-Age: 44 | 3628800 45 | Cache-Control: 46 | no-cache 47 | Connection: 48 | keep-alive 49 | Content-Security-Policy: 50 | frame-ancestors 'self' 51 | Content-Type: 52 | application/json;charset=UTF-8 53 | Date: 54 | Wed, 08 Dec 2021 05:43:47 GMT 55 | Strict-Transport-Security: 56 | max-age=31536000; includeSubDomains 57 | Transfer-Encoding: 58 | chunked 59 | X-Content-Type-Options: 60 | nosniff 61 | X-Frame-Options: 62 | SAMEORIGIN 63 | X-Vcap-Request-Id: 64 | 12d4dc1c-4ae1-4397-48c9-9cfbc9e3a672 65 | X-Xss-Protection: 66 | 1; mode=block 67 | 68 | { 69 | "equity": { 70 | "EQ": { 71 | "date": "2022-02-23", 72 | "marketType": "EQUITY", 73 | "exchange": "NULL", 74 | "category": "NULL", 75 | "product": "EQ", 76 | "productName": "equity", 77 | "isOpen": true, 78 | "sessionHours": { 79 | "preMarket": [ 80 | { 81 | "start": "2022-02-23T07:00:00-05:00", 82 | "end": "2022-02-23T09:30:00-05:00" 83 | } 84 | ], 85 | "regularMarket": [ 86 | { 87 | "start": "2022-02-23T09:30:00-05:00", 88 | "end": "2022-02-23T16:00:00-05:00" 89 | } 90 | ], 91 | "postMarket": [ 92 | { 93 | "start": "2022-02-23T16:00:00-05:00", 94 | "end": "2022-02-23T20:00:00-05:00" 95 | } 96 | ] 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /sampledata/movers-getmovers.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " "https://api.tdameritrade.com/v1/marketdata/$SPX.X/movers?apikey=insesrtkeyhere&direction=up&change=percent" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/marketdata/$SPX.X/movers?apikey=insertkeyhere&direction=up&change=percent HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Host: 16 | api.tdameritrade.com 17 | NS-Proxy-Client-IP: 18 | 24.24.24.24 19 | Sec-Fetch-Dest: 20 | empty 21 | Sec-Fetch-Mode: 22 | cors 23 | Sec-Fetch-Site: 24 | same-site 25 | User-Agent: 26 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 27 | X-Forwarded-For: 28 | 10.152.4.23 29 | X-Forwarded-Port: 30 | 59002 31 | X-Forwarded-Proto: 32 | http 33 | 34 | 35 | REPONSE 36 | 37 | HTTP/1.1 200 38 | 39 | Access-Control-Allow-Headers: 40 | origin 41 | Access-Control-Allow-Methods: 42 | GET 43 | Access-Control-Allow-Origin: 44 | https://developer.tdameritrade.com 45 | Access-Control-Max-Age: 46 | 3628800 47 | Cache-Control: 48 | no-cache 49 | Connection: 50 | keep-alive 51 | Content-Encoding: 52 | gzip 53 | Content-Security-Policy: 54 | frame-ancestors 'self' 55 | Content-Type: 56 | application/json 57 | Date: 58 | Wed, 08 Dec 2021 06:55:37 GMT 59 | Strict-Transport-Security: 60 | max-age=31536000; includeSubDomains 61 | Transfer-Encoding: 62 | chunked 63 | vary: 64 | accept-encoding 65 | X-Content-Type-Options: 66 | nosniff 67 | X-Frame-Options: 68 | SAMEORIGIN 69 | X-Xss-Protection: 70 | 1; mode=block 71 | 72 | [ 73 | { 74 | "change": 0.08628954937679766, 75 | "description": "Fortinet, Inc. - Common Stock", 76 | "direction": "up", 77 | "last": 317.24, 78 | "symbol": "FTNT", 79 | "totalVolume": 1290900 80 | }, 81 | { 82 | "change": 0.07956853214368938, 83 | "description": "NVIDIA Corporation - Common Stock", 84 | "direction": "up", 85 | "last": 324.27, 86 | "symbol": "NVDA", 87 | "totalVolume": 59310100 88 | }, 89 | { 90 | "change": 0.07598858143834954, 91 | "description": "ServiceNow, Inc. Common Stock", 92 | "direction": "up", 93 | "last": 663.39, 94 | "symbol": "NOW", 95 | "totalVolume": 2585898 96 | }, 97 | { 98 | "change": 0.06800332624965351, 99 | "description": "Diamondback Energy, Inc. - Commmon Stock", 100 | "direction": "up", 101 | "last": 115.59, 102 | "symbol": "FANG", 103 | "totalVolume": 2954028 104 | }, 105 | { 106 | "change": 0.06518637417513824, 107 | "description": "NXP Semiconductors N.V. - Common Stock", 108 | "direction": "up", 109 | "last": 238.9, 110 | "symbol": "NXPI", 111 | "totalVolume": 2934542 112 | }, 113 | { 114 | "change": 0.06515580736543905, 115 | "description": "Devon Energy Corporation Common Stock", 116 | "direction": "up", 117 | "last": 45.12, 118 | "symbol": "DVN", 119 | "totalVolume": 16684652 120 | }, 121 | { 122 | "change": 0.06477508914440445, 123 | "description": "DexCom, Inc. - Common Stock", 124 | "direction": "up", 125 | "last": 558.4, 126 | "symbol": "DXCM", 127 | "totalVolume": 1166038 128 | }, 129 | { 130 | "change": 0.06452707287284565, 131 | "description": "Applied Materials, Inc. - Common Stock", 132 | "direction": "up", 133 | "last": 156.89, 134 | "symbol": "AMAT", 135 | "totalVolume": 10515491 136 | }, 137 | { 138 | "change": 0.06414653450420246, 139 | "description": "Moderna, Inc. - Common Stock", 140 | "direction": "up", 141 | "last": 282.35, 142 | "symbol": "MRNA", 143 | "totalVolume": 10804291 144 | }, 145 | { 146 | "change": 0.058844550327575906, 147 | "description": "Microchip Technology Incorporated - Common Stock", 148 | "direction": "up", 149 | "last": 88.89, 150 | "symbol": "MCHP", 151 | "totalVolume": 4046907 152 | } 153 | ] 154 | -------------------------------------------------------------------------------- /sampledata/orders-getOrder.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/accounts/00123456789/orders/54321" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/accounts/000123456789/orders/54321 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Connection: 51 | keep-alive 52 | Content-Length: 53 | 740 54 | Content-Security-Policy: 55 | frame-ancestors 'self' 56 | Content-Type: 57 | application/json 58 | Date: 59 | Fri, 10 Dec 2021 05:17:21 GMT 60 | Expires: 61 | 0 62 | Pragma: 63 | no-cache 64 | Set-Cookie: 65 | ADRUM_BTa=R:35|g:b050e3c9-250d-470b-8507-d26348988e81; Max-Age=30; Expires=Fri 66 | Strict-Transport-Security: 67 | max-age=31536000; includeSubDomains 68 | Vary: 69 | origin 70 | X-API-Version: 71 | 1.13.12 72 | X-Content-Type-Options: 73 | nosniff 74 | X-Frame-Options: 75 | DENY 76 | X-XSS-Protection: 77 | 1; mode=block 78 | 79 | { 80 | "session": "NORMAL", 81 | "duration": "DAY", 82 | "orderType": "MARKET", 83 | "complexOrderStrategyType": "NONE", 84 | "quantity": 15, 85 | "filledQuantity": 0, 86 | "remainingQuantity": 15, 87 | "requestedDestination": "AUTO", 88 | "destinationLinkName": "AutoRoute", 89 | "orderLegCollection": [ 90 | { 91 | "orderLegType": "EQUITY", 92 | "legId": 1, 93 | "instrument": { 94 | "assetType": "EQUITY", 95 | "cusip": "345370860", 96 | "symbol": "F" 97 | }, 98 | "instruction": "BUY", 99 | "positionEffect": "OPENING", 100 | "quantity": 15 101 | } 102 | ], 103 | "orderStrategyType": "SINGLE", 104 | "orderId": 54321, 105 | "cancelable": true, 106 | "editable": false, 107 | "status": "QUEUED", 108 | "enteredTime": "2021-12-10T04:45:05+0000", 109 | "accountId": 000123456789 110 | } 111 | -------------------------------------------------------------------------------- /sampledata/orders-placeorder.txt: -------------------------------------------------------------------------------- 1 | curl -X POST --header "Authorization: Bearer INSERT_ACCESS_TOKEN" --header "Content-Type: application/json" -d "{ 2 | \"orderType\": \"MARKET\", 3 | \"session\": \"NORMAL\", 4 | \"duration\": \"DAY\", 5 | \"orderStrategyType\": \"SINGLE\", 6 | \"orderLegCollection\": [ 7 | { 8 | \"instruction\": \"Buy\", 9 | \"quantity\": 15, 10 | \"instrument\": { 11 | \"symbol\": \"F\", 12 | \"assetType\": \"EQUITY\" 13 | } 14 | } 15 | ] 16 | }" "https://api.tdameritrade.com/v1/accounts/000123456789/orders" 17 | 18 | 19 | REQUEST 20 | 21 | POST /v1/accounts/00123456789/orders HTTP/1.1 22 | 23 | Accept: 24 | */* 25 | Accept-Encoding: 26 | gzip 27 | Accept-Language: 28 | en-US 29 | Authorization: 30 | Bearer INSERT_ACCESS_TOKEN 31 | Content-Length: 32 | 282 33 | Content-Type: 34 | application/json 35 | Host: 36 | api.tdameritrade.com 37 | NS-Proxy-Client-IP: 38 | 24.24.24.24 39 | Sec-Fetch-Dest: 40 | empty 41 | Sec-Fetch-Mode: 42 | cors 43 | Sec-Fetch-Site: 44 | same-site 45 | User-Agent: 46 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 47 | X-Forwarded-For: 48 | 10.152.4.23 49 | X-Forwarded-Port: 50 | 59002 51 | X-Forwarded-Proto: 52 | http 53 | 54 | { 55 | "orderType": "MARKET", 56 | "session": "NORMAL", 57 | "duration": "DAY", 58 | "orderStrategyType": "SINGLE", 59 | "orderLegCollection": [ 60 | { 61 | "instruction": "Buy", 62 | "quantity": 15, 63 | "instrument": { 64 | "symbol": "F", 65 | "assetType": "EQUITY" 66 | } 67 | } 68 | ] 69 | } 70 | 71 | 72 | RESPONSE 73 | 74 | HTTP/1.1 201 75 | 76 | Access-Control-Allow-Headers: 77 | origin 78 | Access-Control-Allow-Methods: 79 | GET 80 | Access-Control-Allow-Origin: 81 | https://developer.tdameritrade.com 82 | Access-Control-Max-Age: 83 | 3628800 84 | Cache-Control: 85 | no-cache 86 | Connection: 87 | keep-alive 88 | Content-Length: 89 | 0 90 | Content-Security-Policy: 91 | frame-ancestors 'self' 92 | Date: 93 | Fri, 10 Dec 2021 04:45:05 GMT 94 | Expires: 95 | 0 96 | Location: 97 | https://api.tdameritrade.com/v1/accounts/000123456789/orders/54321 98 | Pragma: 99 | no-cache 100 | Set-Cookie: 101 | ADRUM_BTa=R:35|g:5a8fb378-1c9e-4c93-8c27-c0d0bd7fc2f3; Max-Age=30; Expires=Fri 102 | Strict-Transport-Security: 103 | max-age=31536000; includeSubDomains 104 | Vary: 105 | origin 106 | X-API-Version: 107 | 1.13.12 108 | X-Content-Type-Options: 109 | nosniff 110 | X-Frame-Options: 111 | DENY 112 | X-XSS-Protection: 113 | 1; mode=block -------------------------------------------------------------------------------- /sampledata/quotes_getQuote.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/marketdata/SPY/quotes" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/marketdata/SPY/quotes HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Connection: 51 | keep-alive 52 | Content-Encoding: 53 | gzip 54 | Content-Security-Policy: 55 | frame-ancestors 'self' 56 | Content-Type: 57 | application/json 58 | Date: 59 | Mon, 20 Dec 2021 07:18:10 GMT 60 | Strict-Transport-Security: 61 | max-age=31536000; includeSubDomains 62 | Transfer-Encoding: 63 | chunked 64 | vary: 65 | accept-encoding 66 | X-Content-Type-Options: 67 | nosniff 68 | X-Frame-Options: 69 | SAMEORIGIN 70 | X-Xss-Protection: 71 | 1; mode=block 72 | 73 | { 74 | "SPY": { 75 | "assetType": "ETF", 76 | "assetMainType": "EQUITY", 77 | "cusip": "78462F103", 78 | "assetSubType": "ETF", 79 | "symbol": "SPY", 80 | "description": "SPDR S&P 500", 81 | "bidPrice": 461.42, 82 | "bidSize": 300, 83 | "bidId": "P", 84 | "askPrice": 461.58, 85 | "askSize": 200, 86 | "askId": "P", 87 | "lastPrice": 459.87, 88 | "lastSize": 2071900, 89 | "lastId": "P", 90 | "openPrice": 461.55, 91 | "highPrice": 464.74, 92 | "lowPrice": 458.06, 93 | "bidTick": " ", 94 | "closePrice": 459.87, 95 | "netChange": 0, 96 | "totalVolume": 135636510, 97 | "quoteTimeInLong": 1639789200948, 98 | "tradeTimeInLong": 1639789200000, 99 | "mark": 459.87, 100 | "exchange": "p", 101 | "exchangeName": "PACIFIC", 102 | "marginable": true, 103 | "shortable": true, 104 | "volatility": 0.0111, 105 | "digits": 2, 106 | "52WkHigh": 473.54, 107 | "52WkLow": 362.03, 108 | "nAV": 0, 109 | "peRatio": 0, 110 | "divAmount": 5.6618, 111 | "divYield": 1.23, 112 | "divDate": "2021-09-17 00:00:00.000", 113 | "securityStatus": "Normal", 114 | "regularMarketLastPrice": 459.87, 115 | "regularMarketLastSize": 0, 116 | "regularMarketNetChange": 0, 117 | "regularMarketTradeTimeInLong": 1639789200000, 118 | "netPercentChangeInDouble": 0, 119 | "markChangeInDouble": 0, 120 | "markPercentChangeInDouble": 0, 121 | "regularMarketPercentChangeInDouble": 0, 122 | "delayed": false, 123 | "realtimeEntitled": true 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /sampledata/stream_CHART_EQUITY.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | '1': 327.65, 4 | '2': 327.8, 5 | '3': 327.55, 6 | '4': 327.6, 7 | '5': 311, 8 | '6': 779, 9 | '7': 1641344340000, 10 | '8': 18996, 11 | seq: 564, 12 | key: 'MSFT' 13 | } 14 | 15 | // TYPED 16 | { 17 | key: 'MSFT', 18 | seq: 564, 19 | datetime: 1641344340000, 20 | open: 327.65, 21 | high: 327.8, 22 | low: 327.55, 23 | close: 327.6, 24 | volume: 311 25 | } 26 | -------------------------------------------------------------------------------- /sampledata/stream_CHART_FUTURES.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | '1': 1641365820000, 4 | '2': 4775.250000000001, 5 | '3': 4775.500000000001, 6 | '4': 4775.250000000001, 7 | '5': 4775.250000000001, 8 | '6': 26, 9 | seq: 3237, 10 | key: '/ES' 11 | } 12 | 13 | 14 | // TYPED 15 | { 16 | timestamp: 1641365927539, 17 | key: '/ES', 18 | symbol: '/ES', 19 | seq: 3237, 20 | datetime: 1641365820000, 21 | open: 4775.250000000001, 22 | high: 4775.500000000001, 23 | low: 4775.250000000001, 24 | close: 4775.250000000001, 25 | volume: 26 26 | } 27 | -------------------------------------------------------------------------------- /sampledata/stream_LEVELONE_FOREX.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | "1": 1.1285, 4 | "10": 1.1309, 5 | "11": 1.1285, 6 | "12": 1.1373, 7 | "13": "T", 8 | "14": "Euro/USDollar Spot", 9 | "15": 1.1298, 10 | "16": -0.0087, 11 | "17": 0, 12 | "18": "GFT", 13 | "19": 2, 14 | "2": 1.1287, 15 | "20": "Unknown", 16 | "27": 1.1309, 17 | "28": 1.1285, 18 | "29": 1.1286, 19 | "3": 1.1286, 20 | "4": 2000000, 21 | "5": 1000000, 22 | "6": 29010000, 23 | "7": 10000, 24 | "8": 1641281388577, 25 | "9": 1641281388577, 26 | "assetMainType": "FOREX", 27 | "delayed": false, 28 | "key": "EUR/USD", 29 | } 30 | 31 | 32 | // TYPED 33 | { 34 | "ask": 1.1289, 35 | "askSize": 1000000, 36 | "assetMainType": "FOREX", 37 | "bid": 1.1288, 38 | "bidSize": 1000000, 39 | "dailyHigh": 1.1309, 40 | "dailyLow": 1.1285, 41 | "dailyOpen": 1.1298, 42 | "dailyVolume": 29010000, 43 | "delayed": false, 44 | "description": "Euro/USDollar Spot", 45 | "exchangeName": "GFT", 46 | "exchangeOfPrimaryListing": "T", 47 | "fiftyTwoWeekHigh": 1.1309, 48 | "fiftyTwoWeekLow": 1.1285, 49 | "isTradable": undefined, 50 | "key": "EUR/USD", 51 | "last": 1.1288, 52 | "lastSize": 10000, 53 | "mark": 1.1288, 54 | "marketMaker": undefined, 55 | "netChange": -0.0085, 56 | "percentChange": 0, 57 | "previousDayClose": 1.1373, 58 | "productName": undefined, 59 | "symbol": "EUR/USD", 60 | "tickAmount": undefined, 61 | "tickSize": undefined, 62 | "timeLastQuote": 1641281508391, 63 | "timeLastTrade": 1641281508391, 64 | "timestamp": 1641281508806, 65 | "tradingHours": undefined, 66 | "tradingStatus": "Unknown", 67 | "validDigits": 2, 68 | } 69 | -------------------------------------------------------------------------------- /sampledata/stream_LEVELONE_FUTURES.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | "1": 4793.5, 4 | "10": 1641281085902, 5 | "11": 1641281072904, 6 | "12": 4798.5, 7 | "13": 4781, 8 | "14": 4786, 9 | "15": "E", 10 | "16": "E-mini S&P 500 Index Futures,Mar-2022,ETH", 11 | "17": "?", 12 | "18": 4785.25, 13 | "19": 7.75, 14 | "2": 4793.75, 15 | "20": 0.0016, 16 | "21": "XCME", 17 | "22": "Unknown", 18 | "23": 2239274, 19 | "24": 4793.75, 20 | "25": 0.25, 21 | "26": 12.5, 22 | "27": "/ES", 23 | "28": "D,D", 24 | "29": "GLBX(de=1640;0=-17001600;1=r-17001600d-15551640;7=d-16401555)", 25 | "3": 4793.75, 26 | "30": true, 27 | "31": 50, 28 | "32": true, 29 | "33": 4786, 30 | "34": "/ESH22", 31 | "35": 1647576000000, 32 | "4": 15, 33 | "5": 14, 34 | "6": "?", 35 | "7": "?", 36 | "8": 46387, 37 | "9": 2, 38 | "assetMainType": "FUTURE", 39 | "delayed": false, 40 | "key": "/ES", 41 | } 42 | 43 | // TYPED 44 | { 45 | "activeContractSymbol": "/ESH22", 46 | "ask": 4794.25, 47 | "askSize": 12, 48 | "assetMainType": "FUTURE", 49 | "bid": 4794, 50 | "bidSize": 27, 51 | "contractExpirationMSEpoch": 1647576000000, 52 | "dailyHigh": 4798.5, 53 | "dailyLow": 4781, 54 | "dailyOpen": 4785.25, 55 | "dailyVolume": 46542, 56 | "delayed": false, 57 | "description": "E-mini S&P 500 Index Futures,Mar-2022,ETH", 58 | "exchangeBestAsk": "?", 59 | "exchangeBestBid": "?", 60 | "exchangeLastTrade": "?", 61 | "exchangeName": "XCME", 62 | "exchangeOfPrimaryListing": "E", 63 | "futuresProduct": "/ES", 64 | "isContractActive": true, 65 | "isTradable": true, 66 | "key": "/ES", 67 | "last": 4794.25, 68 | "lastSize": 1, 69 | "mark": 4794.25, 70 | "multiplier": 50, 71 | "netChange": 8.25, 72 | "openInterest": 2239274, 73 | "percentChange": 0.0017, 74 | "previousDayClose": 4786, 75 | "priceFormat": "D,D", 76 | "settlementPrice": 4786, 77 | "symbol": "/ES", 78 | "tickAmount": 12.5, 79 | "tickSize": 0.25, 80 | "timeLastQuote": 1641281303241, 81 | "timeLastTrade": 1641281300261, 82 | "timestamp": 1641281303495, 83 | "tradingHours": "GLBX(de=1640;0=-17001600;1=r-17001600d-15551640;7=d-16401555)", 84 | "tradingStatus": "Unknown", 85 | } 86 | -------------------------------------------------------------------------------- /sampledata/stream_LEVELONE_FUTURES_OPTIONS.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | '1': 122.25, 4 | '2': 123, 5 | '3': 123.5, 6 | '4': 11, 7 | '5': 2, 8 | '6': 63, 9 | '7': 63, 10 | '8': 207, 11 | '9': 2, 12 | '10': 1641364583546, 13 | '11': 1641360830980, 14 | '12': 123.5, 15 | '13': 120.75, 16 | '14': 116, 17 | '15': 63, 18 | '16': 'E-mini S&P 500 Options', 19 | '17': 120.75, 20 | '18': 2521, 21 | '19': 122.75, 22 | '22': 50, 23 | '23': 116, 24 | '24': '/ESH22', 25 | '25': 4750, 26 | '26': 1647576000000, 27 | key: './ESH22P4750', 28 | delayed: false 29 | } 30 | 31 | 32 | // TYPED 33 | { 34 | key: './ESH22P4750', 35 | symbol: './ESH22P4750', 36 | delayed: false, 37 | description: 'E-mini S&P 500 Options', 38 | multiplier: 50, 39 | underlyingSymbol: '/ESH22', 40 | strike: 4750, 41 | expirationDateMSEpoch: 1647576000000, 42 | bid: 122.25, 43 | ask: 123, 44 | last: 123.5, 45 | dailyHigh: 123.5, 46 | dailyLow: 120.75, 47 | previousDayClose: 116, 48 | dailyOpen: 120.75, 49 | unknown19: 122.75, 50 | unknown23: 116, 51 | bidSize: 11, 52 | askSize: 2, 53 | dailyVolume: 207, 54 | lastSize: 2, 55 | openInterest: 2521, 56 | exchangeBestAsk: 63, 57 | exchangeBestBid: 63, 58 | exchangeOfPrimaryListing: 63, 59 | timeLasatQuote: 1641364583546, 60 | timeLastTrade: 1641360830980 61 | } 62 | 63 | 64 | // RAW UNKNOWN SYMBOL 65 | { 66 | '1': 0, 67 | '2': 0, 68 | '3': 0, 69 | '6': 63, 70 | '7': 63, 71 | '12': 0, 72 | '13': 0, 73 | '14': 0, 74 | '15': 63, 75 | '16': 'Symbol not found', 76 | '17': 0, 77 | '19': 0, 78 | '23': 0, 79 | '24': 'N/A', 80 | key: 'yourmom', 81 | delayed: false 82 | } 83 | 84 | 85 | // TYPED UNKNOWN SYMBOL 86 | { 87 | key: 'yourmom', 88 | symbol: 'yourmom', 89 | delayed: false, 90 | description: 'Symbol not found', 91 | multiplier: undefined, 92 | underlyingSymbol: 'N/A', 93 | strike: undefined, 94 | expirationDateMSEpoch: undefined, 95 | bid: 0, 96 | ask: 0, 97 | last: 0, 98 | dailyHigh: 0, 99 | dailyLow: 0, 100 | previousDayClose: 0, 101 | dailyOpen: 0, 102 | unknown19: 0, 103 | unknown23: 0, 104 | bidSize: undefined, 105 | askSize: undefined, 106 | dailyVolume: undefined, 107 | lastSize: undefined, 108 | openInterest: undefined, 109 | exchangeBestAsk: 63, 110 | exchangeBestBid: 63, 111 | exchangeOfPrimaryListing: 63, 112 | timeLasatQuote: undefined, 113 | timeLastTrade: undefined 114 | } 115 | -------------------------------------------------------------------------------- /sampledata/stream_NEWS_HEADLINE.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | '1': 0, 4 | '2': 1641363248000, 5 | '3': 'B24899724', 6 | '4': 'U', 7 | '5': "Elon Musk's Name Used With Verified Twitter Profile Of Hacked Indonesian Consulate To Dupe Unsuspecting Users Of Bitcoin", 8 | '6': 'B24899724', 9 | '7': 2, 10 | '8': 'TSLA,$ETH,News,Markets,Cryptocurrency,$BTC,*ALL*', 11 | '9': false, 12 | '10': 'BENZINGA', 13 | seq: 151, 14 | key: 'TSLA' 15 | } 16 | 17 | // TYPED 18 | { 19 | timestamp: 1641366406204, 20 | seq: 151, 21 | key: 'TSLA', 22 | symbol: 'TSLA', 23 | errorCode: 0, 24 | storyDatetime: 1641363248000, 25 | headlineId: 'B24899724', 26 | status: 'U', 27 | headline: "Elon Musk's Name Used With Verified Twitter Profile Of Hacked Indonesian Consulate To Dupe Unsuspecting Users Of Bitcoin", 28 | storyId: 'B24899724', 29 | keywordCount: 2, 30 | keywords: 'TSLA,$ETH,News,Markets,Cryptocurrency,$BTC,*ALL*', 31 | isHot: false, 32 | storySource: 'BENZINGA' 33 | } 34 | -------------------------------------------------------------------------------- /sampledata/stream_OPTION.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | "1": "SPY Jan 7 2022 400 Call (Weekly)", 4 | "10": 38.5633, 5 | "11": 58498, 6 | "12": 40623, 7 | "13": 77.71, 8 | "14": 18995, 9 | "15": 18995, 10 | "16": 2022, 11 | "17": 100, 12 | "18": 2, 13 | "19": 75.32, 14 | "2": 77.39, 15 | "20": 300, 16 | "21": 112, 17 | "22": 1, 18 | "23": 0.36, 19 | "24": 400, 20 | "25": "C", 21 | "26": "SPY", 22 | "27": 1, 23 | "29": -2.39, 24 | "3": 77.69, 25 | "30": 7, 26 | "31": 3, 27 | "32": 1, 28 | "33": 0, 29 | "34": -0.0037, 30 | "35": 0.0001, 31 | "36": 0.0512, 32 | "37": "Normal", 33 | "38": 77.7265, 34 | "39": 477.71, 35 | "4": 75.32, 36 | "40": "S", 37 | "41": 77.7278, 38 | "5": 75.32, 39 | "6": 75.32, 40 | "7": 74.96, 41 | "8": 1, 42 | "9": 38, 43 | "assetMainType": "OPTION", 44 | "cusip": "0SPY..A720400000", 45 | "delayed": false, 46 | "key": "SPY_010722C400", 47 | } 48 | 49 | // TYPED 50 | { 51 | "ask": 77.69, 52 | "askSize": 112, 53 | "assetMainType": "OPTION", 54 | "bid": 77.39, 55 | "bidSize": 300, 56 | "contractType": "C", 57 | "cusip": "0SPY..A720400000", 58 | "dailyHigh": 75.32, 59 | "dailyLow": 75.32, 60 | "dailyOpen": 75.32, 61 | "dailyVolume": 1, 62 | "daysTilExpiration": 3, 63 | "delayed": false, 64 | "deliverables": undefined, 65 | "delta": 1, 66 | "description": "SPY Jan 7 2022 400 Call (Weekly)", 67 | "expirationDay": 7, 68 | "expirationMonth": 1, 69 | "expirationYear": 2022, 70 | "gamma": 0, 71 | "intrinsicValues": 77.71, 72 | "key": "SPY_010722C400", 73 | "last": 75.32, 74 | "lastSize": 1, 75 | "mark": 77.7278, 76 | "multiplier": 100, 77 | "netChange": 0.36, 78 | "openInterest": 38, 79 | "previousDayClose": 74.96, 80 | "quoteDay": 18995, 81 | "rho": 0.0512, 82 | "strikePrice": 400, 83 | "symbol": "SPY_010722C400", 84 | "theoreticalOptionValue": 77.7265, 85 | "theta": -0.0037, 86 | "timeLastQuote": 58498, 87 | "timeLastQuoteSecsFromMidnight": 58498, 88 | "timeLastTrade": 40623, 89 | "timeLastTradeSecsFromMidnight": 40623, 90 | "timeValue": -2.39, 91 | "timestamp": 1641280682792, 92 | "tradeDay": 18995, 93 | "tradingStatus": "Normal", 94 | "underlying": "SPY", 95 | "underlyingPrice": 477.71, 96 | "uvExpirationType": "S", 97 | "validDigits": 2, 98 | "vega": 0.0001, 99 | "volatility": 38.5633, 100 | } 101 | -------------------------------------------------------------------------------- /sampledata/stream_QUOTE.txt: -------------------------------------------------------------------------------- 1 | // RAW 2 | { 3 | "1": 334.12, 4 | "10": 71984, 5 | "11": 71988, 6 | "12": 338, 7 | "13": 329.78, 8 | "14": " ", 9 | "15": 336.32, 10 | "16": "q", 11 | "17": true, 12 | "18": true, 13 | "2": 334.6, 14 | "22": 18995, 15 | "23": 18995, 16 | "24": 0.0117, 17 | "25": "Microsoft Corporation - Common Stock", 18 | "26": "Q", 19 | "27": 4, 20 | "28": 335.35, 21 | "29": -1.91, 22 | "3": 334.41, 23 | "30": 349.67, 24 | "31": 211.94, 25 | "32": 37.5958, 26 | "33": 2.48, 27 | "34": 0.74, 28 | "39": "NASD", 29 | "4": 2, 30 | "40": "2022-02-16 00:00:00.000", 31 | "41": true, 32 | "43": 334.75, 33 | "44": 28339, 34 | "45": 57600, 35 | "46": 18995, 36 | "47": -1.57, 37 | "48": "Normal", 38 | "49": 334.6, 39 | "5": 1, 40 | "50": 1641257988820, 41 | "51": 1641257984777, 42 | "52": 1641243600763, 43 | "6": "P", 44 | "7": "P", 45 | "8": 28918013, 46 | "assetMainType": "EQUITY", 47 | "cusip": "594918104", 48 | "delayed": false, 49 | "key": "MSFT", 50 | } 51 | 52 | // TYPED 53 | { 54 | "NAV": undefined, 55 | "ask": 334.6, 56 | "askSize": 1, 57 | "assetMainType": "EQUITY", 58 | "bid": 334.12, 59 | "bidSize": 2, 60 | "bidTickDirection": " ", 61 | "cusip": "594918104", 62 | "dailyHigh": 338, 63 | "dailyLow": 329.78, 64 | "dailyOpen": 335.35, 65 | "dailyVolume": 28918013, 66 | "delayed": false, 67 | "description": "Microsoft Corporation - Common Stock", 68 | "dividendAmount": 2.48, 69 | "dividendDate": "2022-02-16 00:00:00.000", 70 | "dividendYield": 0.74, 71 | "exchangeBestAsk": "P", 72 | "exchangeBestBid": "P", 73 | "exchangeLastTrade": "Q", 74 | "exchangeName": "NASD", 75 | "exchangeOfPrimaryListing": "q", 76 | "fiftyTwoWeekHigh": 349.67, 77 | "fiftyTwoWeekLow": 211.94, 78 | "fundPrice": undefined, 79 | "isLastQuoteFromRegularMarket": true, 80 | "isLastTradeFromRegularMarket": undefined, 81 | "isMarginable": true, 82 | "isShortable": true, 83 | "islandAsk": undefined, 84 | "islandAskSize": undefined, 85 | "islandBid": undefined, 86 | "islandBidSize": undefined, 87 | "islandVolume": undefined, 88 | "key": "MSFT", 89 | "last": 334.41, 90 | "lastQuoteTimeSecsFromMidnight": 71988, 91 | "lastRegularMarketTradeDay": 18995, 92 | "lastRegularMarketTradeTimeMSEpoch": 1641243600763, 93 | "lastRegularMarketTradeTimeSecsFromMidnight": 57600, 94 | "lastSize": undefined, 95 | "lastTradeTimeSecsFromMidnight": 71984, 96 | "mark": 334.6, 97 | "netChange": -1.91, 98 | "peRatio": 37.5958, 99 | "previousDayClose": 336.32, 100 | "quoteDay": 18995, 101 | "regularMarketLastPrice": 334.75, 102 | "regularMarketLastSize": 28339, 103 | "regularMarketNetchange": -1.57, 104 | "symbol": "MSFT", 105 | "timeLastQuote": 1641257988820, 106 | "timeLastTrade": 1641257984777, 107 | "timestamp": 1641280945471, 108 | "tradeDay": 18995, 109 | "tradingStatus": "Normal", 110 | "validDigits": 4, 111 | "volatility": 0.0117, 112 | } 113 | -------------------------------------------------------------------------------- /sampledata/transactions-getTransaction.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " --header "Authorization: Bearer INSERT_TOKEN_HERE" "https://api.tdameritrade.com/v1/accounts/000123546789/transactions/123456789" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/accounts/000123456789/transactions/123456789 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_TOKEN_HERE 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 OK 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Connection: 51 | keep-alive 52 | Content-Length: 53 | 814 54 | Content-Security-Policy: 55 | frame-ancestors 'self' 56 | Content-Type: 57 | application/json 58 | Date: 59 | Fri, 17 Dec 2021 06:38:15 GMT 60 | Expires: 61 | 0 62 | Pragma: 63 | no-cache 64 | Set-Cookie: 65 | ADRUM_BTa="R:35|g:69966272-718f-4f6e-b1cd-cc80b97cc70b"; Version=1; Max-Age=30; Expires=Fri 66 | Strict-Transport-Security: 67 | max-age=31536000; includeSubDomains 68 | Vary: 69 | origin 70 | X-API-Version: 71 | 1.3.5 72 | X-Content-Type-Options: 73 | nosniff 74 | X-Frame-Options: 75 | DENY 76 | X-XSS-Protection: 77 | 1; mode=block 78 | 79 | { 80 | "type": "TRADE", 81 | "subAccount": "1", 82 | "settlementDate": "2021-06-04", 83 | "orderId": "T44444444", 84 | "netAmount": 4050.97, 85 | "transactionDate": "2021-06-02T11:00:48+0000", 86 | "orderDate": "2021-06-02T08:56:59+0000", 87 | "transactionSubType": "SL", 88 | "transactionId": 123456789, 89 | "cashBalanceEffectFlag": true, 90 | "description": "SELL TRADE", 91 | "fees": { 92 | "rFee": 0, 93 | "additionalFee": 0, 94 | "cdscFee": 0, 95 | "regFee": 0.03, 96 | "otherCharges": 0, 97 | "commission": 0, 98 | "optRegFee": 0, 99 | "secFee": 0.02 100 | }, 101 | "transactionItem": { 102 | "accountId": 000123456789, 103 | "amount": 100, 104 | "price": 40.51, 105 | "cost": 4051, 106 | "instruction": "SELL", 107 | "instrument": { 108 | "symbol": "AMC", 109 | "cusip": "00165C104", 110 | "assetType": "EQUITY" 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /sampledata/transactions-getTransactions.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/accounts/000123456789/transactions?type=ALL&symbol=AMC&startDate=2021-06-01&endDate=2021-06-04" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/accounts/000123456789/transactions?type=ALL&symbol=AMC&startDate=2021-06-01&endDate=2021-06-04 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 OK 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Connection: 51 | keep-alive 52 | Content-Length: 53 | 1582 54 | Content-Security-Policy: 55 | frame-ancestors 'self' 56 | Content-Type: 57 | application/json 58 | Date: 59 | Fri, 17 Dec 2021 07:14:35 GMT 60 | Expires: 61 | 0 62 | Pragma: 63 | no-cache 64 | Set-Cookie: 65 | ADRUM_BTa="R:35|g:771a2359-6ba7-482d-9880-638993dc788f"; Version=1; Max-Age=30; Expires=Fri 66 | Strict-Transport-Security: 67 | max-age=31536000; includeSubDomains 68 | Vary: 69 | origin 70 | X-API-Version: 71 | 1.3.5 72 | X-Content-Type-Options: 73 | nosniff 74 | X-Frame-Options: 75 | DENY 76 | X-XSS-Protection: 77 | 1; mode=block 78 | 79 | [ 80 | { 81 | "type": "TRADE", 82 | "subAccount": "1", 83 | "settlementDate": "2021-06-04", 84 | "orderId": "T444444444", 85 | "netAmount": 4050.97, 86 | "transactionDate": "2021-06-02T11:00:48+0000", 87 | "orderDate": "2021-06-02T08:56:59+0000", 88 | "transactionSubType": "SL", 89 | "transactionId": 123456789, 90 | "cashBalanceEffectFlag": true, 91 | "description": "SELL TRADE", 92 | "fees": { 93 | "rFee": 0, 94 | "additionalFee": 0, 95 | "cdscFee": 0, 96 | "regFee": 0.03, 97 | "otherCharges": 0, 98 | "commission": 0, 99 | "optRegFee": 0, 100 | "secFee": 0.02 101 | }, 102 | "transactionItem": { 103 | "accountId": 000123456789, 104 | "amount": 100, 105 | "price": 40.51, 106 | "cost": 4051, 107 | "instruction": "SELL", 108 | "instrument": { 109 | "symbol": "AMC", 110 | "cusip": "00165C104", 111 | "assetType": "EQUITY" 112 | } 113 | } 114 | }, 115 | { 116 | "type": "RECEIVE_AND_DELIVER", 117 | "subAccount": "1", 118 | "settlementDate": "2021-06-01", 119 | "netAmount": 0, 120 | "transactionDate": "2021-06-01T05:00:01+0000", 121 | "transactionSubType": "OX", 122 | "transactionId": 234567890, 123 | "cashBalanceEffectFlag": true, 124 | "description": "REMOVAL OF OPTION DUE TO EXPIRATION", 125 | "fees": { 126 | "rFee": 0, 127 | "additionalFee": 0, 128 | "cdscFee": 0, 129 | "regFee": 0, 130 | "otherCharges": 0, 131 | "commission": 0, 132 | "optRegFee": 0, 133 | "secFee": 0 134 | }, 135 | "transactionItem": { 136 | "accountId": 000123456789, 137 | "amount": 1, 138 | "cost": 0, 139 | "instrument": { 140 | "optionExpirationDate": "2021-05-28T05:00:00+0000", 141 | "cusip": "0AMC..ES10040000", 142 | "assetType": "OPTION" 143 | } 144 | } 145 | } 146 | ] 147 | -------------------------------------------------------------------------------- /sampledata/userinfo-getPreferences.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/accounts/000123456789/preferences" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/accounts/000123456789/preferences HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 OK 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Cneonction: 51 | close 52 | Connection: 53 | keep-alive 54 | Content-Length: 55 | 535 56 | Content-Security-Policy: 57 | frame-ancestors 'self' 58 | Content-Type: 59 | application/json 60 | Date: 61 | Fri, 17 Dec 2021 05:29:20 GMT 62 | Expires: 63 | 0 64 | Pragma: 65 | no-cache 66 | Set-Cookie: 67 | ADRUM_BTa="R:35|g:969f3410-059e-4bbd-b072-7d043f21073a"; Version=1; Max-Age=30; Expires=Fri 68 | Strict-Transport-Security: 69 | max-age=31536000; includeSubDomains 70 | Vary: 71 | origin 72 | X-API-Version: 73 | 1.11.3 74 | X-Content-Type-Options: 75 | nosniff 76 | X-Frame-Options: 77 | DENY 78 | X-XSS-Protection: 79 | 1; mode=block 80 | 81 | { 82 | "expressTrading": false, 83 | "directOptionsRouting": false, 84 | "directEquityRouting": false, 85 | "defaultEquityOrderLegInstruction": "NONE", 86 | "defaultEquityOrderType": "LIMIT", 87 | "defaultEquityOrderPriceLinkType": "NONE", 88 | "defaultEquityOrderDuration": "DAY", 89 | "defaultEquityOrderMarketSession": "NORMAL", 90 | "defaultEquityQuantity": 0, 91 | "mutualFundTaxLotMethod": "FIFO", 92 | "optionTaxLotMethod": "FIFO", 93 | "equityTaxLotMethod": "FIFO", 94 | "defaultAdvancedToolLaunch": "NONE", 95 | "authTokenTimeout": "FIFTY_FIVE_MINUTES" 96 | } 97 | -------------------------------------------------------------------------------- /sampledata/userinfo-getStreamerSubKeys.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: " --header "Authorization: Bearer INSERT_ACCESS_CODE" "https://api.tdameritrade.com/v1/userprincipals/streamersubscriptionkeys?accountIds=000123456789" 2 | 3 | 4 | GET /v1/userprincipals/streamersubscriptionkeys?accountIds=000123456789 HTTP/1.1 5 | 6 | Accept: 7 | */* 8 | Accept-Encoding: 9 | gzip 10 | Accept-Language: 11 | en-US 12 | Authorization: 13 | Bearer INSERT_ACCESS_CODE 14 | Host: 15 | api.tdameritrade.com 16 | NS-Proxy-Client-IP: 17 | 24.24.24.24 18 | Sec-Fetch-Dest: 19 | empty 20 | Sec-Fetch-Mode: 21 | cors 22 | Sec-Fetch-Site: 23 | same-site 24 | User-Agent: 25 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 26 | X-Forwarded-For: 27 | 10.152.4.23 28 | X-Forwarded-Port: 29 | 59002 30 | X-Forwarded-Proto: 31 | http 32 | 33 | 34 | RESPONSE 35 | 36 | HTTP/1.1 200 OK 37 | 38 | Access-Control-Allow-Headers: 39 | origin 40 | Access-Control-Allow-Methods: 41 | GET 42 | Access-Control-Allow-Origin: 43 | https://developer.tdameritrade.com 44 | Access-Control-Max-Age: 45 | 3628800 46 | Cache-Control: 47 | no-cache 48 | Connection: 49 | keep-alive 50 | Content-Length: 51 | 136 52 | Content-Security-Policy: 53 | frame-ancestors 'self' 54 | Content-Type: 55 | application/json 56 | Date: 57 | Fri, 17 Dec 2021 05:34:39 GMT 58 | Expires: 59 | 0 60 | Pragma: 61 | no-cache 62 | Set-Cookie: 63 | ADRUM_BTa="R:35|g:95849697-fcd3-47d0-8991-dbf0701d5503"; Version=1; Max-Age=30; Expires=Fri 64 | Strict-Transport-Security: 65 | max-age=31536000; includeSubDomains 66 | X-API-Version: 67 | 1.11.3 68 | X-Content-Type-Options: 69 | nosniff 70 | X-Frame-Options: 71 | DENY 72 | X-XSS-Protection: 73 | 1; mode=block 74 | 75 | { 76 | "keys": [ 77 | { 78 | "key": "be24aweofijawwjwjf9338jfjf2838fj2039" 79 | } 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /sampledata/userinfo-updatePreferences.txt: -------------------------------------------------------------------------------- 1 | curl -X PUT --header "Authorization: " --header "Authorization: Bearer INSERT_ACCESS_CODE" --header "Content-Type: application/json" -d "{ 2 | \"expressTrading\": false, 3 | \"directOptionsRouting\": false, 4 | \"directEquityRouting\": false, 5 | \"defaultEquityOrderLegInstruction\": \"NONE\", 6 | \"defaultEquityOrderType\": \"LIMIT\", 7 | \"defaultEquityOrderPriceLinkType\": \"NONE\", 8 | \"defaultEquityOrderDuration\": \"DAY\", 9 | \"defaultEquityOrderMarketSession\": \"NORMAL\", 10 | \"defaultEquityQuantity\": 0, 11 | \"mutualFundTaxLotMethod\": \"FIFO\", 12 | \"optionTaxLotMethod\": \"FIFO\", 13 | \"equityTaxLotMethod\": \"FIFO\", 14 | \"defaultAdvancedToolLaunch\": \"NONE\", 15 | \"authTokenTimeout\": \"EIGHT_HOURS\" 16 | }" "https://api.tdameritrade.com/v1/accounts/000123456789/preferences" 17 | 18 | 19 | REQUEST 20 | 21 | PUT /v1/accounts/000123456789/preferences HTTP/1.1 22 | 23 | Accept: 24 | */* 25 | Accept-Encoding: 26 | gzip 27 | Accept-Language: 28 | en-US 29 | Authorization: 30 | Bearer INSERT_ACCESS_CODE 31 | Content-Length: 32 | 514 33 | Content-Type: 34 | application/json 35 | Host: 36 | api.tdameritrade.com 37 | NS-Proxy-Client-IP: 38 | 24.24.24.24 39 | Sec-Fetch-Dest: 40 | empty 41 | Sec-Fetch-Mode: 42 | cors 43 | Sec-Fetch-Site: 44 | same-site 45 | User-Agent: 46 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 47 | X-Forwarded-For: 48 | 10.152.4.23 49 | X-Forwarded-Port: 50 | 59002 51 | X-Forwarded-Proto: 52 | http 53 | 54 | { 55 | "expressTrading": false, 56 | "directOptionsRouting": false, 57 | "directEquityRouting": false, 58 | "defaultEquityOrderLegInstruction": "NONE", 59 | "defaultEquityOrderType": "LIMIT", 60 | "defaultEquityOrderPriceLinkType": "NONE", 61 | "defaultEquityOrderDuration": "DAY", 62 | "defaultEquityOrderMarketSession": "NORMAL", 63 | "defaultEquityQuantity": 0, 64 | "mutualFundTaxLotMethod": "FIFO", 65 | "optionTaxLotMethod": "FIFO", 66 | "equityTaxLotMethod": "FIFO", 67 | "defaultAdvancedToolLaunch": "NONE", 68 | "authTokenTimeout": "EIGHT_HOURS" 69 | } 70 | 71 | 72 | RESPONSE 73 | 74 | HTTP/1.1 204 No Content 75 | 76 | Access-Control-Allow-Headers: 77 | origin 78 | Access-Control-Allow-Methods: 79 | GET 80 | Access-Control-Allow-Origin: 81 | https://developer.tdameritrade.com 82 | Access-Control-Max-Age: 83 | 3628800 84 | Cache-Control: 85 | no-cache 86 | Connection: 87 | keep-alive 88 | Content-Length: 89 | 0 90 | Content-Security-Policy: 91 | frame-ancestors 'self' 92 | Date: 93 | Fri, 17 Dec 2021 05:40:40 GMT 94 | Expires: 95 | 0 96 | Location: 97 | https://api.tdameritrade.com/v1/accounts/000123456789/preferences 98 | Pragma: 99 | no-cache 100 | Set-Cookie: 101 | ADRUM_BTa="R:35|g:3a3b9341-bca8-48d7-abae-856c3482715d"; Version=1; Max-Age=30; Expires=Fri 102 | Strict-Transport-Security: 103 | max-age=31536000; includeSubDomains 104 | Vary: 105 | origin 106 | X-API-Version: 107 | 1.11.3 108 | X-Content-Type-Options: 109 | nosniff 110 | X-Frame-Options: 111 | DENY 112 | X-XSS-Protection: 113 | 1; mode=block 114 | -------------------------------------------------------------------------------- /sampledata/watchlist-createwatchlist.txt: -------------------------------------------------------------------------------- 1 | curl -X POST --header "Authorization: Bearer INSERT_ACCESS_TOKEN" --header "Content-Type: application/json" -d "{ 2 | \"name\": \"test20211211\", 3 | \"watchlistItems\": [ 4 | { 5 | \"instrument\": { 6 | \"symbol\": \"SPY\" 7 | } 8 | } 9 | ] 10 | }" "https://api.tdameritrade.com/v1/accounts/000123456789/watchlists" 11 | 12 | 13 | REQUEST 14 | 15 | POST /v1/accounts/000123456789/watchlists HTTP/1.1 16 | 17 | Accept: 18 | */* 19 | Accept-Encoding: 20 | gzip 21 | Accept-Language: 22 | en-US 23 | Authorization: 24 | Bearer INSSERT_ACCESS_TOKEN 25 | Content-Length: 26 | 156 27 | Content-Type: 28 | application/json 29 | Host: 30 | api.tdameritrade.com 31 | NS-Proxy-Client-IP: 32 | 24.24.24.24 33 | Sec-Fetch-Dest: 34 | empty 35 | Sec-Fetch-Mode: 36 | cors 37 | Sec-Fetch-Site: 38 | same-site 39 | User-Agent: 40 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 41 | X-Forwarded-For: 42 | 10.152.4.23 43 | X-Forwarded-Port: 44 | 59002 45 | X-Forwarded-Proto: 46 | http 47 | 48 | { 49 | "name": "test20211211", 50 | "watchlistItems": [ 51 | { 52 | "instrument": { 53 | "symbol": "SPY" 54 | } 55 | } 56 | ] 57 | } 58 | 59 | 60 | RESPONSE 61 | 62 | HTTP/1.1 201 Created 63 | 64 | Access-Control-Allow-Headers: 65 | origin 66 | Access-Control-Allow-Methods: 67 | GET 68 | Access-Control-Allow-Origin: 69 | https://developer.tdameritrade.com 70 | Access-Control-Max-Age: 71 | 3628800 72 | Cache-Control: 73 | no-cache 74 | Connection: 75 | keep-alive 76 | Content-Length: 77 | 0 78 | Content-Security-Policy: 79 | frame-ancestors 'self' 80 | Date: 81 | Sun, 12 Dec 2021 06:05:54 GMT 82 | Expires: 83 | 0 84 | Location: 85 | https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456 86 | Pragma: 87 | no-cache 88 | Set-Cookie: 89 | ADRUM_BTa="R:35|g:5b66f3a5-f7cb-4ee2-a85d-9e45c0c43b41"; Version=1; Max-Age=30; Expires=Sun 90 | Strict-Transport-Security: 91 | max-age=31536000; includeSubDomains 92 | Vary: 93 | origin 94 | X-API-Version: 95 | 1.2.4 96 | X-Content-Type-Options: 97 | nosniff 98 | X-Frame-Options: 99 | DENY 100 | X-XSS-Protection: 101 | 1; mode=block -------------------------------------------------------------------------------- /sampledata/watchlist-deletewatchlist.txt: -------------------------------------------------------------------------------- 1 | curl -X DELETE --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456" 2 | 3 | 4 | REQUEST 5 | 6 | DELETE /v1/accounts/000123456789/watchlists/123456 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Content-Length: 17 | 0 18 | Host: 19 | api.tdameritrade.com 20 | NS-Proxy-Client-IP: 21 | 24.24.24.24 22 | Sec-Fetch-Dest: 23 | empty 24 | Sec-Fetch-Mode: 25 | cors 26 | Sec-Fetch-Site: 27 | same-site 28 | User-Agent: 29 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 30 | X-Forwarded-For: 31 | 10.152.4.23 32 | X-Forwarded-Port: 33 | 59002 34 | X-Forwarded-Proto: 35 | http 36 | 37 | 38 | RESPONSE 39 | 40 | HTTP/1.1 204 No Content 41 | 42 | Access-Control-Allow-Headers: 43 | origin 44 | Access-Control-Allow-Methods: 45 | GET 46 | Access-Control-Allow-Origin: 47 | https://developer.tdameritrade.com 48 | Access-Control-Max-Age: 49 | 3628800 50 | Cache-Control: 51 | no-cache 52 | Connection: 53 | keep-alive 54 | Content-Length: 55 | 0 56 | Content-Security-Policy: 57 | frame-ancestors 'self' 58 | Date: 59 | Sun, 12 Dec 2021 05:57:41 GMT 60 | Expires: 61 | 0 62 | Pragma: 63 | no-cache 64 | Set-Cookie: 65 | ADRUM_BTa="R:35|g:dd47a78f-ac48-4597-86c2-16b7a8d5fa41"; Version=1; Max-Age=30; Expires=Sun 66 | Strict-Transport-Security: 67 | max-age=31536000; includeSubDomains 68 | Vary: 69 | origin 70 | X-API-Version: 71 | 1.2.4 72 | X-Content-Type-Options: 73 | nosniff 74 | X-Frame-Options: 75 | DENY 76 | X-XSS-Protection: 77 | 1; mode=block 78 | -------------------------------------------------------------------------------- /sampledata/watchlist-getwatchlist.txt: -------------------------------------------------------------------------------- 1 | curl -X GET --header "Authorization: Bearer INSERT_ACCESS_TOKEN" "https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456" 2 | 3 | 4 | REQUEST 5 | 6 | GET /v1/accounts/000123456789/watchlists/123456 HTTP/1.1 7 | 8 | Accept: 9 | */* 10 | Accept-Encoding: 11 | gzip 12 | Accept-Language: 13 | en-US 14 | Authorization: 15 | Bearer INSERT_ACCESS_TOKEN 16 | Host: 17 | api.tdameritrade.com 18 | NS-Proxy-Client-IP: 19 | 24.24.24.24 20 | Sec-Fetch-Dest: 21 | empty 22 | Sec-Fetch-Mode: 23 | cors 24 | Sec-Fetch-Site: 25 | same-site 26 | User-Agent: 27 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 28 | X-Forwarded-For: 29 | 10.152.4.23 30 | X-Forwarded-Port: 31 | 59002 32 | X-Forwarded-Proto: 33 | http 34 | 35 | 36 | RESPONSE 37 | 38 | HTTP/1.1 200 OK 39 | 40 | Access-Control-Allow-Headers: 41 | origin 42 | Access-Control-Allow-Methods: 43 | GET 44 | Access-Control-Allow-Origin: 45 | https://developer.tdameritrade.com 46 | Access-Control-Max-Age: 47 | 3628800 48 | Cache-Control: 49 | no-cache 50 | Connection: 51 | keep-alive 52 | Content-Length: 53 | 296 54 | Content-Security-Policy: 55 | frame-ancestors 'self' 56 | Content-Type: 57 | application/json 58 | Date: 59 | Sun, 12 Dec 2021 05:48:59 GMT 60 | Expires: 61 | 0 62 | Pragma: 63 | no-cache 64 | Set-Cookie: 65 | ADRUM_BTa="R:35|g:fa2847af-c49a-4b19-b112-6d167a1673bb"; Version=1; Max-Age=30; Expires=Sun 66 | Strict-Transport-Security: 67 | max-age=31536000; includeSubDomains 68 | Vary: 69 | origin 70 | X-API-Version: 71 | 1.2.4 72 | X-Content-Type-Options: 73 | nosniff 74 | X-Frame-Options: 75 | DENY 76 | X-XSS-Protection: 77 | 1; mode=block 78 | 79 | { 80 | "name": "test20211211", 81 | "watchlistId": "123456", 82 | "accountId": "000123456789", 83 | "watchlistItems": [ 84 | { 85 | "sequenceId": 1, 86 | "quantity": 0, 87 | "averagePrice": 0, 88 | "commission": 0, 89 | "instrument": { 90 | "symbol": "SPY", 91 | "assetType": "EQUITY" 92 | } 93 | } 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /sampledata/watchlist-replacewatchlist.txt: -------------------------------------------------------------------------------- 1 | curl -X PUT --header "Authorization: Bearer INSERT_ACCESS_TOKEN" --header "Content-Type: application/json" -d "{ 2 | \"name\": \"wlnewname\", 3 | \"watchlistId\": \"123456\", 4 | \"watchlistItems\": [ 5 | { 6 | \"quantity\": 0, 7 | \"averagePrice\": 0, 8 | \"commission\": 0, 9 | \"instrument\": { 10 | \"symbol\": \"SPY\", 11 | \"assetType\": \"EQUITY\" 12 | } 13 | } 14 | ] 15 | }" "https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456" 16 | 17 | 18 | REQUEST 19 | 20 | PUT /v1/accounts/000123456789/watchlists/123456 HTTP/1.1 21 | 22 | Accept: 23 | */* 24 | Accept-Encoding: 25 | gzip 26 | Accept-Language: 27 | en-US 28 | Authorization: 29 | Bearer INSERT_ACCESS_TOKEN 30 | Content-Length: 31 | 249 32 | Content-Type: 33 | application/json 34 | Host: 35 | api.tdameritrade.com 36 | NS-Proxy-Client-IP: 37 | 24.24.24.24 38 | Sec-Fetch-Dest: 39 | empty 40 | Sec-Fetch-Mode: 41 | cors 42 | Sec-Fetch-Site: 43 | same-site 44 | User-Agent: 45 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 46 | X-Forwarded-For: 47 | 10.152.4.23 48 | X-Forwarded-Port: 49 | 59002 50 | X-Forwarded-Proto: 51 | http 52 | 53 | { 54 | "name": "wlnewname", 55 | "watchlistId": "123456", 56 | "watchlistItems": [ 57 | { 58 | "quantity": 0, 59 | "averagePrice": 0, 60 | "commission": 0, 61 | "instrument": { 62 | "symbol": "SPY", 63 | "assetType": "EQUITY" 64 | } 65 | } 66 | ] 67 | } 68 | 69 | 70 | RESPONSE 71 | 72 | HTTP/1.1 204 No Content 73 | 74 | Access-Control-Allow-Headers: 75 | origin 76 | Access-Control-Allow-Methods: 77 | GET 78 | Access-Control-Allow-Origin: 79 | https://developer.tdameritrade.com 80 | Access-Control-Max-Age: 81 | 3628800 82 | Cache-Control: 83 | no-cache 84 | Connection: 85 | keep-alive 86 | Content-Length: 87 | 0 88 | Content-Security-Policy: 89 | frame-ancestors 'self' 90 | Date: 91 | Sun, 12 Dec 2021 06:30:27 GMT 92 | Expires: 93 | 0 94 | Location: 95 | https://api.tdameritrade.com/v1/accounts/000123456/watchlists/123456 96 | Pragma: 97 | no-cache 98 | Set-Cookie: 99 | ADRUM_BTa="R:35|g:fa02a623-b9b4-458d-a5b3-4498aa66206e"; Version=1; Max-Age=30; Expires=Sun 100 | Strict-Transport-Security: 101 | max-age=31536000; includeSubDomains 102 | Vary: 103 | origin 104 | X-API-Version: 105 | 1.2.4 106 | X-Content-Type-Options: 107 | nosniff 108 | X-Frame-Options: 109 | DENY 110 | X-XSS-Protection: 111 | 1; mode=block 112 | -------------------------------------------------------------------------------- /sampledata/watchlist-updatewatchlist.txt: -------------------------------------------------------------------------------- 1 | curl -X PATCH --header "Authorization: Bearer INSERT_ACCESS_TOKEN" --header "Content-Type: application/json" -d "{ 2 | \"name\": \"wlnewname\", 3 | \"watchlistId\": \"123456\", 4 | \"watchlistItems\": [ 5 | { 6 | \"sequenceId\": 1, 7 | \"quantity\": 0, 8 | \"averagePrice\": 0, 9 | \"commission\": 0, 10 | \"instrument\": { 11 | \"symbol\": \"SPY\", 12 | \"assetType\": \"EQUITY\" 13 | } 14 | } 15 | ] 16 | }" "https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456" 17 | 18 | 19 | REQUEST 20 | 21 | PATCH /v1/accounts/000123456789/watchlists/123456 HTTP/1.1 22 | 23 | Accept: 24 | */* 25 | Accept-Encoding: 26 | gzip 27 | Accept-Language: 28 | en-US 29 | Authorization: 30 | Bearer INSERT_ACCESS_TOKEN 31 | Content-Length: 32 | 272 33 | Content-Type: 34 | application/json 35 | Host: 36 | api.tdameritrade.com 37 | NS-Proxy-Client-IP: 38 | 24.24.24.24 39 | Sec-Fetch-Dest: 40 | empty 41 | Sec-Fetch-Mode: 42 | cors 43 | Sec-Fetch-Site: 44 | same-site 45 | User-Agent: 46 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0 47 | X-Forwarded-For: 48 | 10.152.4.23 49 | X-Forwarded-Port: 50 | 59002 51 | X-Forwarded-Proto: 52 | http 53 | 54 | { 55 | "name": "wlnewname", 56 | "watchlistId": "123456", 57 | "watchlistItems": [ 58 | { 59 | "sequenceId": 1, 60 | "quantity": 0, 61 | "averagePrice": 0, 62 | "commission": 0, 63 | "instrument": { 64 | "symbol": "SPY", 65 | "assetType": "EQUITY" 66 | } 67 | } 68 | ] 69 | } 70 | 71 | 72 | RESPONSE 73 | 74 | HTTP/1.1 204 No Content 75 | 76 | Access-Control-Allow-Headers: 77 | origin 78 | Access-Control-Allow-Methods: 79 | GET 80 | Access-Control-Allow-Origin: 81 | https://developer.tdameritrade.com 82 | Access-Control-Max-Age: 83 | 3628800 84 | Cache-Control: 85 | no-cache 86 | Connection: 87 | keep-alive 88 | Content-Length: 89 | 0 90 | Content-Location: 91 | https://api.tdameritrade.com/v1/accounts/000123456789/watchlists/123456 92 | Content-Security-Policy: 93 | frame-ancestors 'self' 94 | Date: 95 | Sun, 12 Dec 2021 06:17:31 GMT 96 | Expires: 97 | 0 98 | Pragma: 99 | no-cache 100 | Set-Cookie: 101 | ADRUM_BTa="R:35|g:d61ee2f9-581b-4743-bb3a-c578ef2cdbe7"; Version=1; Max-Age=30; Expires=Sun 102 | Strict-Transport-Security: 103 | max-age=31536000; includeSubDomains 104 | Vary: 105 | origin 106 | X-API-Version: 107 | 1.2.4 108 | X-Content-Type-Options: 109 | nosniff 110 | X-Frame-Options: 111 | DENY 112 | X-XSS-Protection: 113 | 1; mode=block 114 | -------------------------------------------------------------------------------- /samples/inputJSON/order.json: -------------------------------------------------------------------------------- 1 | { 2 | "orderType": "MARKET", 3 | "session": "NORMAL", 4 | "duration": "DAY", 5 | "orderStrategyType": "SINGLE", 6 | "orderLegCollection": [ 7 | { 8 | "instruction": "Buy", 9 | "quantity": 10, 10 | "instrument": { 11 | "symbol": "F", 12 | "assetType": "EQUITY" 13 | } 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /samples/inputJSON/userpreferences.json: -------------------------------------------------------------------------------- 1 | { 2 | "expressTrading":false, 3 | "defaultEquityOrderLegInstruction":"NONE", 4 | "defaultEquityOrderType":"LIMIT", 5 | "defaultEquityOrderPriceLinkType":"NONE", 6 | "defaultEquityOrderDuration":"DAY", 7 | "defaultEquityOrderMarketSession":"NORMAL", 8 | "defaultEquityQuantity":0, 9 | "mutualFundTaxLotMethod":"FIFO", 10 | "optionTaxLotMethod":"FIFO", 11 | "equityTaxLotMethod":"FIFO", 12 | "defaultAdvancedToolLaunch":"NONE", 13 | "authTokenTimeout":"FIFTY_FIVE_MINUTES" 14 | } 15 | -------------------------------------------------------------------------------- /samples/inputJSON/watchlist.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test_watchlist", 3 | "watchlistItems": [ 4 | { 5 | "quantity": 1, 6 | "averagePrice": 2, 7 | "commission": 3, 8 | "purchasedDate": "2020-08-21", 9 | "instrument": { 10 | "symbol": "T", 11 | "assetType": "EQUITY" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/accounts.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import * as path from "path"; 3 | import {EGetAccountField, getAccount, getAccounts, IAccount, IGetAccountConfig, IGetAccountsConfig} from "./accounts"; 4 | 5 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 6 | 7 | describe("accounts", () => { 8 | test("getAccounts", async () => { 9 | expect(testAuthConfig).toBeTruthy(); 10 | 11 | const config: IGetAccountsConfig = { 12 | fields: [EGetAccountField.ORDERS, EGetAccountField.POSITIONS], 13 | authConfigFileLocation: testauthpath, 14 | }; 15 | const result: IAccount[] = await getAccounts(config); 16 | expect(result).toBeTruthy(); 17 | expect(result[0].securitiesAccount.accountId).toBeTruthy(); 18 | expect(result[0].securitiesAccount.currentBalances).toBeTruthy(); 19 | }); 20 | 21 | test("getAccount", async () => { 22 | const accounts: IAccount[] = await getAccounts({ 23 | fields: "positions,orders", 24 | authConfigFileLocation: testauthpath, 25 | }); 26 | 27 | expect(accounts[0].securitiesAccount.accountId).toBeTruthy(); 28 | 29 | const config: IGetAccountConfig = { 30 | accountId: accounts[0].securitiesAccount.accountId, 31 | fields: "positions,orders", 32 | authConfigFileLocation: testauthpath, 33 | }; 34 | const account: IAccount = await getAccount(config); 35 | expect(String(account.securitiesAccount.accountId)).toBe(String(accounts[0].securitiesAccount.accountId)); 36 | expect(account.securitiesAccount.currentBalances).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/accounts.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiGet, TacRequestConfig} from "./tdapiinterface"; 4 | import {IInstrument} from "./sharedTypes"; 5 | import {IOrderStrategy} from "./orders"; 6 | 7 | export interface IAccountBalance { 8 | accruedInterest: number, 9 | availableFundsNonMarginableTrade: number, 10 | bondValue: number, 11 | buyingPower: number, 12 | cashBalance: number, 13 | cashAvailableForTrading: number, 14 | cashReceipts: number, 15 | dayTradingBuyingPower: number, 16 | dayTradingBuyingPowerCall: number, 17 | dayTradingEquityCall: number, 18 | equity: number, 19 | equityPercentage: number, 20 | liquidationValue: number, 21 | longMarginValue: number, 22 | longOptionMarketValue: number, 23 | longStockValue: number, 24 | maintenanceCall: number, 25 | maintenanceRequirement: number, 26 | margin: number, 27 | marginEquity: number, 28 | moneyMarketFund: number, 29 | mutualFundValue: number, 30 | regTCall: number, 31 | shortMarginValue: number, 32 | shortOptionMarketValue: number, 33 | shortStockValue: number, 34 | totalCash: number, 35 | isInCall: boolean, 36 | pendingDeposits: number, 37 | marginBalance: number, 38 | shortBalance: number, 39 | accountValue: number 40 | } 41 | 42 | export interface IProjectedBalance { 43 | availableFunds: number, 44 | availableFundsNonMarginableTrade: number, 45 | buyingPower: number, 46 | dayTradingBuyingPower: number, 47 | dayTradingBuyingPowerCall: number, 48 | maintenanceCall: number, 49 | regTCall: number, 50 | isInCall: boolean, 51 | stockBuyingPower: number 52 | } 53 | 54 | export interface ICurrentBalance { 55 | accruedInterest: number, 56 | cashBalance: number, 57 | cashReceipts: number, 58 | longOptionMarketValue: number, 59 | liquidationValue: number, 60 | longMarketValue: number, 61 | moneyMarketFund: number, 62 | savings: number, 63 | shortMarketValue: number, 64 | pendingDeposits: number, 65 | availableFunds: number, 66 | availableFundsNonMarginableTrade: number, 67 | buyingPower: number, 68 | buyingPowerNonMarginableTrade: number, 69 | dayTradingBuyingPower: number, 70 | equity: number, 71 | equityPercentage: number, 72 | longMarginValue: number, 73 | maintenanceCall: number, 74 | maintenanceRequirement: number, 75 | marginBalance: number, 76 | regTCall: number, 77 | shortBalance: number, 78 | shortMarginValue: number, 79 | shortOptionMarketValue: number, 80 | sma: number, 81 | mutualFundValue: number, 82 | bondValue: number 83 | } 84 | 85 | export interface IAccountPosition { 86 | shortQuantity: number, 87 | averagePrice: number, 88 | currentDayProfitLoss: number, 89 | currentDayProfitLossPercentage: number, 90 | longQuantity: number, 91 | settledLongQuantity: number, 92 | settledShortQuantity: number, 93 | agedQuantity: number, 94 | instrument: IInstrument, 95 | marketValue: number, 96 | maintenanceRequirement: number, 97 | currentDayCost: number, 98 | previousSessionLongQuantity: number, 99 | } 100 | 101 | export interface IAccount { 102 | securitiesAccount: ISecuritiesAccount 103 | } 104 | 105 | export interface ISecuritiesAccount { 106 | type: string, 107 | accountId: string, 108 | roundTrips: number, 109 | isDayTrader: boolean, 110 | isClosingOnlyRestricted: boolean, 111 | positions: IAccountPosition[], 112 | orderStrategies: IOrderStrategy[], 113 | initialBalances: IAccountBalance, 114 | currentBalances: ICurrentBalance, 115 | projectedBalances: IProjectedBalance, 116 | } 117 | 118 | export interface IGetAccountConfig extends TacRequestConfig { 119 | accountId: string | number, 120 | fields?: string | string[] | EGetAccountField[], 121 | } 122 | 123 | export interface IGetAccountsConfig extends TacRequestConfig { 124 | fields?: string | string[] | EGetAccountField[], 125 | } 126 | 127 | export enum EGetAccountField { 128 | POSITIONS = "positions", 129 | ORDERS = "orders", 130 | } 131 | 132 | 133 | /** 134 | * Gets account info for a single account. You can request additional fields with config.fields as a comma-separated string 135 | * or as an array of string or an array of EGetAccountField 136 | * Possible values for fields are: positions, orders (or EGetAccountField.POSITIONS and .ORDERS) 137 | * Not rate limited so never queued unless specifically overridden. 138 | */ 139 | export async function getAccount(config: IGetAccountConfig): Promise { 140 | let fields = config.fields; 141 | if (Array.isArray(config.fields)) fields = config.fields.join(","); 142 | config.path = `/v1/accounts/${config.accountId}` + 143 | (fields ? `?fields=${fields}` : ""); 144 | return await apiGet({ queueSettings: { enqueue: false }, ...config }); 145 | } 146 | 147 | /** 148 | * Gets account info for all accounts associated to your auth info. You can request additional fields with config.fields as a comma-separated string 149 | * or as an array of string or an array of EGetAccountField 150 | * Possible values for fields are: positions, orders (or EGetAccountField.POSITIONS and .ORDERS) 151 | * Not rate limited so never queued unless specifically overridden. 152 | */ 153 | export async function getAccounts(config?: IGetAccountsConfig): Promise { 154 | config = config ?? {}; 155 | let fields = config.fields; 156 | if (Array.isArray(config.fields)) fields = config.fields.join(","); 157 | config.path = `/v1/accounts` + 158 | (fields ? `?fields=${fields}` : ""); 159 | return await apiGet({ queueSettings: { enqueue: false }, ...config }); 160 | } 161 | -------------------------------------------------------------------------------- /src/cli/accounts-cli.ts: -------------------------------------------------------------------------------- 1 | import {Arguments} from "yargs"; 2 | import {getAccount, getAccounts} from "../accounts"; 3 | 4 | export default { 5 | command: `accounts `, 6 | desc: "Get your account info for one or all linked accounts", 7 | builder: (yargs: any): any => { 8 | return yargs 9 | .command("get ", 10 | "Get account info that returns data based on . Fields is a common-separated string like \"positions,orders\"", 11 | {}, 12 | async (argv: Arguments) => { 13 | if (argv.verbose) { 14 | console.log("getting account info for account %s with fields %s", argv.accountId, argv.fields); 15 | } 16 | return getAccount({ 17 | accountId: argv.accountId as string, 18 | fields: argv.fields as string, 19 | verbose: String(argv.verbose) === "true", 20 | path: "", 21 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 22 | }) 23 | .command("getall ", 24 | "Get account info for all connected accounts. Data returned is based on , a common-separated string like \"positions,orders\"", 25 | {}, 26 | async (argv: Arguments) => { 27 | if (String(argv.verbose) === "true") { 28 | console.log("getting account info for all linked accounts fields %s", argv.fields); 29 | } 30 | return getAccounts({ 31 | fields: argv.fields as string, 32 | verbose: String(argv.verbose) === "true", 33 | path: "", 34 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 35 | }); 36 | }, 37 | handler: (argv: Arguments): void => { /* no op */ }, 38 | }; 39 | -------------------------------------------------------------------------------- /src/cli/authentication-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getAPIAuthentication, refreshAPIAuthentication, refreshAPIAuthorization} from "../tdapiinterface"; 5 | 6 | export default { 7 | command: "auth ", 8 | desc: "Perform some authentication operations", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get", 12 | "Gets the current authentication data that is locally stored, and refreshes the access_token if expired", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting local auth data`); 17 | } 18 | return getAPIAuthentication({ verbose: String(argv.verbose) === "true" }) 19 | .then(data => JSON.stringify(data, null, 2)) 20 | .then(console.log) 21 | .catch(console.log); 22 | }) 23 | .command("refresh", 24 | "Forces a refresh of the access_token and returns the current authentication data that is locally stored", 25 | {}, 26 | async (argv: Arguments) => { 27 | if (argv.verbose) { 28 | console.log(`forcing auth refresh and getting local auth data`); 29 | } 30 | return refreshAPIAuthentication({ verbose: String(argv.verbose) === "true" }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 31 | }) 32 | .command("authorize", 33 | "Forces a refresh of the access_token and returns the current authentication data that is locally stored", 34 | {}, 35 | async (argv: Arguments) => { 36 | if (argv.verbose) { 37 | console.log(`forcing auth refresh and getting local auth data`); 38 | } 39 | return refreshAPIAuthorization({ verbose: String(argv.verbose) === "true" }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 40 | }); 41 | }, 42 | handler: (argv: Arguments): void => { /* no op */ }, 43 | }; 44 | -------------------------------------------------------------------------------- /src/cli/instruments-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {EProjectionType, getInstrument, searchInstruments} from "../instruments"; 5 | 6 | export default { 7 | command: "instruments ", 8 | desc: "Search for an instrument with a text string, or get an instrument by CUSIP", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("search [apikey]", 12 | "Search for an instrument using search string and search type indicated by (one of symbol-search, symbol-regex, desc-search, desc-regex, fundamental), can optionally use apikey for unauthenticated request", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`searching instruments for ${argv.symbol} with search type ${argv.projection}`); 17 | } 18 | return searchInstruments({ 19 | symbol: argv.symbol as string, 20 | projection: argv.projection as EProjectionType, 21 | verbose: String(argv.verbose) === "true", 22 | apikey: argv.apikey ? String(argv.apikey) : "", 23 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 24 | }) 25 | .command("get [apikey]", 26 | "Get an instrument by CUSIP (unique id number assigned to all stocks and registered bonds in US/CA). List here: https://www.sec.gov/divisions/investment/13flists.htm , can use for delayed data", 27 | {}, 28 | async (argv: Arguments) => { 29 | if (argv.verbose) { 30 | console.log(`getting instrument info for cusip ${argv.cusip}`); 31 | } 32 | return getInstrument({ 33 | cusip: argv.cusip as string, 34 | apikey: argv.apikey ? String(argv.apikey) : "", 35 | verbose: String(argv.verbose) === "true", 36 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 37 | }); 38 | }, 39 | handler: (argv: Arguments): void => { /* no op */ }, 40 | }; 41 | -------------------------------------------------------------------------------- /src/cli/markethours-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getMultipleMarketHours, getSingleMarketHours} from "../markethours"; 5 | 6 | export default { 7 | command: "hours ", 8 | desc: "Get market hours", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get [apikey]", 12 | "Get market open hours for a specified date (e.g. 2020-09-18) and a comma-separated set of from EQUITY, OPTION, FUTURE, BOND, or FOREX, e.g. \"EQUITY,OPTION\". Including your optional makes an unauthenticated request.", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting market hours for ${argv.date} for markets ${argv.markets}`); 17 | } 18 | return getMultipleMarketHours({ 19 | markets: argv.markets as string, 20 | date: argv.date as string, 21 | apikey: argv.apikey as string, 22 | verbose: String(argv.verbose) === "true", 23 | path: "", 24 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 25 | }) 26 | .command("getone [apikey]", 27 | "Get market open hours for a specified date and a single from EQUITY, OPTION, FUTURE, BOND, or FOREX. Including your optional makes an unauthenticated request.", 28 | {}, 29 | async (argv: Arguments) => { 30 | if (argv.verbose) { 31 | console.log(`getting market hours for ${argv.date} for market ${argv.market}`); 32 | } 33 | return getSingleMarketHours({ 34 | market: argv.market as string, 35 | date: argv.date as string, 36 | apikey: argv.apikey as string, 37 | verbose: String(argv.verbose) === "true", 38 | path: "", 39 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 40 | }); 41 | }, 42 | handler: (argv: Arguments): void => { /* no op */ }, 43 | }; 44 | -------------------------------------------------------------------------------- /src/cli/movers-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {EChange, EDirection, getMovers, EIndex} from "../movers"; 5 | 6 | export default { 7 | command: "movers ", 8 | desc: "Get market movers", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get [apikey]", 12 | `Get market movers for a specified ('$COMPX', '$DJI', '$SPX.X'), a given ('up', 'down'), and the type of ('value', 'percent'), e.g. "get \\$DJI up percent" (notice the escape character). Optionally takes an apikey for an unathenticated request.`, 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting market movers for ${argv.majorIndex}, moving ${argv.direction} by ${argv.change}`); 17 | } 18 | return getMovers({ 19 | index: EIndex[argv.majorIndex as keyof typeof EIndex], 20 | direction: EDirection[argv.direction as keyof typeof EDirection], 21 | change: EChange[argv.change as keyof typeof EChange], 22 | verbose: String(argv.verbose) === "true", 23 | apikey: argv.apikey as string, 24 | path: "", 25 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 26 | }); 27 | }, 28 | handler: (argv: Arguments): void => { /* no op */ }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/cli/pricehistory-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getPriceHistory} from "../pricehistory"; 5 | 6 | export default { 7 | command: "pricehistory ", 8 | desc: "Get price history info in the form of candles data", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get ", 12 | "Get price history info in the form of candles data for a particular ", 13 | { 14 | apikey: { 15 | alias: "a", 16 | type: "string", 17 | desc: "Your OAuth User ID to make an unauthenticated request for delayed data, e.g. ABC@AMER.OAUTHAP", 18 | }, 19 | from: { 20 | alias: "f", 21 | type: "string", 22 | desc: "Start date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided.", 23 | }, 24 | to: { 25 | alias: "t", 26 | type: "string", 27 | desc: "End date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided. Default is previous trading day.", 28 | }, 29 | needExtendedHoursData: { 30 | alias: "x", 31 | type: "string", 32 | desc: "Include price data from market extended hours (pre 9:30A and post 4P Eastern)", 33 | default: "true", 34 | choices: ["false", "true"], 35 | }, 36 | periodtype: { 37 | alias: "p", 38 | type: "string", 39 | desc: "The type of period by which to group price data (which will be subdivided into candles by FREQUENCY_TYPE)", 40 | default: "day", 41 | choices: ["day", "month", "year", "ytd"], 42 | }, 43 | period: { 44 | alias: "d", 45 | type: "number", 46 | desc: "(Use period OR from and to dates) The number of periods to show. Acceptable values based on PERIOD_TYPE, defaults marked with asterisk. day (1,2,3,4,5,10*), month(1*,2,3,6), year (1*,2,3,5,10,15,20), ytd (1*)", 47 | choices: [1, 2, 3, 4, 5, 6, 10, 15, 20], 48 | }, 49 | frequencytype: { 50 | alias: "c", 51 | type: "string", 52 | desc: "The type of frequency for the price candles. Valid FREQUENCY_TYPEs by PERIOD_TYPE (defaults are *): day (minute*), month (daily, weekly*), year (daily, weekly, monthly*), ytd (daily, weekly*)", 53 | choices: ["minute", "daily", "weekly", "monthly"], 54 | }, 55 | frequency: { 56 | alias: "q", 57 | type: "number", 58 | desc: "How many units of the FREQUENCY_TYPE make up a candle. Valid frequencies by FREQUENCY_TYPE are (default are *): minute (1*,5,10,15,30), daily (1*), weekly (1*), monthly (1*)", 59 | default: 1, 60 | choices: [1, 5, 10, 15, 30], 61 | }, 62 | }, 63 | async (argv: Arguments) => { 64 | if (argv.verbose) { 65 | console.log(`getting price history for ${argv.symbol}`); 66 | } 67 | 68 | return getPriceHistory({ 69 | symbol: argv.symbol as string, 70 | periodType: argv.PERIOD_TYPE ? String(argv.PERIOD_TYPE) : "", 71 | period: argv.period ? Number(argv.period) : (argv.from ? undefined : (argv.PERIOD_TYPE === "day" ? 10 : 1)), 72 | frequencyType: argv.FREQUENCY_TYPE ? String(argv.FREQUENCY_TYPE) : "", 73 | frequency: parseInt(argv.frequency as string), 74 | startDate: argv.from ? Number(argv.from) : undefined, 75 | endDate: argv.to ? Number(argv.to) : undefined, 76 | getExtendedHours: String(argv.needExtendedHoursData) === "true", 77 | verbose: String(argv.verbose) === "true", 78 | apikey: argv.apikey ? String(argv.apikey) : undefined, 79 | path: "", 80 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 81 | }); 82 | }, 83 | handler: (argv: Arguments): void => { /* no op */ }, 84 | }; 85 | -------------------------------------------------------------------------------- /src/cli/quotes-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getQuotes} from "../quotes"; 5 | 6 | export default { 7 | command: "quotes ", 8 | desc: "Get quotes for one or more symbols", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get [apikey]", 12 | "Get quotes for one or more symbols using a comma-separated string, e.g. F,O,TSLA and may optionally use your apikey for an unauthenticated delayed request", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting quotes for ${argv.symbols}`); 17 | } 18 | return getQuotes({ 19 | symbol: argv.symbols as string, 20 | apikey: argv.apikey ? String(argv.apikey) : "", 21 | verbose: String(argv.verbose) === "true", 22 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 23 | }); 24 | }, 25 | handler: (argv: Arguments): void => { /* no op */ }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/cli/savedorders-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {createSavedOrder, deleteSavedOrder, getSavedOrderById, getSavedOrders, replaceSavedOrder} from "../savedorders"; 5 | 6 | export default { 7 | command: "savedorders ", 8 | desc: "Manage your saved orders", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("create ", 12 | "Create a saved order for a specified using the properly formatted (enclose in quotes, escape inner quotes, e.g. \"{\\\"orderType\\\":\\\"MARKET\\\"}\" )", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`creating a saved order for ${argv.accountId}`); 17 | } 18 | return createSavedOrder({ 19 | accountId: argv.accountId as string, 20 | orderJSON: (typeof (argv.orderJSON) === "string" ? JSON.parse(argv.orderJSON) : argv.orderJSON), 21 | verbose: String(argv.verbose) === "true", 22 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 23 | }) 24 | .command("replace ", 25 | "Replace an existing saved order with for a specified using the properly formatted (enclose in quotes, escape inner quotes, e.g. \"{\\\"orderType\\\":\\\"MARKET\\\"}\" )", 26 | {}, 27 | async (argv: Arguments) => { 28 | if (argv.verbose) { 29 | console.log(`replacing saved order ${argv.savedOrderId} for ${argv.accountId}`); 30 | } 31 | return replaceSavedOrder({ 32 | accountId: argv.accountId as string, 33 | orderJSON: (typeof (argv.orderJSON) === "string" ? JSON.parse(argv.orderJSON) : argv.orderJSON), 34 | savedOrderId: argv.savedOrderId as string, 35 | verbose: String(argv.verbose) === "true", 36 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 37 | }) 38 | .command("get ", 39 | "Get saved order info for a specified for a given ", 40 | {}, 41 | async (argv: Arguments) => { 42 | if (argv.verbose) { 43 | console.log(`getting saved order details for order ${argv.savedOrderId} for account ${argv.accountId}`); 44 | } 45 | return getSavedOrderById({ 46 | accountId: argv.accountId as string, 47 | savedOrderId: argv.savedOrderId as string, 48 | verbose: String(argv.verbose) === "true", 49 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 50 | }) 51 | .command("delete ", 52 | "Delete a specified saved order with for a given ", 53 | {}, 54 | async (argv: Arguments) => { 55 | if (argv.verbose) { 56 | console.log(`deleting saved order ${argv.savedOrderId} for account ${argv.accountId}`); 57 | } 58 | return deleteSavedOrder({ 59 | accountId: argv.accountId as string, 60 | savedOrderId: argv.savedOrderId as string, 61 | verbose: String(argv.verbose) === "true", 62 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 63 | }) 64 | .command("getall ", 65 | "Get all saved orders for a given ", 66 | {}, 67 | async (argv: Arguments) => { 68 | if (argv.verbose) { 69 | console.log(`getting all saved order details account ${argv.accountId}`); 70 | } 71 | return getSavedOrders({ 72 | accountId: argv.accountId as string, 73 | verbose: String(argv.verbose) === "true", 74 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 75 | }); 76 | }, 77 | handler: (argv: Arguments): void => { /* no op */ }, 78 | }; 79 | -------------------------------------------------------------------------------- /src/cli/transactions-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getTransaction, getTransactions, ETransactionType} from "../transactions"; 5 | 6 | export default { 7 | command: "trans ", 8 | desc: "Retrieve transaction history", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("get ", 12 | "Get a specific transaction by for a specific ", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting transaction ${argv.transactionId} for ${argv.accountId}`); 17 | } 18 | return getTransaction({ 19 | accountId: argv.accountId as string, 20 | transactionId: argv.transactionId as string, 21 | verbose: String(argv.verbose) === "true", 22 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 23 | }) 24 | .command("getall ", 25 | "Get all transactions for a specific and with the set options, such as type, from, to, symbol", 26 | { 27 | type: { 28 | type: "string", 29 | choices: Object.keys(ETransactionType), 30 | }, 31 | from: { 32 | type: "string", 33 | desc: "date, e.g. 2020-11-22", 34 | }, 35 | to: { 36 | type: "string", 37 | desc: "date, e.g. 2020-11-29", 38 | }, 39 | symbol: { 40 | type: "string", 41 | desc: "ticker symbol, e.g. TSLA", 42 | }, 43 | }, 44 | async (argv: Arguments) => { 45 | if (argv.verbose) { 46 | console.log(`getting transactions for ${argv.accountId}`); 47 | } 48 | return getTransactions({ 49 | accountId: argv.accountId as string, 50 | verbose: String(argv.verbose) === "true", 51 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 52 | }); 53 | 54 | }, 55 | handler: (argv: Arguments): any => { /* no op */ }, 56 | }; 57 | -------------------------------------------------------------------------------- /src/cli/userinfo-cli.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {Arguments} from "yargs"; 4 | import {getStreamerSubKeys, getUserPreferences, getUserPrincipals, updateUserPreferences} from "../userinfo"; 5 | 6 | export default { 7 | command: "userinfo ", 8 | desc: "Get and update user information such as preferences and keys", 9 | builder: (yargs: any): any => { 10 | return yargs 11 | .command("principals [fields]", 12 | "Get user info. Return additional fields with the [fields] param, a comma-separated string of up to 4 fields: streamerSubscriptionKeys, streamerConnectionInfo, preferences, surrogateIds", 13 | {}, 14 | async (argv: Arguments) => { 15 | if (argv.verbose) { 16 | console.log(`getting principal data with extra fields: ${argv.fields || ""}`); 17 | } 18 | return getUserPrincipals({ 19 | fields: argv.fields ? String(argv.fields) : "", 20 | verbose: String(argv.verbose) === "true", 21 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 22 | }) 23 | .command("pref ", 24 | "Get user preferences for a given ", 25 | {}, 26 | async (argv: Arguments) => { 27 | if (argv.verbose) { 28 | console.log(`getting user preferences for account ${argv.accountId}`); 29 | } 30 | return getUserPreferences({ 31 | accountId: argv.accountId as string, 32 | verbose: String(argv.verbose) === "true", 33 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 34 | }) 35 | .command("streamerkeys ", 36 | "Get streamer subscription keys for given as a comma-separated list: 123,345", 37 | {}, 38 | async (argv: Arguments) => { 39 | if (argv.verbose) { 40 | console.log(`getting streamer sub keys for accounts ${argv.accountIds}`); 41 | } 42 | return getStreamerSubKeys({ 43 | accountIds: argv.accountIds as string, 44 | verbose: String(argv.verbose) === "true", 45 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 46 | }) 47 | .command("updateprefs ", 48 | "Update user preferences for a given using (on command line, enclose JSON in quotes, escape inner quotes, e.g. \"{\\\"prop1\\\":\\\"abc\\\"}\" )", 49 | {}, 50 | async (argv: Arguments) => { 51 | if (argv.verbose) { 52 | console.log(`updating preferences for account ${argv.accountId}`); 53 | } 54 | return updateUserPreferences({ 55 | accountId: argv.accountId as string, 56 | preferences: (typeof (argv.preferencesJSON) === "string" ? JSON.parse(argv.preferencesJSON) : argv.preferencesJSON), 57 | verbose: String(argv.verbose) === "true", 58 | }).then(data => JSON.stringify(data, null, 2)).then(console.log).catch(console.log); 59 | }); 60 | 61 | }, 62 | handler: (argv: Arguments): void => { /* no op */ }, 63 | }; 64 | -------------------------------------------------------------------------------- /src/cli_index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Copyright (C) 2020-2 Aaron Satterlee 3 | 4 | import yargs, { terminalWidth } from "yargs"; 5 | import { hideBin } from "yargs/helpers"; 6 | import accountsCli from "./cli/accounts-cli"; 7 | import authenticationCli from "./cli/authentication-cli"; 8 | import instrumentsCli from "./cli/instruments-cli"; 9 | import markethoursCli from "./cli/markethours-cli"; 10 | import moversCli from "./cli/movers-cli"; 11 | import optionschainCli from "./cli/optionschain-cli"; 12 | import ordersCli from "./cli/orders-cli"; 13 | import pricehistoryCli from "./cli/pricehistory-cli"; 14 | import quotesCli from "./cli/quotes-cli"; 15 | import savedordersCli from "./cli/savedorders-cli"; 16 | import transactionsCli from "./cli/transactions-cli"; 17 | import userinfoCli from "./cli/userinfo-cli"; 18 | import watchlistsCli from "./cli/watchlists-cli"; 19 | 20 | yargs(hideBin(process.argv)) 21 | // .commandDir("cli", { extensions: ["js, ts"]}) 22 | .command(accountsCli) 23 | .command(authenticationCli) 24 | .command(instrumentsCli) 25 | .command(markethoursCli) 26 | .command(moversCli) 27 | .command(optionschainCli) 28 | .command(ordersCli) 29 | .command(pricehistoryCli) 30 | .command(quotesCli) 31 | .command(savedordersCli) 32 | .command(transactionsCli) 33 | .command(userinfoCli) 34 | .command(watchlistsCli) 35 | .demandCommand() 36 | .help() 37 | .wrap(terminalWidth()) 38 | .option("verbose", {description: "Print to console some extra information", type: "boolean"}) 39 | .argv; 40 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | export * from "./accounts"; 4 | export * from "./instruments"; 5 | export * from "./markethours"; 6 | export * from "./movers"; 7 | export * from "./optionschain"; 8 | export * from "./orders"; 9 | export * from "./pricehistory"; 10 | export * from "./quotes"; 11 | export * from "./savedorders"; 12 | export * from "./sharedTypes"; 13 | export * from "./streamDataTDA"; 14 | export * from "./streamingdatatypes"; 15 | export * from "./streamingutils"; 16 | export * from "./tdapiinterface"; 17 | export * from "./transactions"; 18 | export * from "./userinfo"; 19 | export * from "./watchlists"; 20 | -------------------------------------------------------------------------------- /src/instruments.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import * as path from "path"; 3 | import { 4 | EProjectionType, 5 | getInstrument, 6 | IGetInstrumentConfig, ISearchInstrumentResult, ISearchInstrumentResults, 7 | ISearchInstrumentsConfig, ISearchInstrumentsFundamentalsConfig, searchInstrumentFundamentals, 8 | searchInstruments, 9 | } from "./instruments"; 10 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 11 | 12 | describe("instruments", () => { 13 | test("search instrument", async () => { 14 | expect(testAuthConfig).toBeTruthy(); 15 | 16 | const config: ISearchInstrumentsConfig = { 17 | symbol: "MSFT", 18 | projection: EProjectionType.SYMBOL_SEARCH, 19 | authConfigFileLocation: testauthpath, 20 | }; 21 | const result: ISearchInstrumentResults = await searchInstruments(config); 22 | expect(result).toBeTruthy(); 23 | // @ts-ignore 24 | expect(result["MSFT"].symbol).toBe("MSFT"); 25 | }); 26 | 27 | test("search instrument unauthenticated", async () => { 28 | const config: ISearchInstrumentsConfig = { 29 | symbol: "MSFT", 30 | projection: EProjectionType.SYMBOL_SEARCH, 31 | apikey: testAuthConfig.client_id, 32 | }; 33 | const result: ISearchInstrumentResults = await searchInstruments(config); 34 | expect(result).toBeTruthy(); 35 | // @ts-ignore 36 | expect(result["MSFT"].symbol).toBe("MSFT"); 37 | }); 38 | 39 | test("search instrument with regex", async () => { 40 | expect(testAuthConfig).toBeTruthy(); 41 | 42 | const config: ISearchInstrumentsConfig = { 43 | symbol: "MSF.*", 44 | projection: EProjectionType.SYMBOL_REGEX, 45 | authConfigFileLocation: testauthpath, 46 | }; 47 | const result: ISearchInstrumentResults = await searchInstruments(config); 48 | expect(result).toBeTruthy(); 49 | expect(Array.isArray(Object.keys(result))).toBe(true); 50 | expect(Object.keys(result).length).toBeGreaterThan(0); 51 | // @ts-ignore 52 | expect(result["MSFT"].symbol).toBe("MSFT"); 53 | }); 54 | 55 | test("search instrument with regex unauthenticated", async () => { 56 | const config: ISearchInstrumentsConfig = { 57 | symbol: "MSF.*", 58 | projection: EProjectionType.SYMBOL_REGEX, 59 | apikey: testAuthConfig.client_id, 60 | }; 61 | const result: ISearchInstrumentResults = await searchInstruments(config); 62 | expect(result).toBeTruthy(); 63 | expect(Array.isArray(Object.keys(result))).toBe(true); 64 | expect(Object.keys(result).length).toBeGreaterThan(0); 65 | // @ts-ignore 66 | expect(result["MSFT"].symbol).toBe("MSFT"); 67 | }); 68 | 69 | test("search instrument fundamentals", async () => { 70 | expect(testAuthConfig).toBeTruthy(); 71 | 72 | const config: ISearchInstrumentsFundamentalsConfig = { 73 | symbol: "MSFT", 74 | authConfigFileLocation: testauthpath, 75 | }; 76 | const result: ISearchInstrumentResults = await searchInstrumentFundamentals(config); 77 | expect(result).toBeTruthy(); 78 | // @ts-ignore 79 | expect(result["MSFT"].symbol).toBe("MSFT"); 80 | expect(result["MSFT"].fundamental).toBeTruthy(); 81 | }); 82 | 83 | test("search instrument fundamentals unauthenticated", async () => { 84 | const config: ISearchInstrumentsFundamentalsConfig = { 85 | symbol: "MSFT", 86 | apikey: testAuthConfig.client_id, 87 | }; 88 | const result: ISearchInstrumentResults = await searchInstrumentFundamentals(config); 89 | expect(result).toBeTruthy(); 90 | // @ts-ignore 91 | expect(result["MSFT"].symbol).toBe("MSFT"); 92 | expect(result["MSFT"].fundamental).toBeTruthy(); 93 | }); 94 | 95 | test("get instrument", async () => { 96 | expect(testAuthConfig).toBeTruthy(); 97 | const config: IGetInstrumentConfig = { 98 | cusip: "594918104", 99 | authConfigFileLocation: testauthpath, 100 | }; 101 | const result: ISearchInstrumentResult[] = await getInstrument(config); 102 | expect(result).toBeTruthy(); 103 | // @ts-ignore 104 | expect(result[0].symbol).toBe("MSFT"); 105 | }); 106 | 107 | test("get instrument unauthenticated", async () => { 108 | const config: IGetInstrumentConfig = { 109 | cusip: "594918104", 110 | apikey: testAuthConfig.client_id, 111 | }; 112 | const result: ISearchInstrumentResult[] = await getInstrument(config); 113 | expect(result).toBeTruthy(); 114 | // @ts-ignore 115 | expect(result[0].symbol).toBe("MSFT"); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /src/instruments.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiGet, TacRequestConfig} from "./tdapiinterface"; 4 | import {EAssetType} from "./sharedTypes"; 5 | 6 | export enum EProjectionType { 7 | // Retrieve instrument data of a specific symbol or cusip 8 | SYMBOL_SEARCH = "symbol-search", 9 | // Retrieve instrument data for all symbols matching regex. Example: symbol=XYZ.* will return all symbols beginning with XYZ 10 | SYMBOL_REGEX = "symbol-regex", 11 | // Retrieve instrument data for instruments whose description contains the word supplied. Example: symbol=FakeCompany will return all instruments with FakeCompany in the description. 12 | DESC_SEARCH = "desc-search", 13 | // Search description with full regex support. Example: symbol=XYZ.[A-C] returns all instruments whose descriptions contain a word beginning with XYZ followed by a character A through C. 14 | DESC_REGEX = "desc-regex", 15 | // Returns fundamental data for a single instrument specified by exact symbol.' 16 | FUNDAMENTAL = "fundamental", 17 | } 18 | 19 | export interface ISearchInstrumentResult { 20 | assetType: EAssetType, 21 | cusip: string, 22 | symbol: string, 23 | description: string, 24 | exchange: string, 25 | fundamental?: IFundamental, 26 | bondPrice?: number, 27 | } 28 | 29 | export interface IFundamental { 30 | high52: number, // double 31 | low52: number, // double 32 | dividendAmount: number, // double 33 | dividendYield: number, // double 34 | dividendDate: string, 35 | peRatio: number, // double 36 | pegRatio: number, // double 37 | pbRatio: number, // double 38 | prRatio: number, // double 39 | pcfRatio: number, // double 40 | grossMarginTTM: number, // double 41 | grossMarginMRQ: number, // double 42 | netProfitMarginTTM: number, // double 43 | netProfitMarginMRQ: number, // double 44 | operatingMarginTTM: number, // double 45 | operatingMarginMRQ: number, // double 46 | returnOnEquity: number, // double 47 | returnOnAssets: number, // double 48 | returnOnInvestment: number, // double 49 | quickRatio: number, // double 50 | currentRatio: number, // double 51 | interestCoverage: number, // double 52 | totalDebtToCapital: number, // double 53 | ltDebtToEquity: number, // double 54 | totalDebtToEquity: number, // double 55 | epsTTM: number, // double 56 | epsChangePercentTTM: number, // double 57 | epsChangeYear: number, // double 58 | epsChange: number, // double 59 | revChangeYear: number, // double 60 | revChangeTTM: number, // double 61 | revChangeIn: number, // double 62 | sharesOutstanding: number, // double 63 | marketCapFloat: number, // double 64 | marketCap: number, // double 65 | bookValuePerShare: number, // double 66 | shortIntToFloat: number, // double 67 | shortIntDayToCover: number, // double 68 | divGrowthRate3Year: number, // double 69 | dividendPayAmount: number, // double 70 | dividendPayDate: string, 71 | beta: number, // double 72 | vol1DayAvg: number, // double 73 | vol10DayAvg: number, // double 74 | vol3MonthAvg: number, // double 75 | } 76 | 77 | export interface ISearchInstrumentsFundamentalsConfig extends TacRequestConfig { 78 | symbol: string, 79 | } 80 | 81 | export interface ISearchInstrumentsConfig extends ISearchInstrumentsFundamentalsConfig { 82 | projection: EProjectionType, 83 | } 84 | 85 | export interface IGetInstrumentConfig extends TacRequestConfig { 86 | cusip: string, 87 | } 88 | 89 | export interface ISearchInstrumentResults { 90 | [key: string]: ISearchInstrumentResult, 91 | } 92 | 93 | /** 94 | * Search for an instrument using search string or regex (config.symbol) and search type (config.projection) 95 | * Projection (you may use enum EProjectionType) is one of: symbol-search, symbol-regex, desc-search, desc-regex, fundamental. 96 | * Can optionally use apikey for delayed data with an unauthenticated request. 97 | */ 98 | export async function searchInstruments(config: ISearchInstrumentsConfig): Promise { 99 | config.path = `/v1/instruments` 100 | + `?symbol=${config.symbol}` 101 | + `&projection=${config.projection}` 102 | + (config.apikey ? `&apikey=${config.apikey}` : ""); 103 | return await apiGet(config); 104 | } 105 | 106 | /** 107 | * This is specifically a shortcut for getting fundamental data for a particular symbol, which can also be achieved 108 | * by calling searchInstruments() with config.projection = EProjectionType.FUNDAMENTAL. The availability of this 109 | * feature seemed less obvious behind the name "searchInstruments" 110 | * Can optionally use apikey for delayed data with an unauthenticated request. 111 | */ 112 | export async function searchInstrumentFundamentals(config: ISearchInstrumentsFundamentalsConfig): Promise { 113 | config.path = `/v1/instruments` 114 | + `?symbol=${config.symbol}` 115 | + `&projection=${EProjectionType.FUNDAMENTAL}` 116 | + (config.apikey ? `&apikey=${config.apikey}` : ""); 117 | return await apiGet(config); 118 | } 119 | 120 | /** 121 | * Get an instrument by CUSIP (unique id number assigned to all stocks and registered bonds in US/CA). 122 | * List of instruments here: https://www.sec.gov/divisions/investment/13flists.htm 123 | * Can optionally use apikey for delayed data with an unauthenticated request. 124 | */ 125 | export async function getInstrument(config: IGetInstrumentConfig): Promise { 126 | config.path = `/v1/instruments/${config.cusip}` 127 | + (config.apikey ? `?apikey=${config.apikey}` : ""); 128 | return await apiGet(config); 129 | } 130 | -------------------------------------------------------------------------------- /src/markethours.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EMarkets, 3 | getMultipleMarketHours, 4 | getSingleMarketHours, 5 | IGetMultiMarketHoursConfig, 6 | IGetSingleMarketHoursConfig, 7 | IMarketMarketHours, 8 | } from "./markethours"; 9 | 10 | import testAuthConfig from "./test_tdaclientauth.json"; 11 | import * as path from "path"; 12 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 13 | 14 | describe("markethours", () => { 15 | test("get single market hours", async () => { 16 | expect(testAuthConfig).toBeTruthy(); 17 | 18 | const config: IGetSingleMarketHoursConfig = { 19 | market: EMarkets.EQUITY, 20 | date: new Date().toISOString().substring(0, 10), 21 | authConfigFileLocation: testauthpath, 22 | }; 23 | const result: IMarketMarketHours = await getSingleMarketHours(config); 24 | expect(result).toBeTruthy(); 25 | 26 | expect(Object.keys(result).length).toBe(1); 27 | const topLevelKey = Object.keys(result)[0]; 28 | expect(Object.keys(result[topLevelKey]).length).toBe(1); 29 | const secondLevelKey = Object.keys(result[topLevelKey])[0]; 30 | 31 | const hours = result[topLevelKey][secondLevelKey]; 32 | expect(hours.date).toBe(config.date); 33 | }); 34 | 35 | test("get single market hours unauthenticated", async () => { 36 | const config: IGetSingleMarketHoursConfig = { 37 | market: EMarkets.EQUITY, 38 | date: new Date().toISOString().substring(0, 10), 39 | apikey: testAuthConfig.client_id, 40 | }; 41 | const result: IMarketMarketHours = await getSingleMarketHours(config); 42 | expect(result).toBeTruthy(); 43 | 44 | expect(Object.keys(result).length).toBe(1); 45 | const topLevelKey = Object.keys(result)[0]; 46 | expect(Object.keys(result[topLevelKey]).length).toBe(1); 47 | const secondLevelKey = Object.keys(result[topLevelKey])[0]; 48 | 49 | const hours = result[topLevelKey][secondLevelKey]; 50 | expect(hours.date).toBe(config.date); 51 | }); 52 | 53 | test("get multiple market hours", async () => { 54 | expect(testAuthConfig).toBeTruthy(); 55 | 56 | const config: IGetMultiMarketHoursConfig = { 57 | markets: [EMarkets.EQUITY, EMarkets.BOND, EMarkets.FOREX, EMarkets.OPTION, EMarkets.FUTURE], 58 | date: new Date().toISOString().substring(0, 10), 59 | authConfigFileLocation: testauthpath, 60 | }; 61 | const result: IMarketMarketHours = await getMultipleMarketHours(config); 62 | expect(result).toBeTruthy(); 63 | 64 | expect(Object.keys(result).length).toBe(5); 65 | expect(Object.keys(result).sort().join(",")).toBe("bond,equity,forex,future,option"); 66 | }); 67 | 68 | test("get multiple market hours unauthenticated", async () => { 69 | const config: IGetMultiMarketHoursConfig = { 70 | markets: [EMarkets.EQUITY, EMarkets.BOND, EMarkets.FOREX, EMarkets.OPTION, EMarkets.FUTURE], 71 | date: new Date().toISOString().substring(0, 10), 72 | apikey: testAuthConfig.client_id, 73 | }; 74 | const result: IMarketMarketHours = await getMultipleMarketHours(config); 75 | expect(result).toBeTruthy(); 76 | 77 | expect(Object.keys(result).length).toBe(5); 78 | expect(Object.keys(result).sort().join(",")).toBe("bond,equity,forex,future,option"); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /src/markethours.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiGet, TacRequestConfig} from "./tdapiinterface"; 4 | 5 | export enum EMarkets { 6 | EQUITY = "EQUITY", 7 | OPTION = "OPTION", 8 | FUTURE = "FUTURE", 9 | BOND = "BOND", 10 | FOREX = "FOREX" 11 | } 12 | 13 | export interface IMarketSession { 14 | start: string, 15 | end: string, 16 | } 17 | 18 | export interface IMarketHours { 19 | category: string, 20 | date: string, 21 | exchange: string, 22 | isOpen: boolean, 23 | marketType: EMarkets, 24 | product: string, 25 | productName: string, 26 | sessionHours: {[index: string]: IMarketSession}, 27 | } 28 | 29 | export interface IProductMarketHours { 30 | [index:string]: IMarketHours 31 | } 32 | 33 | export interface IMarketMarketHours { 34 | [index:string]: IProductMarketHours 35 | } 36 | 37 | export interface IGetSingleMarketHoursConfig extends TacRequestConfig { 38 | market: EMarkets | string, 39 | date: string, 40 | } 41 | 42 | export interface IGetMultiMarketHoursConfig extends TacRequestConfig { 43 | markets: EMarkets[] | string[] | string, 44 | date: string, 45 | } 46 | 47 | /** 48 | * Get market open hours for a specified date in ISO-8601 (yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz) 49 | * (e.g. 2020-09-18) and a specified market (use enum EMarkets). 50 | * Can optionally use apikey for delayed data with an unauthenticated request. 51 | */ 52 | export async function getSingleMarketHours(config: IGetSingleMarketHoursConfig): Promise { 53 | config.path = `/v1/marketdata/${config.market}/hours?date=${config.date}` + 54 | (config.apikey ? `&apikey=${config.apikey}` : ""); 55 | return await apiGet(config); 56 | } 57 | 58 | /** 59 | * Get market open hours for a specified date (e.g. 2020-09-18) and a set of markets. 60 | * Markets can be an array of EMarkets (enum), an array of strings, or a string with comma-separated values 61 | * e.g. [EMarkets.EQUITY, EMarkets.OPTION] or ["EQUITY","OPTION"] or "EQUITY,OPTION". 62 | * Can optionally use apikey for delayed data with an unauthenticated request. 63 | */ 64 | export async function getMultipleMarketHours(config: IGetMultiMarketHoursConfig): Promise { 65 | const markets = Array.isArray(config.markets) ? config.markets.join(",") : config.markets; 66 | config.path = `/v1/marketdata/hours?markets=${markets}&date=${config.date}` + 67 | (config.apikey ? `&apikey=${config.apikey}` : ""); 68 | return await apiGet(config); 69 | } 70 | -------------------------------------------------------------------------------- /src/movers.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import {EChange, EDirection, EIndex, getMovers, IGetMoversConfig, IMover} from "./movers"; 3 | import * as path from "path"; 4 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 5 | 6 | describe("movers", () => { 7 | test("get single market hours", async () => { 8 | // This test will return an empty array during market closed days 9 | // TODO: check for whether market is open today 10 | // TODO: check whether change and direction are required by TDA 11 | expect(testAuthConfig).toBeTruthy(); 12 | 13 | const config: IGetMoversConfig = { 14 | index: EIndex.SPX, 15 | direction: EDirection.UP, 16 | change: EChange.PERCENT, 17 | authConfigFileLocation: testauthpath, 18 | }; 19 | const result: IMover[] = await getMovers(config); 20 | expect(result).toBeTruthy(); 21 | expect(Array.isArray(result)).toBe(true); 22 | }); 23 | 24 | test("get single market hours unauthenticated", async () => { 25 | // This test will return an empty array during market closed days 26 | // TODO: check for whether market is open today 27 | // TODO: check whether change and direction are required by TDA 28 | 29 | const config: IGetMoversConfig = { 30 | index: EIndex.SPX, 31 | direction: EDirection.UP, 32 | change: EChange.PERCENT, 33 | apikey: testAuthConfig.client_id, 34 | }; 35 | const result: IMover[] = await getMovers(config); 36 | expect(result).toBeTruthy(); 37 | expect(Array.isArray(result)).toBe(true); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/movers.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiGet, TacRequestConfig} from "./tdapiinterface"; 4 | 5 | export enum EIndex { 6 | COMPX = "$COMPX", 7 | DJI = "$DJI", 8 | SPX = "$SPX.X", 9 | } 10 | 11 | export enum EDirection { 12 | UP = "up", 13 | DOWN = "down", 14 | } 15 | 16 | export enum EChange { 17 | PERCENT = "percent", 18 | VALUE = "value", 19 | } 20 | 21 | export interface IGetMoversConfig extends TacRequestConfig { 22 | index: EIndex | string, 23 | direction: EDirection | string, 24 | change: EChange | string, 25 | } 26 | 27 | export interface IMover { 28 | change: number, 29 | description: string, 30 | direction: EDirection | string, 31 | last: number, 32 | symbol: string, 33 | totalVolume: number, 34 | } 35 | 36 | /** 37 | * Get market movers for a specified major index, Nasdaq Composite, Dow, S&P (use enum EIndex) 38 | * a given direction, up or down (use enum EDirection), and the type of change, value or percent (use enum EChange) 39 | * Can optionally use apikey for delayed data with an unauthenticated request. 40 | */ 41 | export async function getMovers(config: IGetMoversConfig): Promise { 42 | config.path = `/v1/marketdata/${config.index}/movers` + 43 | `?direction=${config.direction}` + 44 | `&change=${config.change}` + 45 | (config.apikey ? `&apikey=${config.apikey}` : ""); 46 | return await apiGet(config); 47 | } 48 | -------------------------------------------------------------------------------- /src/optionschain.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import * as path from "path"; 3 | import { 4 | EContractType, 5 | EExpirationMonth, 6 | ERange, 7 | EStrategy, 8 | getOptionChain, 9 | IGetOptionChainConfig, 10 | IOptionChain, IOptionStrategyListItem, 11 | } from "./optionschain"; 12 | 13 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 14 | 15 | describe("optionschain", () => { 16 | test("getOptionChain", async () => { 17 | expect(testAuthConfig).toBeTruthy(); 18 | 19 | const config: IGetOptionChainConfig = { 20 | symbol: "MSFT", 21 | authConfigFileLocation: testauthpath, 22 | }; 23 | const result: IOptionChain = await getOptionChain(config); 24 | expect(result).toBeTruthy(); 25 | expect(result.symbol).toBe("MSFT"); 26 | expect(result.isDelayed).toBe(false); 27 | expect(result.callExpDateMap).toBeTruthy(); 28 | expect(result.putExpDateMap).toBeTruthy(); 29 | }); 30 | 31 | test("getOptionChain unauthenticated", async () => { 32 | expect(testAuthConfig).toBeTruthy(); 33 | 34 | const config: IGetOptionChainConfig = { 35 | symbol: "MSFT", 36 | apikey: testAuthConfig.client_id, 37 | }; 38 | const result: IOptionChain = await getOptionChain(config); 39 | expect(result).toBeTruthy(); 40 | expect(result.symbol).toBe("MSFT"); 41 | expect(result.isDelayed).toBe(true); 42 | expect(result.callExpDateMap).toBeTruthy(); 43 | expect(result.putExpDateMap).toBeTruthy(); 44 | }); 45 | 46 | test("getOptionChain with more options unauthenticated", async () => { 47 | expect(testAuthConfig).toBeTruthy(); 48 | 49 | const strikeCount = 5; 50 | 51 | const config: IGetOptionChainConfig = { 52 | symbol: "MSFT", 53 | expMonth: EExpirationMonth.JAN, 54 | contractType: EContractType.CALL, 55 | strategy: EStrategy.SINGLE, 56 | range: ERange.OTM, 57 | includeQuotes: true, 58 | strikeCount: strikeCount, 59 | fromDate: new Date().toISOString().substring(0, 10), 60 | apikey: testAuthConfig.client_id, 61 | }; 62 | const result: IOptionChain = await getOptionChain(config); 63 | expect(result).toBeTruthy(); 64 | expect(result.symbol).toBe("MSFT"); 65 | expect(result.isDelayed).toBe(true); 66 | expect(result.callExpDateMap).toBeTruthy(); 67 | 68 | // no puts since I asked for calls only 69 | expect(result.putExpDateMap).toBeTruthy(); 70 | expect(Object.keys(result.putExpDateMap).length).toBe(0); 71 | 72 | const expiryDatesDTEs: string[] = Object.keys(result.callExpDateMap); 73 | // confirm 5 strikes per date and that they are OTM 74 | expiryDatesDTEs.forEach(expiry => { 75 | const strikes: string[] = Object.keys(result.callExpDateMap[expiry]); 76 | // 5 strikes 77 | expect(strikes.length).toBe(5); 78 | // strike is OTM 79 | strikes.forEach(s => expect(Number(s) > result.underlyingPrice)); 80 | }); 81 | }); 82 | 83 | test("getOptionChain verticals unauthenticated", async () => { 84 | expect(testAuthConfig).toBeTruthy(); 85 | 86 | const config: IGetOptionChainConfig = { 87 | symbol: "MSFT", 88 | strategy: EStrategy.VERTICAL, 89 | range: ERange.NTM, 90 | includeQuotes: true, 91 | toDate: new Date(Date.now() + 30*24*60*60*1000).toISOString().substring(0, 10), 92 | apikey: testAuthConfig.client_id, 93 | }; 94 | const result: IOptionChain = await getOptionChain(config); 95 | expect(result).toBeTruthy(); 96 | expect(result.symbol).toBe("MSFT"); 97 | expect(result.isDelayed).toBe(true); 98 | 99 | // no calls since I selected a spread strategy 100 | expect(result.callExpDateMap).toBeTruthy(); 101 | expect(Object.keys(result.callExpDateMap).length).toBe(0); 102 | 103 | // no puts since I selected a spread strategy 104 | expect(result.putExpDateMap).toBeTruthy(); 105 | expect(Object.keys(result.putExpDateMap).length).toBe(0); 106 | 107 | expect(result.monthlyStrategyList).toBeTruthy(); 108 | expect(result.monthlyStrategyList?.length).toBeGreaterThan(0); 109 | 110 | expect(result.monthlyStrategyList![0].optionStrategyList.length).toBeGreaterThan(0); 111 | 112 | const oneStratItem: IOptionStrategyListItem = result.monthlyStrategyList![0].optionStrategyList[0]; 113 | expect(oneStratItem.primaryLeg).toBeTruthy(); 114 | expect(oneStratItem.secondaryLeg).toBeTruthy(); 115 | expect(oneStratItem.primaryLeg.putCallInd) 116 | .toBe(oneStratItem.secondaryLeg.putCallInd); 117 | expect(oneStratItem.strategyBid).toBeTruthy(); 118 | expect(oneStratItem.strategyAsk).toBeTruthy(); 119 | }); 120 | }); 121 | -------------------------------------------------------------------------------- /src/orders.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { 3 | cancelOrder, 4 | EOrderDuration, 5 | EOrderStatus, 6 | EOrderType, 7 | generateBuyLimitEquityOrder, 8 | getOrder, getOrdersByAccount, 9 | getOrdersByQuery, 10 | IOrderGet, IOrdersByAccountConfig, 11 | IOrdersByQueryConfig, 12 | IPlaceOrderConfig, 13 | IReplaceOrderConfig, 14 | placeOrder, 15 | replaceOrder, 16 | } from "./orders"; 17 | import {getAccounts} from "./accounts"; 18 | import {IWriteResponse, TacRequestConfig} from "./tdapiinterface"; 19 | 20 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 21 | 22 | jest.setTimeout(20000); 23 | 24 | describe("orders", () => { 25 | let accountId = ""; 26 | const baseConfig: TacRequestConfig = { 27 | verbose: false, 28 | authConfigFileLocation: testauthpath, 29 | }; 30 | 31 | beforeAll(async () => { 32 | // first find an account for placing the order 33 | const accounts = await getAccounts({ 34 | ...baseConfig, 35 | }); 36 | accountId = accounts[0].securitiesAccount.accountId; 37 | }); 38 | 39 | test("placeOrder, replaceOrder, getOrder, cancelOrder", async () => { 40 | expect(baseConfig.authConfigFileLocation).toBeTruthy(); 41 | 42 | // place an order 43 | const config: IPlaceOrderConfig = { 44 | accountId: accountId, 45 | orderJSON: generateBuyLimitEquityOrder({ symbol: "F", price: 2.50, quantity: 1 }), 46 | ...baseConfig, 47 | }; 48 | const result: IWriteResponse = await placeOrder(config); 49 | expect(result).toBeTruthy(); 50 | expect(result.location).toBeTruthy(); 51 | const orderId: string = result.location.substring(result.location.lastIndexOf("/") + 1); 52 | 53 | // verify the order exists 54 | const order: IOrderGet = await getOrder({ 55 | accountId, 56 | orderId, 57 | ...baseConfig, 58 | }); 59 | expect(String(order.orderId)).toBe(String(orderId)); 60 | expect(order.quantity).toBe(1); 61 | expect(order.duration).toBe(EOrderDuration.DAY); 62 | expect(order.orderType).toBe(EOrderType.LIMIT); 63 | expect(order.status).not.toBe(EOrderStatus.CANCELED); 64 | expect(order.price).toBe(2.5); 65 | // @ts-ignore 66 | expect(order?.orderLegCollection[0].instrument.symbol).toBe("F"); 67 | 68 | // next replace an order 69 | const configReplace: IReplaceOrderConfig = { 70 | orderId, 71 | accountId: accountId, 72 | orderJSON: generateBuyLimitEquityOrder({ symbol: "F", price: 3.50, quantity: 1 }), 73 | ...baseConfig, 74 | }; 75 | const resultReplace: IWriteResponse = await replaceOrder(configReplace); 76 | expect(resultReplace).toBeTruthy(); 77 | expect(resultReplace.location).toBeTruthy(); 78 | const orderIdReplace: string = resultReplace.location.substring(resultReplace.location.lastIndexOf("/") + 1); 79 | 80 | // verify the order exists 81 | const orderReplaced: IOrderGet = await getOrder({ 82 | accountId, 83 | orderId: orderIdReplace, 84 | ...baseConfig, 85 | }); 86 | expect(String(orderReplaced.orderId)).toBe(String(orderIdReplace)); 87 | expect(orderReplaced.quantity).toBe(1); 88 | expect(orderReplaced.duration).toBe(EOrderDuration.DAY); 89 | expect(orderReplaced.orderType).toBe(EOrderType.LIMIT); 90 | expect(orderReplaced.status).not.toBe(EOrderStatus.CANCELED); 91 | expect(orderReplaced.price).toBe(3.5); 92 | // @ts-ignore 93 | expect(order?.orderLegCollection[0].instrument.symbol).toBe("F"); 94 | 95 | 96 | // cancel the order 97 | await cancelOrder({ 98 | accountId, 99 | orderId: orderIdReplace, 100 | ...baseConfig, 101 | }); 102 | 103 | // verify the cancel 104 | const orderC: IOrderGet = await getOrder({ 105 | accountId, 106 | orderId: orderIdReplace, 107 | ...baseConfig, 108 | }); 109 | expect(String(orderC.orderId)).toBe(String(orderIdReplace)); 110 | expect(orderC.status).toBe(EOrderStatus.CANCELED); 111 | }); 112 | 113 | test("getOrdersByQuery", async () => { 114 | const config: IOrdersByQueryConfig = { 115 | maxResults: 5, 116 | fromEnteredTime: new Date(Date.now() - 14*24*60*60*1000).toISOString().substring(0, 10), 117 | toEnteredTime: new Date().toISOString().substring(0, 10), 118 | status: EOrderStatus.CANCELED, 119 | ...baseConfig, 120 | }; 121 | const result = await getOrdersByQuery(config); 122 | expect(result).toBeTruthy(); 123 | expect(result.length).toBeGreaterThan(0); 124 | }); 125 | 126 | test("getOrdersByAccount", async () => { 127 | const config: IOrdersByAccountConfig = { 128 | accountId, 129 | maxResults: 5, 130 | fromEnteredTime: new Date(Date.now() - 14*24*60*60*1000).toISOString().substring(0, 10), 131 | toEnteredTime: new Date().toISOString().substring(0, 10), 132 | status: EOrderStatus.CANCELED, 133 | ...baseConfig, 134 | }; 135 | const result = await getOrdersByAccount(config); 136 | expect(result).toBeTruthy(); 137 | expect(result.length).toBeGreaterThan(0); 138 | }); 139 | 140 | }); 141 | -------------------------------------------------------------------------------- /src/pricehistory.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import * as path from "path"; 3 | import { 4 | EFrequencyQtyByFrequencyType, 5 | EFrequencyType, 6 | EFrequencyTypeByPeriodType, 7 | EPeriodQtyByPeriodType, 8 | EPeriodType, 9 | getPriceHistory, IPriceHistory, 10 | IPriceHistoryConfig, 11 | } from "./pricehistory"; 12 | 13 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 14 | 15 | describe("pricehistory", () => { 16 | test("get pricehistory", async () => { 17 | expect(testAuthConfig).toBeTruthy(); 18 | 19 | const config: IPriceHistoryConfig = { 20 | symbol: "MSFT", 21 | periodType: EPeriodType.DAY, 22 | period: EPeriodQtyByPeriodType[EPeriodType.DAY].FIVE, 23 | frequencyType: EFrequencyTypeByPeriodType[EPeriodType.DAY].MINUTE, 24 | frequency: EFrequencyQtyByFrequencyType[EFrequencyType.MINUTE].THIRTY, 25 | getExtendedHours: true, 26 | authConfigFileLocation: testauthpath, 27 | }; 28 | const result: IPriceHistory = await getPriceHistory(config); 29 | expect(result).toBeTruthy(); 30 | expect(result.symbol).toBe("MSFT"); 31 | expect(result.empty).toBe(false); 32 | expect(result.candles.length).toBeGreaterThan(0); 33 | }); 34 | 35 | test("get pricehistory unauthenticated", async () => { 36 | const config: IPriceHistoryConfig = { 37 | symbol: "MSFT", 38 | periodType: EPeriodType.DAY, 39 | period: EPeriodQtyByPeriodType[EPeriodType.DAY].FIVE, 40 | frequencyType: EFrequencyTypeByPeriodType[EPeriodType.DAY].MINUTE, 41 | frequency: EFrequencyQtyByFrequencyType[EFrequencyType.MINUTE].THIRTY, 42 | getExtendedHours: true, 43 | apikey: testAuthConfig.client_id, 44 | }; 45 | const result: IPriceHistory = await getPriceHistory(config); 46 | expect(result).toBeTruthy(); 47 | expect(result.symbol).toBe("MSFT"); 48 | expect(result.empty).toBe(false); 49 | expect(result.candles.length).toBeGreaterThan(0); 50 | }); 51 | 52 | test("get pricehistory with dates", async () => { 53 | expect(testAuthConfig).toBeTruthy(); 54 | 55 | const config: IPriceHistoryConfig = { 56 | symbol: "MSFT", 57 | periodType: EPeriodType.DAY, 58 | frequencyType: EFrequencyTypeByPeriodType[EPeriodType.DAY].MINUTE, 59 | frequency: EFrequencyQtyByFrequencyType[EFrequencyType.MINUTE].THIRTY, 60 | startDate: Date.now() - 5*24*60*60*1000, 61 | endDate: Date.now(), 62 | authConfigFileLocation: testauthpath, 63 | }; 64 | const result: IPriceHistory = await getPriceHistory(config); 65 | expect(result).toBeTruthy(); 66 | expect(result.symbol).toBe("MSFT"); 67 | expect(result.empty).toBe(false); 68 | expect(result.candles.length).toBeGreaterThan(0); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /src/quotes.test.ts: -------------------------------------------------------------------------------- 1 | import testAuthConfig from "./test_tdaclientauth.json"; 2 | import * as path from "path"; 3 | import {getQuote, getQuotes, IGetQuoteConfig, IQuoteResult} from "./quotes"; 4 | 5 | 6 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 7 | 8 | describe("quotes", () => { 9 | test("getquote", async () => { 10 | expect(testAuthConfig).toBeTruthy(); 11 | 12 | const config: IGetQuoteConfig = { 13 | symbol: "MSFT", 14 | authConfigFileLocation: testauthpath, 15 | }; 16 | const result: IQuoteResult = await getQuote(config); 17 | expect(result).toBeTruthy(); 18 | expect(result["MSFT"].symbol).toBe("MSFT"); 19 | expect(result["MSFT"].description).toBeTruthy(); 20 | }); 21 | 22 | test("getquote unauthenticated", async () => { 23 | const config: IGetQuoteConfig = { 24 | symbol: "MSFT", 25 | apikey: testAuthConfig.client_id, 26 | }; 27 | const result: IQuoteResult = await getQuote(config); 28 | expect(result).toBeTruthy(); 29 | expect(result["MSFT"].symbol).toBe("MSFT"); 30 | expect(result["MSFT"].description).toBeTruthy(); 31 | }); 32 | 33 | test("getquotes", async () => { 34 | expect(testAuthConfig).toBeTruthy(); 35 | 36 | const symbols = ["MSFT", "/ES", "EUR/USD", "MSFT_011924C330"]; 37 | const config: IGetQuoteConfig = { 38 | symbol: symbols.join(","), 39 | authConfigFileLocation: testauthpath, 40 | }; 41 | const result: IQuoteResult = await getQuotes(config); 42 | expect(result).toBeTruthy(); 43 | expect(Object.keys(result).sort().join(",")).toBe(symbols.sort().join(",")); 44 | symbols.forEach(s => expect(result[s].symbol).toBe(s)); 45 | }); 46 | 47 | test("getquotes unauthenticated", async () => { 48 | const symbols = ["MSFT", "/ES", "EUR/USD", "MSFT_011924C330"]; 49 | const config: IGetQuoteConfig = { 50 | symbol: symbols.join(","), 51 | apikey: testAuthConfig.client_id, 52 | }; 53 | const result: IQuoteResult = await getQuotes(config); 54 | expect(result).toBeTruthy(); 55 | expect(Object.keys(result).sort().join(",")).toBe(symbols.sort().join(",")); 56 | symbols.forEach(s => expect(result[s].symbol).toBe(s)); 57 | }); 58 | 59 | test("getquotes single symbol unauthenticated", async () => { 60 | const config: IGetQuoteConfig = { 61 | symbol: "MSFT", 62 | apikey: testAuthConfig.client_id, 63 | }; 64 | const result: IQuoteResult = await getQuotes(config); 65 | expect(result).toBeTruthy(); 66 | expect(result["MSFT"].symbol).toBe("MSFT"); 67 | expect(result["MSFT"].description).toBeTruthy(); 68 | }); 69 | 70 | test("getquote using symbol with special character not a good idea", async () => { 71 | const config: IGetQuoteConfig = { 72 | symbol: "EUR/USD", 73 | apikey: testAuthConfig.client_id, 74 | }; 75 | let error; 76 | try { 77 | await getQuote(config); 78 | } catch (e) { 79 | error = e; 80 | } 81 | expect(error).toBeTruthy(); 82 | expect(String(error)).toContain("Bad Request"); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /src/savedorders.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiDelete, apiGet, apiPost, apiPut, IWriteResponse, TacRequestConfig} from "./tdapiinterface"; 4 | import {IOrderGet} from "./orders"; 5 | 6 | export interface ICreateSavedOrderConfig extends TacRequestConfig { 7 | accountId: string | number, 8 | orderJSON: any, 9 | } 10 | 11 | export interface IReplaceSaveOrderConfig extends TacRequestConfig { 12 | accountId: string | number, 13 | savedOrderId: string, 14 | orderJSON: any, 15 | } 16 | 17 | export interface ISimpleSavedOrderConfig extends TacRequestConfig { 18 | accountId: string | number, 19 | savedOrderId: string, 20 | } 21 | 22 | export interface IGetSavedOrdersConfig extends TacRequestConfig { 23 | accountId: string | number, 24 | } 25 | 26 | /** 27 | * Create a saved order for a given account 28 | * The id is part of the uri in the location property of the return object 29 | * See order examples at: https://developer.tdameritrade.com/content/place-order-samples 30 | * Not rate limited so never queued unless specifically overridden. 31 | */ 32 | export async function createSavedOrder(config: ICreateSavedOrderConfig): Promise { 33 | config.bodyJSON = config.orderJSON; 34 | config.path = `/v1/accounts/${config.accountId}/savedorders`; 35 | 36 | return await apiPost({ queueSettings: { enqueue: false }, ...config }); 37 | } 38 | 39 | /** 40 | * Delete a specified saved order for a given account 41 | * Just an acknowledgement response code is returned. 42 | * Not rate limited so never queued unless specifically overridden. 43 | */ 44 | export async function deleteSavedOrder(config: ISimpleSavedOrderConfig): Promise { 45 | config.path = `/v1/accounts/${config.accountId}/savedorders/${config.savedOrderId}`; 46 | return await apiDelete({ queueSettings: { enqueue: false }, ...config }); 47 | } 48 | 49 | /** 50 | * Get a particular saved order for a given account 51 | * Not rate limited so never queued unless specifically overridden. 52 | */ 53 | export async function getSavedOrderById(config: ISimpleSavedOrderConfig): Promise { 54 | config.path = `/v1/accounts/${config.accountId}/savedorders/${config.savedOrderId}`; 55 | return await apiGet({ queueSettings: { enqueue: false }, ...config }); 56 | } 57 | 58 | /** 59 | * Get all saved orders for a given account 60 | * Not rate limited so never queued unless specifically overridden. 61 | */ 62 | export async function getSavedOrders(config: IGetSavedOrdersConfig): Promise { 63 | config.path = `/v1/accounts/${config.accountId}/savedorders`; 64 | return await apiGet({ queueSettings: { enqueue: false }, ...config }); 65 | } 66 | 67 | /** 68 | * Replace an existing saved order for a specified account using the properly formatted orderJSON 69 | * The saved order id will be part of the location uri in the returned object 70 | * See order examples at: https://developer.tdameritrade.com/content/place-order-samples 71 | * Not rate limited so never queued unless specifically overridden. 72 | */ 73 | export async function replaceSavedOrder(config: IReplaceSaveOrderConfig): Promise { 74 | config.bodyJSON = config.orderJSON; 75 | config.path = `/v1/accounts/${config.accountId}/savedorders/${config.savedOrderId}`; 76 | return await apiPut({ queueSettings: { enqueue: false }, ...config }); 77 | } 78 | -------------------------------------------------------------------------------- /src/sharedTypes.ts: -------------------------------------------------------------------------------- 1 | 2 | export enum EAssetType { 3 | EQUITY = "EQUITY", 4 | ETF = "ETF", 5 | FOREX = "FOREX", 6 | FUTURE = "FUTURE", 7 | FUTURE_OPTION = "FUTURE_OPTION", 8 | INDEX = "INDEX", 9 | INDICATOR = "INDICATOR", 10 | MUTUAL_FUND = "MUTUAL_FUND", 11 | OPTION = "OPTION", 12 | UNKNOWN = "UNKNOWN", 13 | CASH_EQUIVALENT = "CASH_EQUIVALENT", 14 | FIXED_INCOME = "FIXED_INCOME", 15 | CURRENCY = "CURRENCY", 16 | } 17 | 18 | export interface IInstrument { 19 | assetType: EAssetType, 20 | cusip?: string, 21 | symbol: string, 22 | description?: string, 23 | exchange?: string, 24 | } 25 | 26 | export type IEquity = IInstrument 27 | 28 | export interface IFixedIncome extends IInstrument { 29 | // "assetType": "'EQUITY' or 'OPTION' or 'INDEX' or 'MUTUAL_FUND' or 'CASH_EQUIVALENT' or 'FIXED_INCOME' or 'CURRENCY'", 30 | // "cusip": "string", 31 | // "symbol": "string", 32 | // "description": "string", 33 | maturityDate: string, // date-time 34 | variableRate: number, // double 35 | factor: number, // double 36 | } 37 | 38 | export interface IMutualFund extends IInstrument { 39 | type: EMutualFundType 40 | } 41 | 42 | export enum EMutualFundType { 43 | NOT_APPLICABLE, 44 | OPEN_END_NON_TAXABLE, 45 | OPEN_END_TAXABLE, 46 | NO_LOAD_NON_TAXABLE, 47 | NO_LOAD_TAXABLE, 48 | } 49 | 50 | export interface ICashEquivalent extends IInstrument { 51 | type: ECashEquivalentType 52 | } 53 | 54 | export interface IBond extends Omit { 55 | bondPrice: number, 56 | assetType: "BOND", 57 | bondMaturityDate: string, 58 | bondInterestRate: number, 59 | } 60 | 61 | export enum ECashEquivalentType { 62 | SAVINGS, 63 | MONEY_MARKET_FUND, 64 | } 65 | 66 | export enum EOptionInstrumentType { 67 | VANILLA, 68 | BINARY, 69 | BARRIER, 70 | } 71 | 72 | export interface IOptionInstrument extends IInstrument { 73 | type: EOptionInstrumentType, 74 | putCall: "PUT" | "CALL", 75 | underlyingSymbol: string, 76 | optionMultiplier: number, // int32 77 | optionDeliverables: IOptionDeliverable[], 78 | optionExpirationDate: string, 79 | optionStrikePrice: number, 80 | } 81 | 82 | export interface IOptionDeliverable { 83 | symbol: string, 84 | deliverableUnits: number, 85 | currencyType: ECurrencyType, 86 | assetType: EAssetType, 87 | } 88 | 89 | export enum ECurrencyType { 90 | USD, 91 | CAD, 92 | EUR, 93 | JPY, 94 | } 95 | 96 | export interface ICandle { 97 | open: number, 98 | high: number, 99 | low: number, 100 | close: number, 101 | volume: number, 102 | datetime: number, 103 | } 104 | -------------------------------------------------------------------------------- /src/transactions.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import {TacRequestConfig} from "./tdapiinterface"; 3 | import { 4 | ETransactionType, 5 | getTransaction, 6 | getTransactions, 7 | IGetTransactionConfig, 8 | IGetTransactionsConfig, 9 | ITransaction, 10 | } from "./transactions"; 11 | import {getAccounts} from "./accounts"; 12 | 13 | describe("transactions", () => { 14 | let accountId = ""; 15 | 16 | const baseConfig: TacRequestConfig = { 17 | verbose: false, 18 | authConfigFileLocation: path.join(__dirname, "test_tdaclientauth.json"), 19 | }; 20 | 21 | beforeAll(async () => { 22 | // first find an account for placing the order 23 | const accounts = await getAccounts({ 24 | ...baseConfig, 25 | }); 26 | accountId = accounts[0].securitiesAccount.accountId; 27 | }); 28 | 29 | test("getTransactions and getTransaction", async () => { 30 | expect(baseConfig.authConfigFileLocation).toBeTruthy(); 31 | 32 | const config: IGetTransactionsConfig = { 33 | ...baseConfig, 34 | accountId, 35 | type: ETransactionType.ALL, 36 | startDate: new Date(Date.now() - 300*24*60*60*1000).toISOString().substring(0, 10), 37 | endDate: new Date().toISOString().substring(0, 10), 38 | }; 39 | const result: ITransaction[] = await getTransactions(config); 40 | expect(result).toBeTruthy(); 41 | expect(Array.isArray(result)).toBe(true); 42 | if (result.length > 0) { 43 | expect(result[0].transactionDate).toBeTruthy(); 44 | expect(result[0].transactionId).toBeTruthy(); 45 | 46 | const config: IGetTransactionConfig = { 47 | ...baseConfig, 48 | accountId, 49 | transactionId: result[0].transactionId, 50 | }; 51 | const resultSingle: ITransaction = await getTransaction(config); 52 | expect(resultSingle).toBeTruthy(); 53 | expect(resultSingle.transactionDate).toBe(result[0].transactionDate); 54 | expect(resultSingle.transactionId).toBe(result[0].transactionId); 55 | } 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/transactions.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020-2 Aaron Satterlee 2 | 3 | import {apiGet, TacRequestConfig} from "./tdapiinterface"; 4 | import {IInstrument} from "./sharedTypes"; 5 | 6 | /** 7 | * Enum for the transaction types 8 | * @enum 9 | */ 10 | export enum ETransactionType { 11 | ALL = "ALL", 12 | TRADE = "TRADE", 13 | BUY_ONLY = "BUY_ONLY", 14 | SELL_ONLY = "SELL_ONLY", 15 | CASH_IN_OR_CASH_OUT = "CASH_IN_OR_CASH_OUT", 16 | CHECKING = "CHECKING", 17 | DIVIDEND = "DIVIDEND", 18 | INTEREST = "INTEREST", 19 | OTHER = "OTHER", 20 | ADVISOR_FEES = "ADVISOR_FEES", 21 | RECEIVE_AND_DELIVER = "RECEIVE_AND_DELIVER", 22 | DIVIDEND_OR_INTEREST = "DIVIDEND_OR_INTEREST", 23 | ACH_RECEIPT = "ACH_RECEIPT", 24 | ACH_DISBURSEMENT = "ACH_DISBURSEMENT", 25 | CASH_RECEIPT = "CASH_RECEIPT", 26 | CASH_DISBURSEMENT = "CASH_DISBURSEMENT", 27 | ELECTRONIC_FUND = "ELECTRONIC_FUND", 28 | WIRE_OUT = "WIRE_OUT", 29 | WIRE_IN = "WIRE_IN", 30 | JOURNAL = "JOURNAL", 31 | MEMORANDUM = "MEMORANDUM", 32 | MARGIN_CALL = "MARGIN_CALL", 33 | MONEY_MARKET = "MONEY_MARKET", 34 | SMA_ADUSTMENT = "SMA_ADUSTMENT", 35 | } 36 | 37 | export enum EAchStatus { 38 | APPROVED = "APPROVED", 39 | REJECTED = "REJECTED", 40 | CANCEL = "CANCEL", 41 | ERROR = "ERROR", 42 | } 43 | 44 | export interface ITransactionItem { 45 | accountId: number, 46 | amount: number, 47 | price: number, 48 | cost: number, 49 | parentOrderKey: number, 50 | parentChildIndicator: string, 51 | instruction: string, 52 | positionEffect: string, 53 | instrument: IInstrument, 54 | } 55 | 56 | export interface ITransaction { 57 | type: ETransactionType, 58 | clearingReferenceNumber: string, 59 | subAccount: string, 60 | settlementDate: string, 61 | orderId: string, 62 | sma: number, 63 | requirementReallocationAmount: number, 64 | dayTradeBuyingPowerEffect: number, 65 | netAmount: number, 66 | transactionDate: string, 67 | orderDate: string, 68 | transactionSubType: string, 69 | transactionId: number, 70 | cashBalanceEffectFlag: boolean, 71 | description: string, 72 | achStatus: EAchStatus, 73 | accruedInterest: number, 74 | fees: {[index:string]: number}, 75 | transactionItem: ITransactionItem[], 76 | } 77 | 78 | export interface IGetTransactionsConfig extends TacRequestConfig { 79 | accountId: string | number, 80 | type?: ETransactionType | string, 81 | symbol?: string, 82 | startDate?: string, 83 | endDate?: string, 84 | } 85 | 86 | export interface IGetTransactionConfig extends TacRequestConfig { 87 | accountId: string | number, 88 | transactionId: string | number, 89 | } 90 | 91 | /** 92 | * Gets all transactions for a specific account with the set options, such as symbol, type, 93 | * startDate (yyyy-MM-dd), endDate (yyyy-MM-dd) (maximum time span is 1 year) 94 | */ 95 | export async function getTransactions(config: IGetTransactionsConfig): Promise { 96 | config.path = `/v1/accounts/${config.accountId}/transactions?` + 97 | (config.type ? `type=${config.type}&` : "") + 98 | (config.startDate ? `startDate=${config.startDate}&` : "") + 99 | (config.endDate ? `endDate=${config.endDate}&` : "") + 100 | (config.symbol ? `symbol=${config.symbol}` : ""); 101 | 102 | return await apiGet(config); 103 | } 104 | 105 | /** 106 | * Get a sepcific transaction for a specified account 107 | */ 108 | export async function getTransaction(config: IGetTransactionConfig): Promise { 109 | config.path = `/v1/accounts/${config.accountId}/transactions/${config.transactionId}`; 110 | 111 | return await apiGet(config); 112 | } 113 | -------------------------------------------------------------------------------- /src/userinfo.test.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import {TacRequestConfig} from "./tdapiinterface"; 3 | import { 4 | EPrefAuthTokenTimeout, 5 | EUserPrincipalFields, 6 | getStreamerSubKeys, 7 | getUserPreferences, getUserPrincipals, 8 | IGetStreamerKeysConfig, 9 | IGetUserPreferencesConfig, 10 | IGetUserPrincipalsConfig, 11 | IPreferences, IPreferencesUpdate, 12 | IStreamerSubKeys, IUpdateUserPrefConfig, IUserPrincipal, updateUserPreferences, 13 | } from "./userinfo"; 14 | import {getAccounts} from "./accounts"; 15 | 16 | const testauthpath = path.join(__dirname, "test_tdaclientauth.json"); 17 | 18 | describe("userinfo", () => { 19 | let accountId = ""; 20 | 21 | const baseConfig: TacRequestConfig = { 22 | verbose: false, 23 | authConfigFileLocation: testauthpath, 24 | }; 25 | 26 | beforeAll(async () => { 27 | // first find an account for placing the order 28 | const accounts = await getAccounts({ 29 | ...baseConfig, 30 | }); 31 | accountId = accounts[0].securitiesAccount.accountId; 32 | }); 33 | 34 | test("getUserPreferences", async () => { 35 | const config: IGetUserPreferencesConfig = { 36 | ...baseConfig, 37 | accountId, 38 | }; 39 | 40 | const result: IPreferences = await getUserPreferences(config); 41 | expect(result).toBeTruthy(); 42 | expect(Object.values(EPrefAuthTokenTimeout)).toContain(result.authTokenTimeout); 43 | }); 44 | 45 | test("getStreamerSubKeys", async () => { 46 | const config: IGetStreamerKeysConfig = { 47 | ...baseConfig, 48 | accountIds: accountId, 49 | }; 50 | 51 | const result: IStreamerSubKeys = await getStreamerSubKeys(config); 52 | expect(result).toBeTruthy(); 53 | expect(result.keys[0].key).toBeTruthy(); 54 | }); 55 | 56 | test("getUserPrincipals", async () => { 57 | const config: IGetUserPrincipalsConfig = { 58 | ...baseConfig, 59 | fields: [ 60 | EUserPrincipalFields.STREAMER_CONNECTION_INFO, 61 | EUserPrincipalFields.PREFERENCES, 62 | EUserPrincipalFields.STREAMER_SUB_KEYS, 63 | EUserPrincipalFields.SURROGATE_IDS, 64 | ], 65 | }; 66 | 67 | const result: IUserPrincipal = await getUserPrincipals(config); 68 | expect(result).toBeTruthy(); 69 | expect(result.accounts.map(acct => acct.accountId)).toContain(accountId); 70 | }); 71 | 72 | test("updateUserPreferences", async () => { 73 | const config: IGetUserPreferencesConfig = { 74 | ...baseConfig, 75 | accountId, 76 | }; 77 | 78 | const result: IPreferences = await getUserPreferences(config); 79 | expect(result).toBeTruthy(); 80 | expect(Object.values(EPrefAuthTokenTimeout)).toContain(result.authTokenTimeout); 81 | 82 | const preferences: IPreferencesUpdate = { 83 | ...result, 84 | }; 85 | // delete the two fields from the get result that can't be updated via this method 86 | // @ts-ignore 87 | delete preferences.directEquityRouting; 88 | // @ts-ignore 89 | delete preferences.directOptionsRouting; 90 | 91 | const updateConfig: IUpdateUserPrefConfig = { 92 | ...baseConfig, 93 | accountId, 94 | preferences, 95 | }; 96 | 97 | await updateUserPreferences(updateConfig); 98 | // at this point we are just expecting a 2XX response 99 | expect(1).toBe(1); 100 | }); 101 | }); 102 | --------------------------------------------------------------------------------