@tigeropenapi/tigeropen 0.5.3 → 0.5.4

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.
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryToken = queryToken;
4
+ exports.refreshToken = refreshToken;
5
+ exports.startTokenAutoRefresh = startTokenAutoRefresh;
6
+ /**
7
+ * Call the `user_token_refresh` API and return the new token string.
8
+ * Read-only: does NOT update the stored token.
9
+ * Use `refreshToken()` to also update the in-memory config and optionally persist.
10
+ */
11
+ async function queryToken(httpClient) {
12
+ return httpClient.queryToken();
13
+ }
14
+ /**
15
+ * Refresh the token: call the API, update the in-memory config token, and
16
+ * optionally persist via the provided TokenManager (file + writer callback).
17
+ *
18
+ * @param httpClient - The underlying HTTP client
19
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
20
+ */
21
+ async function refreshToken(httpClient, tokenManager) {
22
+ return httpClient.refreshToken(tokenManager);
23
+ }
24
+ /**
25
+ * Start background token auto-refresh. Returns a TokenManager that can be
26
+ * used to stop the background task via `tm.stopAutoRefresh()`.
27
+ *
28
+ * @param httpClient - The underlying HTTP client
29
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
30
+ * When the token age exceeds this value the refresh is triggered.
31
+ * @param checkIntervalMs - How often to check whether a refresh is needed,
32
+ * in milliseconds. Defaults to 300 000 ms (5 minutes).
33
+ * @param tokenWriter - Optional callback invoked with the new token string
34
+ * after each successful refresh.
35
+ */
36
+ function startTokenAutoRefresh(httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter) {
37
+ return httpClient.startTokenAutoRefresh(null, {
38
+ refreshDuration: refreshDurationSecs,
39
+ refreshInterval: checkIntervalMs,
40
+ tokenWriter,
41
+ });
42
+ }
@@ -113,23 +113,32 @@ function createClientConfig(options) {
113
113
  const opts = options ?? {};
114
114
  // Load properties: explicit path > auto-discovery
115
115
  let fileProps = {};
116
+ let configFileDir;
116
117
  if (opts.propertiesFilePath) {
117
118
  // Support both directory path and full file path
118
119
  let filePath = opts.propertiesFilePath;
119
120
  if ((0, fs_1.existsSync)(filePath) && (0, fs_1.statSync)(filePath).isDirectory()) {
121
+ configFileDir = filePath;
120
122
  filePath = (0, path_1.join)(filePath, CONFIG_FILE_NAME);
121
123
  }
122
124
  else if (!(0, fs_1.existsSync)(filePath) && !filePath.endsWith('.properties')) {
123
125
  // Path doesn't exist as-is; try treating it as a directory
124
126
  const asDir = (0, path_1.join)(filePath, CONFIG_FILE_NAME);
125
- if ((0, fs_1.existsSync)(asDir))
127
+ if ((0, fs_1.existsSync)(asDir)) {
128
+ configFileDir = filePath;
126
129
  filePath = asDir;
130
+ }
131
+ }
132
+ else {
133
+ // It's a file path: derive directory from it
134
+ configFileDir = (0, path_1.dirname)(filePath);
127
135
  }
128
136
  fileProps = loadPropertiesFile(filePath);
129
137
  }
130
138
  else {
131
139
  const discovered = discoverConfigFile();
132
140
  if (discovered) {
141
+ configFileDir = (0, path_1.dirname)(discovered);
133
142
  fileProps = loadPropertiesFile(discovered);
134
143
  }
135
144
  }
@@ -189,8 +198,9 @@ function createClientConfig(options) {
189
198
  }
190
199
  }
