tradestation-client 1.0.15 → 1.1.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/.prettierrc CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "singleQuote": true,
3
3
  "semi": false,
4
- "printWidth": 120
4
+ "printWidth": 120,
5
+ "arrowParens": "avoid"
5
6
  }
@@ -12,7 +12,7 @@ const units = ['Minute', 'Hour', 'Daily', 'Weekly', 'Monthly']
12
12
  async function authenticateOrFail() {
13
13
  const authData = await tryLoadAuth()
14
14
  if (!authData) {
15
- console.error('No authentication data found. Please run the auth command first.')
15
+ console.error('No authentication data found. Please run the auth command first or provide credentials.')
16
16
  process.exit(1)
17
17
  }
18
18
  return authData
@@ -22,16 +22,19 @@ export const barsCommand = new Command('bars')
22
22
  .description('Download market data bars from TradeStation API')
23
23
  .argument('<symbol>', 'Market symbol to download data for')
24
24
  .option('--interval <interval>', 'Bar interval (e.g., 1, 5, 1440, ...)', '1')
25
- .addOption(new Option('--unit <unit>', 'Bar unit').choices(units).default(units[0]))
26
- .option('--barsBack <barsBack>', 'Number of bars to retrieve', parseInt, 10)
25
+ .addOption(new Option('--unit <unit>', 'Bar unit').choices(units).default('Daily'))
26
+ .option('--barsBack <barsBack>', 'Number of bars to retrieve', parseInt)
27
27
  .option('--firstDate <firstDate>', 'First date for bar data (YYYY-MM-DD)')
28
28
  .option('--lastDate <lastDate>', 'Last date for bar data (YYYY-MM-DD)')
29
29
  .addOption(
30
30
  new Option('--sessionTemplate <sessionTemplate>', 'Session template to use.').choices(sessions).default(sessions[0])
31
31
  )
32
+ // Optional authentication options
32
33
  .addOption(new Option('--clientId <clientId>', 'TradeStation Client ID'))
33
34
  .addOption(new Option('--clientSecret <clientSecret>', 'TradeStation Client Secret'))
34
35
  .addOption(new Option('--refreshToken <refreshToken>', 'TradeStation Refresh Token'))
36
+ // Output options
37
+ .option('-o --output <output>', 'Output file name, defaults to <symbol>.json')
35
38
  .action(async function (
36
39
  symbol: string,
37
40
  options: {
@@ -44,9 +47,11 @@ export const barsCommand = new Command('bars')
44
47
  clientId?: string
45
48
  clientSecret?: string
46
49
  refreshToken?: string
50
+ output: string
47
51
  }
48
52
  ) {
49
53
  const environment = this.optsWithGlobals().environment as 'Live' | 'Simulation'
54
+ const output = options.output || `${symbol}.json`
50
55
 
51
56
  let client: TradeStationClient
52
57
 
@@ -78,6 +83,6 @@ export const barsCommand = new Command('bars')
78
83
  sessiontemplate: options.sessionTemplate,
79
84
  })
80
85
 
81
- await fsp.writeFile(`${symbol}_bars.json`, JSON.stringify(bars.Bars, null, 2))
82
- console.log(`Saved ${bars.Bars.length} bars to ${symbol}_bars.json`)
86
+ await fsp.writeFile(output, JSON.stringify(bars.Bars, null, 2))
87
+ console.log(`Saved ${bars.Bars.length} bars to ${output}`)
83
88
  })
