@tastytrade/api 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +4 -4
- package/.vscode/launch.json +7 -11
- package/README.md +76 -0
- package/dist/account-streamer.d.ts +1 -1
- package/dist/account-streamer.js +1 -1
- package/dist/services/accounts-and-customers-service.d.ts +3 -3
- package/dist/services/accounts-and-customers-service.js +6 -6
- package/lib/account-streamer.ts +2 -2
- package/lib/services/accounts-and-customers-service.ts +6 -6
- package/package.json +1 -1
package/.env
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
BASE_URL=https://api.tastyworks.com
|
|
2
|
-
API_USERNAME=
|
|
1
|
+
BASE_URL=https://api.cert.tastyworks.com
|
|
2
|
+
API_USERNAME=devin.moss@tastytrade.com
|
|
3
3
|
API_PASSWORD=rebuke-padding-vizor
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
API_ACCOUNT_NUMBER=5WT05179
|
|
5
|
+
API_CUSTOMER_ID=31
|
package/.vscode/launch.json
CHANGED
|
@@ -7,18 +7,14 @@
|
|
|
7
7
|
{
|
|
8
8
|
"type": "node",
|
|
9
9
|
"request": "launch",
|
|
10
|
-
"name": "
|
|
11
|
-
"skipFiles": [
|
|
10
|
+
"name": "Launch Program",
|
|
11
|
+
"skipFiles": [
|
|
12
|
+
"<node_internals>/**"
|
|
13
|
+
],
|
|
12
14
|
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
|
|
13
|
-
"args": [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"type": "node",
|
|
17
|
-
"request": "launch",
|
|
18
|
-
"name": "Unit Tests",
|
|
19
|
-
"skipFiles": ["<node_internals>/**"],
|
|
20
|
-
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
|
|
21
|
-
"args": ["-i", "--", "tests/unit/service/session-service.test.ts"]
|
|
15
|
+
"args": [
|
|
16
|
+
"-c", "jest.config.js", "tests/integration/service/accounts-and-customers-service.test.ts"
|
|
17
|
+
]
|
|
22
18
|
}
|
|
23
19
|
]
|
|
24
20
|
}
|
package/README.md
CHANGED
|
@@ -1,4 +1,80 @@
|
|
|
1
1
|
# Tastytrade Api Javascript SDK
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
npm:
|
|
5
|
+
`npm -i @tastytrade/api`
|
|
6
|
+
|
|
7
|
+
yarn:
|
|
8
|
+
`yarn add @tastytrade/api`
|
|
9
|
+
|
|
10
|
+
## Quickstart
|
|
11
|
+
```js
|
|
12
|
+
import TastytradeClient from "@tastytrade/api"
|
|
13
|
+
const tastytradeClient = new TastytradeClient(baseUrl, accountStreamerUrl)
|
|
14
|
+
const loginResponse = await tastytradeClient.sessionService.login(usernameOrEmail, pasword)
|
|
15
|
+
const accounts = await tastytradeClient.accountsAndCustomersService.getCustomerAccounts()
|
|
16
|
+
const accountPositions = await tastytradeClient.balancesAndPositionsService.getPositionsList(accounts[0].accounts['account-number'])
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Market Data
|
|
20
|
+
```js
|
|
21
|
+
import TastytradeClient, { QuoteStreamer } from "@tastytrade-api"
|
|
22
|
+
const tastytradeClient = new TastytradeClient(baseUrl, accountStreamerUrl)
|
|
23
|
+
await tastytradeClient.sessionService.login(usernameOrEmail, pasword)
|
|
24
|
+
const tokenResponse = await tastytradeClient.AccountsAndCustomersService.getQuoteStreamerTokens()
|
|
25
|
+
const quoteStreamer = new QuoteStreamer(tokenResponse.token, `${tokenResponse['websocket-url']}/cometd`)
|
|
26
|
+
quoteStreamer.connect()
|
|
27
|
+
|
|
28
|
+
function handleMarketDataReceived(event) {
|
|
29
|
+
// Triggers every time market data event occurs
|
|
30
|
+
console.log(event)
|
|
31
|
+
}
|
|
32
|
+
// Subscribe to a single equity quote
|
|
33
|
+
quoteStreamer.subscribe('AAPL', handleMarketDataReceived)
|
|
34
|
+
|
|
35
|
+
// Subscribe to a single equity option quote
|
|
36
|
+
const optionChain = await tastytradeClient.instrumentsService.getOptionChain('AAPL')
|
|
37
|
+
quoteStreamer.subscribe(optionChain[0]['streamer-symbol'], handleMarketDataReceived)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Account Streamer
|
|
41
|
+
```js
|
|
42
|
+
const TastytradeApi = require("@tastytrade/api")
|
|
43
|
+
const TastytradeClient = TastytradeApi.default
|
|
44
|
+
const { AccountStreamer, QuoteStreamer } = TastytradeApi
|
|
45
|
+
const _ = require('lodash')
|
|
46
|
+
|
|
47
|
+
function handleStreamerMessage(json) {
|
|
48
|
+
console.log('streamer message received: ', json)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function handleStreamerStateChange(streamerState) {
|
|
52
|
+
console.log('streamer state changed: ', streamerState)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const tastytradeClient = new TastytradeClient(baseUrl, accountStreamerUrl)
|
|
56
|
+
const accountStreamer = tastytradeClient.accountStreamer
|
|
57
|
+
const loginResponse = await tastytradeClient.sessionService.login(usernameOrEmail, password)
|
|
58
|
+
const accounts = await tastytradeClient.accountsAndCustomersService.getCustomerAccounts()
|
|
59
|
+
const accountNumbers = _.map(accounts, account => _.get(account, 'account.account-number'))
|
|
60
|
+
await accountStreamer.start()
|
|
61
|
+
await accountStreamer.subscribeToAccounts(accountNumbers)
|
|
62
|
+
accountStreamer.addMessageObserver(handleStreamerMessage)
|
|
63
|
+
accountStreamer.addStreamerStateObserver(handleStreamerStateChange)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
You should then be able to place a trade and see live status updates for the order come through via `handleStreamerMessage`.
|
|
67
|
+
|
|
68
|
+
## Running in Node
|
|
69
|
+
The `cometd` package has an explicit reference to `window`, so there's not a perfect way to run this code in a NodeJs. You could fake the `window` object to get it running. You'll have to `npm install ws` and do this:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
const WebSocket = require('ws')
|
|
73
|
+
|
|
74
|
+
global.WebSocket = WebSocket
|
|
75
|
+
global.window = { WebSocket, setTimeout, clearTimeout }
|
|
76
|
+
```
|
|
77
|
+
|
|
2
78
|
## Building Locally
|
|
3
79
|
`npm run build`
|
|
4
80
|
Outputs everything to `dist/`
|
|
@@ -8,7 +8,7 @@ export declare enum STREAMER_STATE {
|
|
|
8
8
|
}
|
|
9
9
|
export declare type Disposer = () => void;
|
|
10
10
|
export declare type StreamerStateObserver = (streamerState: STREAMER_STATE) => void;
|
|
11
|
-
export declare type StreamerMessageObserver = (
|
|
11
|
+
export declare type StreamerMessageObserver = (json: object) => void;
|
|
12
12
|
export declare class AccountStreamer {
|
|
13
13
|
private readonly url;
|
|
14
14
|
private readonly session;
|
package/dist/account-streamer.js
CHANGED
|
@@ -143,7 +143,7 @@ var AccountStreamer = /** @class */ (function () {
|
|
|
143
143
|
this.handleOneMessage = function (json) {
|
|
144
144
|
_this.logger.info(json);
|
|
145
145
|
var action = json.action;
|
|
146
|
-
_this.streamerMessageObservers.forEach(function (observer) { return observer(json
|
|
146
|
+
_this.streamerMessageObservers.forEach(function (observer) { return observer(json); });
|
|
147
147
|
if (action) {
|
|
148
148
|
if (action === MessageAction.HEARTBEAT) {
|
|
149
149
|
// schedule next heartbeat
|
|
@@ -3,8 +3,8 @@ export default class AccountsAndCustomersService {
|
|
|
3
3
|
private httpClient;
|
|
4
4
|
constructor(httpClient: TastytradeHttpClient);
|
|
5
5
|
getCustomerAccounts(): Promise<any>;
|
|
6
|
-
getCustomerResource(
|
|
7
|
-
getCustomerAccountResources(
|
|
8
|
-
getFullCustomerAccountResource(
|
|
6
|
+
getCustomerResource(): Promise<any>;
|
|
7
|
+
getCustomerAccountResources(): Promise<any>;
|
|
8
|
+
getFullCustomerAccountResource(accountNumber: string): Promise<any>;
|
|
9
9
|
getQuoteStreamerTokens(): Promise<any>;
|
|
10
10
|
}
|
|
@@ -58,12 +58,12 @@ var AccountsAndCustomersService = /** @class */ (function () {
|
|
|
58
58
|
});
|
|
59
59
|
};
|
|
60
60
|
//Customers: Operations about customers
|
|
61
|
-
AccountsAndCustomersService.prototype.getCustomerResource = function (
|
|
61
|
+
AccountsAndCustomersService.prototype.getCustomerResource = function () {
|
|
62
62
|
return __awaiter(this, void 0, void 0, function () {
|
|
63
63
|
var customerResource;
|
|
64
64
|
return __generator(this, function (_a) {
|
|
65
65
|
switch (_a.label) {
|
|
66
|
-
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/"
|
|
66
|
+
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/me", {}, {})];
|
|
67
67
|
case 1:
|
|
68
68
|
customerResource = (_a.sent());
|
|
69
69
|
return [2 /*return*/, (0, response_util_1.default)(customerResource)];
|
|
@@ -71,12 +71,12 @@ var AccountsAndCustomersService = /** @class */ (function () {
|
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
73
|
};
|
|
74
|
-
AccountsAndCustomersService.prototype.getCustomerAccountResources = function (
|
|
74
|
+
AccountsAndCustomersService.prototype.getCustomerAccountResources = function () {
|
|
75
75
|
return __awaiter(this, void 0, void 0, function () {
|
|
76
76
|
var customerAccountResources;
|
|
77
77
|
return __generator(this, function (_a) {
|
|
78
78
|
switch (_a.label) {
|
|
79
|
-
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/
|
|
79
|
+
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/me/accounts", {}, {})];
|
|
80
80
|
case 1:
|
|
81
81
|
customerAccountResources = (_a.sent());
|
|
82
82
|
return [2 /*return*/, (0, response_util_1.default)(customerAccountResources)];
|
|
@@ -84,12 +84,12 @@ var AccountsAndCustomersService = /** @class */ (function () {
|
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
86
|
};
|
|
87
|
-
AccountsAndCustomersService.prototype.getFullCustomerAccountResource = function (
|
|
87
|
+
AccountsAndCustomersService.prototype.getFullCustomerAccountResource = function (accountNumber) {
|
|
88
88
|
return __awaiter(this, void 0, void 0, function () {
|
|
89
89
|
var fullCustomerAccountResource;
|
|
90
90
|
return __generator(this, function (_a) {
|
|
91
91
|
switch (_a.label) {
|
|
92
|
-
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/
|
|
92
|
+
case 0: return [4 /*yield*/, this.httpClient.getData("/customers/me/accounts/".concat(accountNumber), {}, {})];
|
|
93
93
|
case 1:
|
|
94
94
|
fullCustomerAccountResource = (_a.sent());
|
|
95
95
|
return [2 /*return*/, (0, response_util_1.default)(fullCustomerAccountResource)];
|
package/lib/account-streamer.ts
CHANGED
|
@@ -26,7 +26,7 @@ export type Disposer = () => void
|
|
|
26
26
|
|
|
27
27
|
export type StreamerStateObserver = (streamerState: STREAMER_STATE) => void
|
|
28
28
|
|
|
29
|
-
export type StreamerMessageObserver = (
|
|
29
|
+
export type StreamerMessageObserver = (json: object) => void
|
|
30
30
|
|
|
31
31
|
const REQUEST_ID = 'request-id'
|
|
32
32
|
|
|
@@ -368,7 +368,7 @@ export class AccountStreamer {
|
|
|
368
368
|
this.logger.info(json)
|
|
369
369
|
|
|
370
370
|
const action = json.action as string
|
|
371
|
-
this.streamerMessageObservers.forEach(observer => observer(json
|
|
371
|
+
this.streamerMessageObservers.forEach(observer => observer(json))
|
|
372
372
|
if (action) {
|
|
373
373
|
if (action === MessageAction.HEARTBEAT) {
|
|
374
374
|
// schedule next heartbeat
|
|
@@ -10,19 +10,19 @@ export default class AccountsAndCustomersService {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
//Customers: Operations about customers
|
|
13
|
-
async getCustomerResource(
|
|
13
|
+
async getCustomerResource(){
|
|
14
14
|
//Get a full customer resource.
|
|
15
|
-
const customerResource = (await this.httpClient.getData(`/customers
|
|
15
|
+
const customerResource = (await this.httpClient.getData(`/customers/me`, {}, {}))
|
|
16
16
|
return extractResponseData(customerResource)
|
|
17
17
|
}
|
|
18
|
-
async getCustomerAccountResources(
|
|
18
|
+
async getCustomerAccountResources(){
|
|
19
19
|
//Get a list of all the customer account resources attached to the current customer.
|
|
20
|
-
const customerAccountResources = (await this.httpClient.getData(`/customers
|
|
20
|
+
const customerAccountResources = (await this.httpClient.getData(`/customers/me/accounts`, {}, {}))
|
|
21
21
|
return extractResponseData(customerAccountResources)
|
|
22
22
|
}
|
|
23
|
-
async getFullCustomerAccountResource(
|
|
23
|
+
async getFullCustomerAccountResource(accountNumber: string){
|
|
24
24
|
//Get a full customer account resource.
|
|
25
|
-
const fullCustomerAccountResource = (await this.httpClient.getData(`/customers
|
|
25
|
+
const fullCustomerAccountResource = (await this.httpClient.getData(`/customers/me/accounts/${accountNumber}`, {}, {}))
|
|
26
26
|
return extractResponseData(fullCustomerAccountResource)
|
|
27
27
|
}
|
|
28
28
|
|