191
200
  else {
192
- // Load from token file: TIGEROPEN_TOKEN_FILE env var > default file
193
- const tokenFilePath = process.env[ENV_TOKEN_FILE] || 'tiger_openapi_token.properties';
201
+ // Load from token file: TIGEROPEN_TOKEN_FILE env var > config dir > default
202
+ const tokenFilePath = process.env[ENV_TOKEN_FILE]
203
+ || (configFileDir ? (0, path_1.join)(configFileDir, 'tiger_openapi_token.properties') : 'tiger_openapi_token.properties');
194
204
  const tm = new token_manager_1.TokenManager({ filePath: tokenFilePath });
195
205
  try {
196
206
  token = tm.loadTokenSync();
@@ -9,8 +9,14 @@ exports.auctionLimitOrder = auctionLimitOrder;
9
9
  exports.auctionMarketOrder = auctionMarketOrder;
10
10
  exports.algoOrder = algoOrder;
11
11
  exports.icebergOrder = icebergOrder;
12
- exports.icebergOrderFull = icebergOrderFull;
13
12
  exports.orderLeg = orderLeg;
13
+ exports.marketOrderByAmount = marketOrderByAmount;
14
+ exports.limitOrderByAmount = limitOrderByAmount;
15
+ exports.trailOrderByPrice = trailOrderByPrice;
16
+ exports.limitOrderWithLegs = limitOrderWithLegs;
17
+ exports.comboOrder = comboOrder;
18
+ exports.ocaOrder = ocaOrder;
19
+ exports.contractLeg = contractLeg;
14
20
  const enums_1 = require("./enums");
15
21
  /** Market order */
16
22
  function marketOrder(account, symbol, secType, action, quantity) {
@@ -101,26 +107,11 @@ function algoOrder(account, symbol, secType, action, quantity, limitPrice, algoT
101
107
  };
102
108
  }
103
109
  /**
104
- * Iceberg order (basic) — only displaySize required.
105
- */
106
- function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize) {
107
- return {
108
- account, symbol, secType, action,
109
- orderType: enums_1.OrderType.ICEBERG,
110
- totalQuantity: quantity,
111
- limitPrice,
112
- timeInForce: enums_1.TimeInForce.DAY,
113
- outsideRth: false,
114
- displaySize,
115
- priceType: enums_1.PriceType.LIMIT_PRICE,
116
- };
117
- }
118
- /**
119
- * Iceberg order (full params).
120
- * Pass `priceType` as empty string to use server default (LIMIT_PRICE).
110
+ * Iceberg order. `displaySize` is required; all other parameters are optional.
111
+ * Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
121
112
  * Pass `startTime` / `endTime` as 0 to omit the time window.
122
113
  */
123
- function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
114
+ function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
124
115
  const req = {
125
116
  account, symbol, secType, action,
126
117
  orderType: enums_1.OrderType.ICEBERG,
@@ -129,13 +120,12 @@ function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice
129
120
  timeInForce: enums_1.TimeInForce.DAY,
130
121
  outsideRth: false,
131
122
  displaySize,
123
+ priceType: priceType || enums_1.PriceType.LIMIT_PRICE,
132
124
  };
133
125
  if (minDisplaySize !== undefined && minDisplaySize > 0)
134
126
  req.minDisplaySize = minDisplaySize;
135
127
  if (checkIntervals !== undefined && checkIntervals > 0)
136
128
  req.checkIntervals = checkIntervals;
137
- if (priceType)
138
- req.priceType = priceType;
139
129
  if (startTime && startTime > 0)
140
130
  req.startTime = startTime;
141
131
  if (endTime && endTime > 0)
@@ -146,3 +136,118 @@ function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice
146
136
  function orderLeg(legType, price, timeInForce) {
147
137
  return { legType, price, timeInForce };
148
138
  }
139
+ /**
140
+ * Market order by cash amount (instead of quantity).
141
+ * Server uses `isQuantityByAmount=true` + `amount` field.
142
+ */
143
+ function marketOrderByAmount(account, symbol, secType, action, amount) {
144
+ return {
145
+ account, symbol, secType, action,
146
+ orderType: enums_1.OrderType.MKT,
147
+ totalQuantity: 0,
148
+ cashAmount: amount,
149
+ timeInForce: enums_1.TimeInForce.DAY,
150
+ outsideRth: false,
151
+ };
152
+ }
153
+ /**
154
+ * Limit order by cash amount (instead of quantity).
155
+ */
156
+ function limitOrderByAmount(account, symbol, secType, action, amount, limitPrice) {
157
+ return {
158
+ account, symbol, secType, action,
159
+ orderType: enums_1.OrderType.LMT,
160
+ totalQuantity: 0,
161
+ cashAmount: amount,
162
+ limitPrice,
163
+ timeInForce: enums_1.TimeInForce.DAY,
164
+ outsideRth: false,
165
+ };
166
+ }
167
+ /**
168
+ * Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
169
+ * Use `trailOrder()` for percentage-based trailing stops.
170
+ */
171
+ function trailOrderByPrice(account, symbol, secType, action, quantity, auxPrice) {
172
+ return {
173
+ account, symbol, secType, action,
174
+ orderType: enums_1.OrderType.TRAIL,
175
+ totalQuantity: quantity,
176
+ auxPrice,
177
+ timeInForce: enums_1.TimeInForce.DAY,
178
+ outsideRth: false,
179
+ };
180
+ }
181
+ /**
182
+ * Limit order with attached profit/loss legs (bracket order).
183
+ * At most 2 legs are supported.
184
+ *
185
+ * @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
186
+ */
187
+ function limitOrderWithLegs(account, symbol, secType, action, quantity, limitPrice, orderLegs) {
188
+ if (orderLegs.length === 0) {
189
+ throw new Error('At least 1 order leg is required for a bracket order');
190
+ }
191
+ if (orderLegs.length > 2) {
192
+ throw new Error('At most 2 order legs are supported');
193
+ }
194
+ return {
195
+ account, symbol, secType, action,
196
+ orderType: enums_1.OrderType.LMT,
197
+ totalQuantity: quantity,
198
+ limitPrice,
199
+ orderLegs,
200
+ timeInForce: enums_1.TimeInForce.DAY,
201
+ outsideRth: false,
202
+ };
203
+ }
204
+ /**
205
+ * Multi-leg (combo/MLEG) order for options combos.
206
+ *
207
+ * @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
208
+ * @param comboType - e.g. `'MLEG'`
209
+ */
210
+ function comboOrder(account, action, quantity, orderType, contractLegs, comboType = 'MLEG', limitPrice, auxPrice, trailingPercent) {
211
+ return {
212
+ account,
213
+ symbol: '', // not used for combo orders
214
+ secType: 'MLEG',
215
+ action,
216
+ orderType,
217
+ totalQuantity: quantity,
218
+ limitPrice,
219
+ auxPrice,
220
+ trailingPercent,
221
+ contractLegs,
222
+ comboType,
223
+ timeInForce: enums_1.TimeInForce.DAY,
224
+ outsideRth: false,
225
+ };
226
+ }
227
+ /**
228
+ * OCA (One-Cancels-All) order.
229
+ * Server expects `orderType: 'OCA'` and an `ocaOrders` list.
230
+ *
231
+ * @param ocaOrders - The contained orders (use any order helper to build each)
232
+ */
233
+ function ocaOrder(account, symbol, secType, action, quantity, ocaOrders) {
234
+ return {
235
+ account, symbol, secType, action,
236
+ orderType: enums_1.OrderType.OCA,
237
+ totalQuantity: quantity,
238
+ ocaOrders,
239
+ timeInForce: enums_1.TimeInForce.DAY,
240
+ outsideRth: false,
241
+ };
242
+ }
243
+ /**
244
+ * Build a single leg for a multi-leg (MLEG / combo) order.
245
+ *
246
+ * @param symbol - Underlying symbol
247
+ * @param secType - Security type (e.g. `'OPT'`)
248
+ * @param action - `'BUY'` or `'SELL'`
249
+ * @param ratio - Number of contracts for this leg
250
+ */
251
+ function contractLeg(symbol, secType, action, ratio, expiry, strike, right) {
252
+ return { symbol, secType, action, ratio, expiry, strike, right };
253
+ }
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.QuoteClient = void 0;
4
37
  exports.parseOptionIdentifier = parseOptionIdentifier;
@@ -12,6 +45,7 @@ exports.parseOptionIdentifier = parseOptionIdentifier;
12
45
  const http_client_1 = require("../client/http-client");
13
46
  const api_request_1 = require("../client/api-request");
14
47
  const api_response_1 = require("../client/api-response");
48
+ const tokenMethods = __importStar(require("../client/token-methods"));
15
49
  /**
16
50
  * resolveOptionTimezone returns the timezone string to use for expiry conversion.
17
51
  * Explicit tz takes precedence; otherwise infer from symbol (.HK suffix → Asia/Hong_Kong, else America/New_York).
@@ -94,6 +128,25 @@ class QuoteClient {
94
128
  static fromConfig(config) {
95
129
  return new QuoteClient(new http_client_1.HttpClient(config, undefined, { useQuoteServerUrl: true }));
96
130
  }
131
+ // ── Token management ──────────────────────────────────────────────────────
132
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
133
+ async queryToken() {
134
+ return tokenMethods.queryToken(this.httpClient);
135
+ }
136
+ /** Refresh the token and update the in-memory config token. */
137
+ async refreshToken(tokenManager) {
138
+ return tokenMethods.refreshToken(this.httpClient, tokenManager);
139
+ }
140
+ /**
141
+ * Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
142
+ *
143
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
144
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
145
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
146
+ */
147
+ startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
148
+ return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
149
+ }
97
150
  async callInto(method, bizParams, version) {
98
151
  const request = (0, api_request_1.createApiRequest)(method, bizParams, version);
99
152
  const response = await this.httpClient.executeRequest(request);
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.TradeClient = void 0;
4
37
  /**
@@ -13,6 +46,7 @@ exports.TradeClient = void 0;
13
46
  const http_client_1 = require("../client/http-client");
14
47
  const api_request_1 = require("../client/api-request");
15
48
  const api_response_1 = require("../client/api-response");
49
+ const tokenMethods = __importStar(require("../client/token-methods"));
16
50
  const order_status_1 = require("../model/order-status");
17
51
  /** Normalize `Order.status` field in-place (handles int → string). */
18
52
  function normalizeOrderInPlace(o) {
@@ -44,6 +78,31 @@ class TradeClient {
44
78
  static fromConfig(config, account, secretKey) {
45
79
  return new TradeClient(new http_client_1.HttpClient(config), account, secretKey);
46
80
  }
81
+ // ── Token management ──────────────────────────────────────────────────────
82
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
83
+ async queryToken() {
84
+ return tokenMethods.queryToken(this.httpClient);
85
+ }
86
+ /**
87
+ * Refresh the token: call the API, update the in-memory config token, and
88
+ * optionally persist via the provided TokenManager (file + writer callback).
89
+ *
90
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
91
+ */
92
+ async refreshToken(tokenManager) {
93
+ return tokenMethods.refreshToken(this.httpClient, tokenManager);
94
+ }
95
+ /**
96
+ * Start background token auto-refresh. Returns a TokenManager that can be
97
+ * used to stop the background task via `tm.stopAutoRefresh()`.
98
+ *
99
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
100
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
101
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
102
+ */
103
+ startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
104
+ return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
105
+ }
47
106
  async callInto(method, bizParams) {
48
107
  // Inject secretKey into every request when available (institution accounts require it).
49
108
  // Individual methods that already set secretKey will not be overwritten (|| not &&).
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Call the `user_token_refresh` API and return the new token string.
3
+ * Read-only: does NOT update the stored token.
4
+ * Use `refreshToken()` to also update the in-memory config and optionally persist.
5
+ */
6
+ export async function queryToken(httpClient) {
7
+ return httpClient.queryToken();
8
+ }
9
+ /**
10
+ * Refresh the token: call the API, update the in-memory config token, and
11
+ * optionally persist via the provided TokenManager (file + writer callback).
12
+ *
13
+ * @param httpClient - The underlying HTTP client
14
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
15
+ */
16
+ export async function refreshToken(httpClient, tokenManager) {
17
+ return httpClient.refreshToken(tokenManager);
18
+ }
19
+ /**
20
+ * Start background token auto-refresh. Returns a TokenManager that can be
21
+ * used to stop the background task via `tm.stopAutoRefresh()`.
22
+ *
23
+ * @param httpClient - The underlying HTTP client
24
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
25
+ * When the token age exceeds this value the refresh is triggered.
26
+ * @param checkIntervalMs - How often to check whether a refresh is needed,
27
+ * in milliseconds. Defaults to 300 000 ms (5 minutes).
28
+ * @param tokenWriter - Optional callback invoked with the new token string
29
+ * after each successful refresh.
30
+ */
31
+ export function startTokenAutoRefresh(httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter) {
32
+ return httpClient.startTokenAutoRefresh(null, {
33
+ refreshDuration: refreshDurationSecs,
34
+ refreshInterval: checkIntervalMs,
35
+ tokenWriter,
36
+ });
37
+ }
@@ -9,7 +9,7 @@
9
9
  * Priority: environment variables > code options (incl. config file) > defaults
10
10
  */
11
11
  import { readFileSync, existsSync, statSync } from 'fs';
12
- import { join } from 'path';
12
+ import { join, dirname } from 'path';
13
13
  import { homedir, networkInterfaces } from 'os';
14
14
  import { parsePropertiesString } from './config-parser.js';
15
15
  import { queryDomains, resolveDynamicServerUrl, resolveDynamicQuoteServerUrl } from './domain.js';
@@ -108,23 +108,32 @@ export function createClientConfig(options) {
108
108
  const opts = options ?? {};
109
109
  // Load properties: explicit path > auto-discovery
110
110
  let fileProps = {};
111
+ let configFileDir;
111
112
  if (opts.propertiesFilePath) {
112
113
  // Support both directory path and full file path
113
114
  let filePath = opts.propertiesFilePath;
114
115
  if (existsSync(filePath) && statSync(filePath).isDirectory()) {
116
+ configFileDir = filePath;
115
117
  filePath = join(filePath, CONFIG_FILE_NAME);
116
118
  }
117
119
  else if (!existsSync(filePath) && !filePath.endsWith('.properties')) {
118
120
  // Path doesn't exist as-is; try treating it as a directory
119
121
  const asDir = join(filePath, CONFIG_FILE_NAME);
120
- if (existsSync(asDir))
122
+ if (existsSync(asDir)) {
123
+ configFileDir = filePath;
121
124
  filePath = asDir;
125
+ }
126
+ }
127
+ else {
128
+ // It's a file path: derive directory from it
129
+ configFileDir = dirname(filePath);
122
130
  }
123
131
  fileProps = loadPropertiesFile(filePath);
124
132
  }
125
133
  else {
126
134
  const discovered = discoverConfigFile();
127
135
  if (discovered) {
136
+ configFileDir = dirname(discovered);
128
137
  fileProps = loadPropertiesFile(discovered);
129
138
  }
130
139
  }
@@ -184,8 +193,9 @@ export function createClientConfig(options) {
184
193
  }
185
194
  }
186
195
  else {
187
- // Load from token file: TIGEROPEN_TOKEN_FILE env var > default file
188
- const tokenFilePath = process.env[ENV_TOKEN_FILE] || 'tiger_openapi_token.properties';
196
+ // Load from token file: TIGEROPEN_TOKEN_FILE env var > config dir > default
197
+ const tokenFilePath = process.env[ENV_TOKEN_FILE]
198
+ || (configFileDir ? join(configFileDir, 'tiger_openapi_token.properties') : 'tiger_openapi_token.properties');
189
199
  const tm = new TokenManager({ filePath: tokenFilePath });
190
200
  try {
191
201
  token = tm.loadTokenSync();
@@ -88,26 +88,11 @@ export function algoOrder(account, symbol, secType, action, quantity, limitPrice
88
88
  };
89
89
  }
90
90
  /**
91
- * Iceberg order (basic) — only displaySize required.
92
- */
93
- export function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize) {
94
- return {
95
- account, symbol, secType, action,
96
- orderType: OrderType.ICEBERG,
97
- totalQuantity: quantity,
98
- limitPrice,
99
- timeInForce: TimeInForce.DAY,
100
- outsideRth: false,
101
- displaySize,
102
- priceType: PriceType.LIMIT_PRICE,
103
- };
104
- }
105
- /**
106
- * Iceberg order (full params).
107
- * Pass `priceType` as empty string to use server default (LIMIT_PRICE).
91
+ * Iceberg order. `displaySize` is required; all other parameters are optional.
92
+ * Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
108
93
  * Pass `startTime` / `endTime` as 0 to omit the time window.
109
94
  */
110
- export function icebergOrderFull(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
95
+ export function icebergOrder(account, symbol, secType, action, quantity, limitPrice, displaySize, minDisplaySize, checkIntervals, priceType, startTime, endTime) {
111
96
  const req = {
112
97
  account, symbol, secType, action,
113
98
  orderType: OrderType.ICEBERG,
@@ -116,13 +101,12 @@ export function icebergOrderFull(account, symbol, secType, action, quantity, lim
116
101
  timeInForce: TimeInForce.DAY,
117
102
  outsideRth: false,
118
103
  displaySize,
104
+ priceType: priceType || PriceType.LIMIT_PRICE,
119
105
  };
120
106
  if (minDisplaySize !== undefined && minDisplaySize > 0)
121
107
  req.minDisplaySize = minDisplaySize;
122
108
  if (checkIntervals !== undefined && checkIntervals > 0)
123
109
  req.checkIntervals = checkIntervals;
124
- if (priceType)
125
- req.priceType = priceType;
126
110
  if (startTime && startTime > 0)
127
111
  req.startTime = startTime;
128
112
  if (endTime && endTime > 0)
@@ -133,3 +117,118 @@ export function icebergOrderFull(account, symbol, secType, action, quantity, lim
133
117
  export function orderLeg(legType, price, timeInForce) {
134
118
  return { legType, price, timeInForce };
135
119
  }
120
+ /**
121
+ * Market order by cash amount (instead of quantity).
122
+ * Server uses `isQuantityByAmount=true` + `amount` field.
123
+ */
124
+ export function marketOrderByAmount(account, symbol, secType, action, amount) {
125
+ return {
126
+ account, symbol, secType, action,
127
+ orderType: OrderType.MKT,
128
+ totalQuantity: 0,
129
+ cashAmount: amount,
130
+ timeInForce: TimeInForce.DAY,
131
+ outsideRth: false,
132
+ };
133
+ }
134
+ /**
135
+ * Limit order by cash amount (instead of quantity).
136
+ */
137
+ export function limitOrderByAmount(account, symbol, secType, action, amount, limitPrice) {
138
+ return {
139
+ account, symbol, secType, action,
140
+ orderType: OrderType.LMT,
141
+ totalQuantity: 0,
142
+ cashAmount: amount,
143
+ limitPrice,
144
+ timeInForce: TimeInForce.DAY,
145
+ outsideRth: false,
146
+ };
147
+ }
148
+ /**
149
+ * Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
150
+ * Use `trailOrder()` for percentage-based trailing stops.
151
+ */
152
+ export function trailOrderByPrice(account, symbol, secType, action, quantity, auxPrice) {
153
+ return {
154
+ account, symbol, secType, action,
155
+ orderType: OrderType.TRAIL,
156
+ totalQuantity: quantity,
157
+ auxPrice,
158
+ timeInForce: TimeInForce.DAY,
159
+ outsideRth: false,
160
+ };
161
+ }
162
+ /**
163
+ * Limit order with attached profit/loss legs (bracket order).
164
+ * At most 2 legs are supported.
165
+ *
166
+ * @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
167
+ */
168
+ export function limitOrderWithLegs(account, symbol, secType, action, quantity, limitPrice, orderLegs) {
169
+ if (orderLegs.length === 0) {
170
+ throw new Error('At least 1 order leg is required for a bracket order');
171
+ }
172
+ if (orderLegs.length > 2) {
173
+ throw new Error('At most 2 order legs are supported');
174
+ }
175
+ return {
176
+ account, symbol, secType, action,
177
+ orderType: OrderType.LMT,
178
+ totalQuantity: quantity,
179
+ limitPrice,
180
+ orderLegs,
181
+ timeInForce: TimeInForce.DAY,
182
+ outsideRth: false,
183
+ };
184
+ }
185
+ /**
186
+ * Multi-leg (combo/MLEG) order for options combos.
187
+ *
188
+ * @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
189
+ * @param comboType - e.g. `'MLEG'`
190
+ */
191
+ export function comboOrder(account, action, quantity, orderType, contractLegs, comboType = 'MLEG', limitPrice, auxPrice, trailingPercent) {
192
+ return {
193
+ account,
194
+ symbol: '', // not used for combo orders
195
+ secType: 'MLEG',
196
+ action,
197
+ orderType,
198
+ totalQuantity: quantity,
199
+ limitPrice,
200
+ auxPrice,
201
+ trailingPercent,
202
+ contractLegs,
203
+ comboType,
204
+ timeInForce: TimeInForce.DAY,
205
+ outsideRth: false,
206
+ };
207
+ }
208
+ /**
209
+ * OCA (One-Cancels-All) order.
210
+ * Server expects `orderType: 'OCA'` and an `ocaOrders` list.
211
+ *
212
+ * @param ocaOrders - The contained orders (use any order helper to build each)
213
+ */
214
+ export function ocaOrder(account, symbol, secType, action, quantity, ocaOrders) {
215
+ return {
216
+ account, symbol, secType, action,
217
+ orderType: OrderType.OCA,
218
+ totalQuantity: quantity,
219
+ ocaOrders,
220
+ timeInForce: TimeInForce.DAY,
221
+ outsideRth: false,
222
+ };
223
+ }
224
+ /**
225
+ * Build a single leg for a multi-leg (MLEG / combo) order.
226
+ *
227
+ * @param symbol - Underlying symbol
228
+ * @param secType - Security type (e.g. `'OPT'`)
229
+ * @param action - `'BUY'` or `'SELL'`
230
+ * @param ratio - Number of contracts for this leg
231
+ */
232
+ export function contractLeg(symbol, secType, action, ratio, expiry, strike, right) {
233
+ return { symbol, secType, action, ratio, expiry, strike, right };
234
+ }
@@ -8,6 +8,7 @@
8
8
  import { HttpClient } from '../client/http-client.js';
9
9
  import { createApiRequest } from '../client/api-request.js';
10
10
  import { unmarshalData } from '../client/api-response.js';
11
+ import * as tokenMethods from '../client/token-methods.js';
11
12
  /**
12
13
  * resolveOptionTimezone returns the timezone string to use for expiry conversion.
13
14
  * Explicit tz takes precedence; otherwise infer from symbol (.HK suffix → Asia/Hong_Kong, else America/New_York).
@@ -90,6 +91,25 @@ export class QuoteClient {
90
91
  static fromConfig(config) {
91
92
  return new QuoteClient(new HttpClient(config, undefined, { useQuoteServerUrl: true }));
92
93
  }
94
+ // ── Token management ──────────────────────────────────────────────────────
95
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
96
+ async queryToken() {
97
+ return tokenMethods.queryToken(this.httpClient);
98
+ }
99
+ /** Refresh the token and update the in-memory config token. */
100
+ async refreshToken(tokenManager) {
101
+ return tokenMethods.refreshToken(this.httpClient, tokenManager);
102
+ }
103
+ /**
104
+ * Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
105
+ *
106
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
107
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
108
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
109
+ */
110
+ startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
111
+ return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
112
+ }
93
113
  async callInto(method, bizParams, version) {
94
114
  const request = createApiRequest(method, bizParams, version);
95
115
  const response = await this.httpClient.executeRequest(request);
@@ -10,6 +10,7 @@
10
10
  import { HttpClient } from '../client/http-client.js';
11
11
  import { createApiRequest } from '../client/api-request.js';
12
12
  import { unmarshalData } from '../client/api-response.js';
13
+ import * as tokenMethods from '../client/token-methods.js';
13
14
  import { normalizeOrderStatus } from '../model/order-status.js';
14
15
  /** Normalize `Order.status` field in-place (handles int → string). */
15
16
  function normalizeOrderInPlace(o) {
@@ -41,6 +42,31 @@ export class TradeClient {
41
42
  static fromConfig(config, account, secretKey) {
42
43
  return new TradeClient(new HttpClient(config), account, secretKey);
43
44
  }
45
+ // ── Token management ──────────────────────────────────────────────────────
46
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
47
+ async queryToken() {
48
+ return tokenMethods.queryToken(this.httpClient);
49
+ }
50
+ /**
51
+ * Refresh the token: call the API, update the in-memory config token, and
52
+ * optionally persist via the provided TokenManager (file + writer callback).
53
+ *
54
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
55
+ */
56
+ async refreshToken(tokenManager) {
57
+ return tokenMethods.refreshToken(this.httpClient, tokenManager);
58
+ }
59
+ /**
60
+ * Start background token auto-refresh. Returns a TokenManager that can be
61
+ * used to stop the background task via `tm.stopAutoRefresh()`.
62
+ *
63
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
64
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
65
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
66
+ */
67
+ startTokenAutoRefresh(refreshDurationSecs, checkIntervalMs, tokenWriter) {
68
+ return tokenMethods.startTokenAutoRefresh(this.httpClient, refreshDurationSecs, checkIntervalMs, tokenWriter);
69
+ }
44
70
  async callInto(method, bizParams) {
45
71
  // Inject secretKey into every request when available (institution accounts require it).
46
72
  // Individual methods that already set secretKey will not be overwritten (|| not &&).
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shared token management methods for TradeClient and QuoteClient.
3
+ * Both clients delegate to the underlying HttpClient; this module
4
+ * centralises the JSDoc so each client stays in sync automatically.
5
+ */
6
+ import type { HttpClient } from './http-client';
7
+ import type { TokenManager } from '../config/token-manager';
8
+ /**
9
+ * Call the `user_token_refresh` API and return the new token string.
10
+ * Read-only: does NOT update the stored token.
11
+ * Use `refreshToken()` to also update the in-memory config and optionally persist.
12
+ */
13
+ export declare function queryToken(httpClient: HttpClient): Promise<string>;
14
+ /**
15
+ * Refresh the token: call the API, update the in-memory config token, and
16
+ * optionally persist via the provided TokenManager (file + writer callback).
17
+ *
18
+ * @param httpClient - The underlying HTTP client
19
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
20
+ */
21
+ export declare function refreshToken(httpClient: HttpClient, tokenManager?: TokenManager | null): Promise<void>;
22
+ /**
23
+ * Start background token auto-refresh. Returns a TokenManager that can be
24
+ * used to stop the background task via `tm.stopAutoRefresh()`.
25
+ *
26
+ * @param httpClient - The underlying HTTP client
27
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
28
+ * When the token age exceeds this value the refresh is triggered.
29
+ * @param checkIntervalMs - How often to check whether a refresh is needed,
30
+ * in milliseconds. Defaults to 300 000 ms (5 minutes).
31
+ * @param tokenWriter - Optional callback invoked with the new token string
32
+ * after each successful refresh.
33
+ */
34
+ export declare function startTokenAutoRefresh(httpClient: HttpClient, refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
@@ -2,7 +2,7 @@
2
2
  * Order construction helpers.
3
3
  * All helpers return an `OrderRequest` with sensible defaults.
4
4
  */
5
- import type { OrderRequest, OrderLegRequest, AlgoParamsRequest } from './order';
5
+ import type { OrderRequest, OrderLegRequest, AlgoParamsRequest, ContractLegRequest } from './order';
6
6
  import { PriceType } from './enums';
7
7
  /** Market order */
8
8
  export declare function marketOrder(account: string, symbol: string, secType: string, action: string, quantity: number): OrderRequest;
@@ -21,14 +21,54 @@ export declare function auctionMarketOrder(account: string, symbol: string, secT
21
21
  /** Algo order (TWAP / VWAP) */
22
22
  export declare function algoOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, algoType: string, params: AlgoParamsRequest): OrderRequest;
23
23
  /**
24
- * Iceberg order (basic) — only displaySize required.
25
- */
26
- export declare function icebergOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, displaySize: number): OrderRequest;
27
- /**
28
- * Iceberg order (full params).
29
- * Pass `priceType` as empty string to use server default (LIMIT_PRICE).
24
+ * Iceberg order. `displaySize` is required; all other parameters are optional.
25
+ * Pass `priceType` as empty string to use the server default (LIMIT_PRICE).
30
26
  * Pass `startTime` / `endTime` as 0 to omit the time window.
31
27
  */
32
- export declare function icebergOrderFull(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, displaySize: number, minDisplaySize?: number, checkIntervals?: number, priceType?: PriceType | string, startTime?: number, endTime?: number): OrderRequest;
28
+ export declare function icebergOrder(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, displaySize: number, minDisplaySize?: number, checkIntervals?: number, priceType?: PriceType | string, startTime?: number, endTime?: number): OrderRequest;
33
29
  /** Attached profit / loss leg */
34
30
  export declare function orderLeg(legType: string, price: number, timeInForce: string): OrderLegRequest;
31
+ /**
32
+ * Market order by cash amount (instead of quantity).
33
+ * Server uses `isQuantityByAmount=true` + `amount` field.
34
+ */
35
+ export declare function marketOrderByAmount(account: string, symbol: string, secType: string, action: string, amount: number): OrderRequest;
36
+ /**
37
+ * Limit order by cash amount (instead of quantity).
38
+ */
39
+ export declare function limitOrderByAmount(account: string, symbol: string, secType: string, action: string, amount: number, limitPrice: number): OrderRequest;
40
+ /**
41
+ * Trailing stop order using a fixed price offset (auxPrice) instead of a percentage.
42
+ * Use `trailOrder()` for percentage-based trailing stops.
43
+ */
44
+ export declare function trailOrderByPrice(account: string, symbol: string, secType: string, action: string, quantity: number, auxPrice: number): OrderRequest;
45
+ /**
46
+ * Limit order with attached profit/loss legs (bracket order).
47
+ * At most 2 legs are supported.
48
+ *
49
+ * @param orderLegs - Array of `OrderLegRequest` (use `orderLeg()` helper)
50
+ */
51
+ export declare function limitOrderWithLegs(account: string, symbol: string, secType: string, action: string, quantity: number, limitPrice: number, orderLegs: OrderLegRequest[]): OrderRequest;
52
+ /**
53
+ * Multi-leg (combo/MLEG) order for options combos.
54
+ *
55
+ * @param contractLegs - Array of `ContractLegRequest` (use `contractLeg()` helper)
56
+ * @param comboType - e.g. `'MLEG'`
57
+ */
58
+ export declare function comboOrder(account: string, action: string, quantity: number, orderType: string, contractLegs: ContractLegRequest[], comboType?: string, limitPrice?: number, auxPrice?: number, trailingPercent?: number): OrderRequest;
59
+ /**
60
+ * OCA (One-Cancels-All) order.
61
+ * Server expects `orderType: 'OCA'` and an `ocaOrders` list.
62
+ *
63
+ * @param ocaOrders - The contained orders (use any order helper to build each)
64
+ */
65
+ export declare function ocaOrder(account: string, symbol: string, secType: string, action: string, quantity: number, ocaOrders: OrderRequest[]): OrderRequest;
66
+ /**
67
+ * Build a single leg for a multi-leg (MLEG / combo) order.
68
+ *
69
+ * @param symbol - Underlying symbol
70
+ * @param secType - Security type (e.g. `'OPT'`)
71
+ * @param action - `'BUY'` or `'SELL'`
72
+ * @param ratio - Number of contracts for this leg
73
+ */
74
+ export declare function contractLeg(symbol: string, secType: string, action: string, ratio: number, expiry?: string, strike?: string, right?: string): ContractLegRequest;
@@ -149,7 +149,12 @@ export interface OrderRequest {
149
149
  segType?: string;
150
150
  /** 按金额下单:委托金额 */
151
151
  amount?: number;
152
- /** 是否按金额下单 */
152
+ /** 按金额下单:现金金额(wire: cash_amount,与 amount 二选一) */
153
+ cashAmount?: number;
154
+ /**
155
+ * @deprecated 服务端不再需要此字段,by-amount 订单直接设置 `cashAmount`。
156
+ * 保留仅为向前兼容,新代码勿使用。
157
+ */
153
158
  isQuantityByAmount?: boolean;
154
159
  /** 账户分配列表(机构账户) */
155
160
  allocAccounts?: string[];
@@ -173,6 +178,8 @@ export interface OrderRequest {
173
178
  ocaOrders?: OrderRequest[];
174
179
  /** 多腿期权各腿(MLEG) */
175
180
  contractLegs?: ContractLegRequest[];
181
+ /** 组合单类型(如 MLEG) */
182
+ comboType?: string;
176
183
  }
177
184
  /** Single leg of a multi-leg option order (MLEG) */
178
185
  export interface ContractLegRequest {
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { HttpClient } from '../client/http-client';
9
9
  import type { ClientConfig } from '../config/client-config';
10
+ import type { TokenManager } from '../config/token-manager';
10
11
  import type { MarketState, Brief, Kline, KlineItem, Timeline, TradeTick, Depth, OptionExpiration, OptionChain, OptionChainFilter, FutureExchange, FutureContractInfo, FutureQuote, FutureKline, FutureKlineItem, FinancialDailyItem, FinancialReportItem, CorporateAction, CorporateSymbolChange, CorporateDelisting, CorporateIPO, CapitalFlow, CapitalDistribution, ScannerResult, QuotePermission, MarketScannerRequest, SymbolName, TradeMeta, StockDetail, StockBroker, StockIndustry, TradeRankItem, ShortInterest, KlineQuota, OptionAnalysis, OptionSymbol, FutureMainContractHistory, FutureTradingTime, FutureTradeTickItem, FutureDepth, WarrantBrief, WarrantFilterResult, IndustryItem, IndustryStock, TradingCalendarItem, ExchangeRate, FinancialCurrency, QuoteOvernight, MarketScannerTagGroup, FundContractInfo, FundQuote, FundHistoryQuote, FinancialDailyRequest, FinancialReportRequest, CorporateActionRequest } from '../model/quote';
11
12
  import type { BriefRequest, DepthQuoteRequest, TradeTickRequest, FutureBriefRequest, SymbolsRequest, TradeMetasRequest, StockDetailsRequest, StockDelayBriefsRequest, KlineRequest, KlineByPageRequest, TimelineHistoryRequest, TradeRankRequest, ShortInterestRequest, StockBrokerRequest, StockFundamentalRequest, StockIndustryRequest, KlineQuotaRequest, QuotePermissionRequest, OptionTradeTicksRequest, OptionTimelineRequest, OptionDepthRequest, OptionSymbolsRequest, OptionAnalysisRequest, FutureContractSingleRequest, AllFutureContractsRequest, FutureContinuousContractsRequest, FutureHistoryMainContractRequest, FutureKlineRequest, FutureKlineByPageRequest, FutureTradeTicksRequest, FutureDepthRequest, FutureTradingTimesRequest, FundSymbolsRequest, FundContractsRequest, FundQuoteRequest, FundHistoryQuoteRequest, WarrantBriefsRequest, WarrantFilterRequest, IndustryListRequest, IndustryStocksRequest, TradingCalendarRequest, FinancialExchangeRateRequest, FinancialCurrencyRequest, MarketScannerTagsRequest, QuoteOvernightRequest } from '../model/quote-requests';
12
13
  /**
@@ -28,6 +29,18 @@ export declare class QuoteClient {
28
29
  constructor(httpClient: HttpClient);
29
30
  /** Create a QuoteClient directly from a ClientConfig — no need to construct HttpClient manually. */
30
31
  static fromConfig(config: ClientConfig): QuoteClient;
32
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
33
+ queryToken(): Promise<string>;
34
+ /** Refresh the token and update the in-memory config token. */
35
+ refreshToken(tokenManager?: TokenManager | null): Promise<void>;
36
+ /**
37
+ * Start background token auto-refresh. Returns a TokenManager to stop with `tm.stopAutoRefresh()`.
38
+ *
39
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
40
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
41
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
42
+ */
43
+ startTokenAutoRefresh(refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
31
44
  private callInto;
32
45
  /**
33
46
  * Some endpoints return either a list or a single object depending on the
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { HttpClient } from '../client/http-client';
11
11
  import type { ClientConfig } from '../config/client-config';
12
+ import type { TokenManager } from '../config/token-manager';
12
13
  import type { OrderRequest, Order } from '../model/order';
13
14
  import type { Contract } from '../model/contract';
14
15
  import type { Position } from '../model/position';
@@ -22,6 +23,24 @@ export declare class TradeClient {
22
23
  constructor(httpClient: HttpClient, account: string, secretKey?: string);
23
24
  /** Create a TradeClient directly from a ClientConfig — no need to construct HttpClient manually. */
24
25
  static fromConfig(config: ClientConfig, account: string, secretKey?: string): TradeClient;
26
+ /** Call the `user_token_refresh` API and return the new token. Read-only. */
27
+ queryToken(): Promise<string>;
28
+ /**
29
+ * Refresh the token: call the API, update the in-memory config token, and
30
+ * optionally persist via the provided TokenManager (file + writer callback).
31
+ *
32
+ * @param tokenManager - optional TokenManager for file persistence and writer callback
33
+ */
34
+ refreshToken(tokenManager?: TokenManager | null): Promise<void>;
35
+ /**
36
+ * Start background token auto-refresh. Returns a TokenManager that can be
37
+ * used to stop the background task via `tm.stopAutoRefresh()`.
38
+ *
39
+ * @param refreshDurationSecs - Refresh threshold in seconds (minimum 30).
40
+ * @param checkIntervalMs - How often to check, in milliseconds (default 300 000 / 5 min).
41
+ * @param tokenWriter - Optional callback invoked after each successful refresh.
42
+ */
43
+ startTokenAutoRefresh(refreshDurationSecs: number, checkIntervalMs?: number, tokenWriter?: (token: string) => void): TokenManager;
25
44
  private callInto;
26
45
  /** Strip `{items: [...]}` envelope used by most trade read endpoints. */
27
46
  private callIntoItems;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tigeropenapi/tigeropen",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Tiger Brokers OpenAPI TypeScript SDK for market data, trading, and real-time push",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",