@@ -1 +1 @@
1
- {"version":3,"file":"barsCommand.d.ts","sourceRoot":"","sources":["../../commands/barsCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAoB3C,eAAO,MAAM,WAAW,SA8DpB,CAAA"}
1
+ {"version":3,"file":"barsCommand.d.ts","sourceRoot":"","sources":["../../commands/barsCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAoB3C,eAAO,MAAM,WAAW,SAmEpB,CAAA"}
@@ -7,7 +7,7 @@ const units = ['Minute', 'Hour', 'Daily', 'Weekly', 'Monthly'];
7
7
  async function authenticateOrFail() {
8
8
  const authData = await tryLoadAuth();
9
9
  if (!authData) {
10
- console.error('No authentication data found. Please run the auth command first.');
10
+ console.error('No authentication data found. Please run the auth command first or provide credentials.');
11
11
  process.exit(1);
12
12
  }
13
13
  return authData;
@@ -16,16 +16,20 @@ export const barsCommand = new Command('bars')
16
16
  .description('Download market data bars from TradeStation API')
17
17
  .argument('<symbol>', 'Market symbol to download data for')
18
18
  .option('--interval <interval>', 'Bar interval (e.g., 1, 5, 1440, ...)', '1')
19
- .addOption(new Option('--unit <unit>', 'Bar unit').choices(units).default(units[0]))
20
- .option('--barsBack <barsBack>', 'Number of bars to retrieve', parseInt, 10)
19
+ .addOption(new Option('--unit <unit>', 'Bar unit').choices(units).default('Daily'))
20
+ .option('--barsBack <barsBack>', 'Number of bars to retrieve', parseInt)
21
21
  .option('--firstDate <firstDate>', 'First date for bar data (YYYY-MM-DD)')
22
22
  .option('--lastDate <lastDate>', 'Last date for bar data (YYYY-MM-DD)')
23
23
  .addOption(new Option('--sessionTemplate <sessionTemplate>', 'Session template to use.').choices(sessions).default(sessions[0]))
24
+ // Optional authentication options
24
25
  .addOption(new Option('--clientId <clientId>', 'TradeStation Client ID'))
25
26
  .addOption(new Option('--clientSecret <clientSecret>', 'TradeStation Client Secret'))
26
27
  .addOption(new Option('--refreshToken <refreshToken>', 'TradeStation Refresh Token'))
28
+ // Output options
29
+ .option('-o --output <output>', 'Output file name, defaults to <symbol>.json')
27
30
  .action(async function (symbol, options) {
28
31
  const environment = this.optsWithGlobals().environment;
32
+ const output = options.output || `${symbol}.json`;
29
33
  let client;
30
34
  if (options.clientId && options.clientSecret && options.refreshToken) {
31
35
  client = new TradeStationClient({
@@ -53,7 +57,7 @@ export const barsCommand = new Command('bars')
53
57
  barsback: options.barsBack,
54
58
  sessiontemplate: options.sessionTemplate,
55
59
  });
56
- await fsp.writeFile(`${symbol}_bars.json`, JSON.stringify(bars.Bars, null, 2));
57
- console.log(`Saved ${bars.Bars.length} bars to ${symbol}_bars.json`);
60
+ await fsp.writeFile(output, JSON.stringify(bars.Bars, null, 2));
61
+ console.log(`Saved ${bars.Bars.length} bars to ${output}`);
58
62
  });
59
63
  //# sourceMappingURL=barsCommand.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"barsCommand.js","sourceRoot":"","sources":["../../commands/barsCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"barsCommand.js","sourceRoot":"","sources":["../../commands/barsCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../../test/cli.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { describe, test, beforeEach, mock } from 'node:test';
2
+ describe('CLI Tests', () => {
3
+ describe('auth command', () => {
4
+ beforeEach(t => {
5
+ mock.reset();
6
+ mock.module('../authMiddleware.js', {
7
+ namedExports: {
8
+ authenticate: mock.fn(),
9
+ },
10
+ });
11
+ });
12
+ test('should require clientId and clientSecret', async (t) => {
13
+ const { authCommand } = await import('../commands/auth.js');
14
+ t.assert.throws(() => authCommand.exitOverride().parse([], { from: 'user' }));
15
+ });
16
+ test('should fail with just clientId', async (t) => {
17
+ const { authCommand } = await import('../commands/auth.js');
18
+ t.assert.throws(() => authCommand.exitOverride().parse(['--clientId', 'myClientId'], { from: 'user' }));
19
+ });
20
+ test('should fail with just clientSecret', async (t) => {
21
+ const { authCommand } = await import('../commands/auth.js');
22
+ t.assert.throws(() => authCommand.exitOverride().parse(['--clientSecret', 'myClientSecret'], { from: 'user' }));
23
+ });
24
+ test('should pass with both clientId and clientSecret', async (t) => {
25
+ const { authCommand } = await import('../commands/auth.js');
26
+ authCommand.exitOverride().parse(['--clientId', 'myClientId', '--clientSecret', 'myClientSecret'], {
27
+ from: 'user',
28
+ });
29
+ });
30
+ });
31
+ });
32
+ //# sourceMappingURL=cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../test/cli.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAE5D,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,UAAU,CAAC,CAAC,CAAC,EAAE;YACb,IAAI,CAAC,KAAK,EAAE,CAAA;YACZ,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE;gBAClC,YAAY,EAAE;oBACZ,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE;iBACxB;aACF,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,0CAA0C,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;YACzD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YAC3D,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QAC/E,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,gCAAgC,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;YAC/C,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YAC3D,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QACzG,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,oCAAoC,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;YACnD,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YAC3D,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QACjH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,iDAAiD,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;YAChE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;YAE3D,WAAW,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,EAAE;gBACjG,IAAI,EAAE,MAAM;aACb,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "tradestation-client",
3
- "version": "1.0.15",
3
+ "version": "1.1.0",
4
4
  "description": "A Node.js client for the TradeStation API with OAuth2 authentication and OpenAPI integration.",
5
5
  "type": "module",
6
6
  "bin": "./dist/cli.js",
7
7
  "scripts": {
8
+ "test": "tsx --experimental-test-module-mocks --test",
8
9
  "test:ts": "tsc --noEmit",
10
+ "cli": "tsx cli.ts",
9
11
  "download-openapi": "node ./downloadOpenAPI.ts",
10
12
  "generate-client": "openapi-typescript ./openapi.json --output generated/tradestation-api.d.ts",
11
13
  "build": "npm run download-openapi && npm run generate-client && tsc",
@@ -26,6 +28,7 @@
26
28
  "@types/node": "^25.0.3",
27
29
  "openapi-typescript": "^7.10.1",
28
30
  "playwright-core": "^1.57.0",
31
+ "tsx": "^4.21.0",
29
32
  "typescript": "^5.9.3"
30
33
  }
31
34
  }
@@ -0,0 +1,37 @@
1
+ import { describe, test, beforeEach, mock } from 'node:test'
2
+
3
+ describe('CLI Tests', () => {
4
+ describe('auth command', () => {
5
+ beforeEach(t => {
6
+ mock.reset()
7
+ mock.module('../authMiddleware.js', {
8
+ namedExports: {
9
+ authenticate: mock.fn(),
10
+ },
11
+ })
12
+ })
13
+
14
+ test('should require clientId and clientSecret', async t => {
15
+ const { authCommand } = await import('../commands/auth.js')
16
+ t.assert.throws(() => authCommand.exitOverride().parse([], { from: 'user' }))
17
+ })
18
+
19
+ test('should fail with just clientId', async t => {
20
+ const { authCommand } = await import('../commands/auth.js')
21
+ t.assert.throws(() => authCommand.exitOverride().parse(['--clientId', 'myClientId'], { from: 'user' }))
22
+ })
23
+
24
+ test('should fail with just clientSecret', async t => {
25
+ const { authCommand } = await import('../commands/auth.js')
26
+ t.assert.throws(() => authCommand.exitOverride().parse(['--clientSecret', 'myClientSecret'], { from: 'user' }))
27
+ })
28
+
29
+ test('should pass with both clientId and clientSecret', async t => {
30
+ const { authCommand } = await import('../commands/auth.js')
31
+
32
+ authCommand.exitOverride().parse(['--clientId', 'myClientId', '--clientSecret', 'myClientSecret'], {
33
+ from: 'user',
34
+ })
35
+ })
36
+ })
37
+ })