@tigeropenapi/tigeropen 0.3.0 → 0.4.5

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.
Files changed (64) hide show
  1. package/dist/cjs/client/case-convert.js +4 -3
  2. package/dist/cjs/client/http-client.js +123 -6
  3. package/dist/cjs/config/client-config.js +56 -12
  4. package/dist/cjs/config/index.js +3 -1
  5. package/dist/cjs/config/token-manager.js +54 -4
  6. package/dist/cjs/index.js +51 -2
  7. package/dist/cjs/model/enums.js +89 -7
  8. package/dist/cjs/model/order-status.js +46 -0
  9. package/dist/cjs/model/quote-requests.js +11 -0
  10. package/dist/cjs/model/trade-requests.js +13 -0
  11. package/dist/cjs/push/pb/OrderStatusData.js +24 -0
  12. package/dist/cjs/push/proto-message.js +6 -0
  13. package/dist/cjs/push/push-client.js +111 -16
  14. package/dist/cjs/push/push-message.js +4 -0
  15. package/dist/cjs/quote/quote-client.js +333 -9
  16. package/dist/cjs/trade/trade-client.js +204 -25
  17. package/dist/esm/client/api-request.js +1 -1
  18. package/dist/esm/client/api-response.js +1 -1
  19. package/dist/esm/client/case-convert.js +4 -3
  20. package/dist/esm/client/http-client.js +128 -11
  21. package/dist/esm/client/index.js +6 -6
  22. package/dist/esm/config/client-config.js +59 -15
  23. package/dist/esm/config/index.js +4 -3
  24. package/dist/esm/config/token-manager.js +55 -5
  25. package/dist/esm/index.js +15 -1
  26. package/dist/esm/logger/index.js +1 -1
  27. package/dist/esm/model/contract-helpers.js +1 -1
  28. package/dist/esm/model/enums.js +87 -6
  29. package/dist/esm/model/order-helpers.js +1 -1
  30. package/dist/esm/model/order-status.js +43 -0
  31. package/dist/esm/model/quote-requests.js +10 -0
  32. package/dist/esm/model/trade-requests.js +12 -0
  33. package/dist/esm/push/index.js +5 -5
  34. package/dist/esm/push/pb/OrderStatusData.js +24 -0
  35. package/dist/esm/push/pb/PushData.js +11 -11
  36. package/dist/esm/push/pb/QuoteBasicData.js +1 -1
  37. package/dist/esm/push/pb/Response.js +1 -1
  38. package/dist/esm/push/pb/index.js +17 -17
  39. package/dist/esm/push/proto-message.js +9 -3
  40. package/dist/esm/push/push-client.js +118 -23
  41. package/dist/esm/push/push-message.js +4 -0
  42. package/dist/esm/quote/index.js +1 -1
  43. package/dist/esm/quote/quote-client.js +335 -11
  44. package/dist/esm/signer/index.js +2 -2
  45. package/dist/esm/trade/index.js +1 -1
  46. package/dist/esm/trade/trade-client.js +206 -27
  47. package/dist/types/client/case-convert.d.ts +3 -1
  48. package/dist/types/client/http-client.d.ts +32 -1
  49. package/dist/types/config/client-config.d.ts +16 -1
  50. package/dist/types/config/index.d.ts +2 -0
  51. package/dist/types/config/token-manager.d.ts +27 -3
  52. package/dist/types/index.d.ts +22 -1
  53. package/dist/types/model/enums.d.ts +60 -6
  54. package/dist/types/model/order-status.d.ts +14 -0
  55. package/dist/types/model/quote-requests.d.ts +344 -0
  56. package/dist/types/model/quote.d.ts +261 -0
  57. package/dist/types/model/trade-requests.d.ts +260 -0
  58. package/dist/types/model/trade.d.ts +214 -1
  59. package/dist/types/push/pb/OrderStatusData.d.ts +4 -0
  60. package/dist/types/push/push-client.d.ts +36 -3
  61. package/dist/types/push/push-message.d.ts +4 -0
  62. package/dist/types/quote/quote-client.d.ts +121 -6
  63. package/dist/types/trade/trade-client.d.ts +95 -12
  64. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
- import { createApiRequest } from '../client/api-request';
2
- import { unmarshalData } from '../client/api-response';
1
+ import { createApiRequest } from '../client/api-request.js';
2
+ import { unmarshalData } from '../client/api-response.js';
3
3
  /**
4
4
  * Parse an OCC-style option identifier like "AAPL 260619C00150000"
5
5
  * into its component parts.
@@ -41,12 +41,31 @@ export class QuoteClient {
41
41
  const response = await this.httpClient.executeRequest(request);
42
42
  return unmarshalData(response.data);
43
43
  }
44
+ /**
45
+ * Some endpoints return either a list or a single object depending on the
46
+ * server response shape (future_contract_by_contract_code /
47
+ * future_continuous_contracts). Unify into an array.
48
+ */
49
+ async callIntoListOrObject(method, bizParams, version) {
50
+ const raw = await this.callInto(method, bizParams, version);
51
+ if (raw == null)
52
+ return [];
53
+ if (Array.isArray(raw))
54
+ return raw;
55
+ return [raw];
56
+ }
57
+ /** Unwrap server {"items":[...]} envelope. */
58
+ async callIntoItems(method, bizParams, version) {
59
+ const wrap = await this.callInto(method, bizParams, version);
60
+ return wrap?.items ?? [];
61
+ }
44
62
  // === Basic market data ===
45
63
  async getMarketState(market) {
46
64
  return this.callInto('market_state', { market });
47
65
  }
48
- async getBrief(symbols) {
49
- return this.callInto('quote_real_time', { symbols });
66
+ /** Real-time stock briefs. wire: quote_real_time */
67
+ async getBrief(req) {
68
+ return this.callInto('quote_real_time', req);
50
69
  }
51
70
  async getKline(symbol, period) {
52
71
  return this.callInto('kline', { symbols: [symbol], period });
@@ -54,12 +73,13 @@ export class QuoteClient {
54
73
  async getTimeline(symbols) {
55
74
  return this.callInto('timeline', { symbols });
56
75
  }
57
- async getTradeTick(symbols) {
58
- return this.callInto('trade_tick', { symbols });
76
+ /** Tick-by-tick trades. wire: trade_tick */
77
+ async getTradeTick(req) {
78
+ return this.callInto('trade_tick', req);
59
79
  }
60
- /** Depth snapshot. market is required (US / HK supported). */
61
- async getQuoteDepth(symbol, market) {
62
- return this.callInto('quote_depth', { symbols: [symbol], market });
80
+ /** Depth snapshot. wire: quote_depth */
81
+ async getQuoteDepth(req) {
82
+ return this.callInto('quote_depth', req);
63
83
  }
64
84
  // === Options ===
65
85
  async getOptionExpiration(symbol) {
@@ -94,8 +114,9 @@ export class QuoteClient {
94
114
  async getFutureContracts(exchange) {
95
115
  return this.callInto('future_contract_by_exchange_code', { exchangeCode: exchange });
96
116
  }
97
- async getFutureRealTimeQuote(contractCodes) {
98
- return this.callInto('future_real_time_quote', { contractCodes });
117
+ /** Real-time futures quotes. wire: future_real_time_quote */
118
+ async getFutureRealTimeQuote(req) {
119
+ return this.callInto('future_real_time_quote', req);
99
120
  }
100
121
  /** Futures K-line; use -1 for unbounded beginTime / endTime. */
101
122
  async getFutureKline(req) {
@@ -136,4 +157,307 @@ export class QuoteClient {
136
157
  async grabQuotePermission() {
137
158
  return this.callInto('grab_quote_permission');
138
159
  }
160
+ // ==========================================================================
161
+ // Batch 3: stock basics + time series
162
+ // ==========================================================================
163
+ /** All symbol codes (string list). wire: all_symbols */
164
+ async getSymbols(req) {
165
+ return this.callInto('all_symbols', req);
166
+ }
167
+ /** All symbols with names. wire: all_symbol_names */
168
+ async getSymbolNames(req) {
169
+ return this.callInto('all_symbol_names', req);
170
+ }
171
+ /** Trade meta (lot size / tick size). wire: quote_stock_trade */
172
+ async getTradeMetas(req) {
173
+ return this.callInto('quote_stock_trade', req);
174
+ }
175
+ /** Stock details. wire: stock_detail. Server returns {items:[...]}. */
176
+ async getStockDetails(req) {
177
+ return this.callIntoItems('stock_detail', req);
178
+ }
179
+ /** Delayed stock briefs. wire: quote_delay */
180
+ async getStockDelayBriefs(req) {
181
+ return this.callInto('quote_delay', req);
182
+ }
183
+ /** K-line bars (full request). wire: kline */
184
+ async getBars(req) {
185
+ return this.callInto('kline', req);
186
+ }
187
+ /**
188
+ * Client-side paginated K-line fetch — loops over getBars until TotalSize
189
+ * bars are collected. Items are returned oldest-first, matching
190
+ * Python/Go get_bars_by_page behaviour.
191
+ */
192
+ async getBarsByPage(req) {
193
+ const pageSize = req.pageSize && req.pageSize > 0 ? req.pageSize : 200;
194
+ const totalSize = req.totalSize && req.totalSize > 0 ? req.totalSize : 1000;
195
+ let beginTime = req.beginTime ?? -1;
196
+ let endTime = req.endTime ?? -1;
197
+ if (beginTime === 0)
198
+ beginTime = -1;
199
+ if (endTime === 0)
200
+ endTime = -1;
201
+ const acc = [];
202
+ while (acc.length < totalSize) {
203
+ const sub = {
204
+ symbols: req.symbol ? [req.symbol] : undefined,
205
+ period: req.period,
206
+ right: req.right,
207
+ beginTime,
208
+ endTime,
209
+ limit: pageSize,
210
+ tradeSession: req.tradeSession,
211
+ lang: req.lang,
212
+ };
213
+ const pageOut = await this.callInto('kline', sub);
214
+ if (!pageOut || pageOut.length === 0 || !pageOut[0].items || pageOut[0].items.length === 0) {
215
+ break;
216
+ }
217
+ const items = pageOut[0].items;
218
+ acc.push(...items);
219
+ if (items.length < pageSize)
220
+ break;
221
+ // next page endTime = oldest bar time - 1
222
+ let oldest = items[0].time;
223
+ for (const it of items) {
224
+ if (it.time < oldest)
225
+ oldest = it.time;
226
+ }
227
+ endTime = oldest - 1;
228
+ }
229
+ return acc;
230
+ }
231
+ /** Historical intraday timeline. wire: history_timeline */
232
+ async getTimelineHistory(req) {
233
+ return this.callInto('history_timeline', req);
234
+ }
235
+ /** Trade rank (top movers / volume). wire: trade_rank */
236
+ async getTradeRank(req) {
237
+ return this.callInto('trade_rank', req);
238
+ }
239
+ /** Short interest / shortable. wire: quote_shortable_stocks */
240
+ async getShortInterest(req) {
241
+ return this.callInto('quote_shortable_stocks', req);
242
+ }
243
+ /** Broker queue. wire: stock_broker */
244
+ async getStockBroker(req) {
245
+ return this.callInto('stock_broker', req);
246
+ }
247
+ /** Stock fundamentals (server returns grouped map). wire: stock_fundamental */
248
+ async getStockFundamental(req) {
249
+ const out = await this.callInto('stock_fundamental', req);
250
+ return out ?? {};
251
+ }
252
+ /** Stock industry classification (array). wire: stock_industry */
253
+ async getStockIndustry(req) {
254
+ return this.callInto('stock_industry', req);
255
+ }
256
+ /** Quote permission detail. wire: get_quote_permission */
257
+ async getQuotePermission(req) {
258
+ return this.callInto('get_quote_permission', req);
259
+ }
260
+ /** K-line quota usage. wire: kline_quota */
261
+ async getKlineQuota(req) {
262
+ return this.callInto('kline_quota', req);
263
+ }
264
+ // ==========================================================================
265
+ // Batch 4: option / future extensions
266
+ // ==========================================================================
267
+ /** Option K-line. wire: option_kline (v2.0) */
268
+ async getOptionBars(req) {
269
+ return this.callInto('option_kline', req, '2.0');
270
+ }
271
+ /** Option tick trades. wire: option_trade_tick */
272
+ async getOptionTradeTicks(req) {
273
+ return this.callInto('option_trade_tick', req);
274
+ }
275
+ /** Option intraday timeline. wire: option_timeline */
276
+ async getOptionTimeline(req) {
277
+ return this.callInto('option_timeline', req);
278
+ }
279
+ /** Option depth. wire: option_depth */
280
+ async getOptionDepth(req) {
281
+ return this.callInto('option_depth', req);
282
+ }
283
+ /** Available option symbols. wire: option_symbol */
284
+ async getOptionSymbols(req) {
285
+ return this.callInto('option_symbol', req);
286
+ }
287
+ /** Option analysis (volatility). wire: option_analysis */
288
+ async getOptionAnalysis(req) {
289
+ return this.callInto('option_analysis', req);
290
+ }
291
+ /** Single futures contract by code. wire: future_contract_by_contract_code */
292
+ async getFutureContract(req) {
293
+ return this.callIntoListOrObject('future_contract_by_contract_code', req);
294
+ }
295
+ /** All futures contracts. wire: future_contracts */
296
+ async getAllFutureContracts(req) {
297
+ return this.callInto('future_contracts', req);
298
+ }
299
+ /** Current main contract. wire: future_current_contract */
300
+ async getCurrentFutureContract(req) {
301
+ return this.callInto('future_current_contract', req);
302
+ }
303
+ /** Continuous main contracts. wire: future_continuous_contracts */
304
+ async getFutureContinuousContracts(req) {
305
+ return this.callIntoListOrObject('future_continuous_contracts', req);
306
+ }
307
+ /** Historical main contracts. wire: future_main_contract */
308
+ async getFutureHistoryMainContract(req) {
309
+ return this.callInto('future_main_contract', req);
310
+ }
311
+ /**
312
+ * Futures K-line (full request with index pagination). wire: future_kline
313
+ * begin_time / end_time default to -1 when unset (server requires them present).
314
+ */
315
+ async getFutureBars(req) {
316
+ const body = {
317
+ ...req,
318
+ beginTime: req.beginTime ?? -1,
319
+ endTime: req.endTime ?? -1,
320
+ };
321
+ return this.callInto('future_kline', body);
322
+ }
323
+ /** Client-side paginated futures K-line fetch. */
324
+ async getFutureBarsByPage(req) {
325
+ const pageSize = req.pageSize && req.pageSize > 0 ? req.pageSize : 200;
326
+ const totalSize = req.totalSize && req.totalSize > 0 ? req.totalSize : 1000;
327
+ let beginTime = req.beginTime ?? -1;
328
+ let endTime = req.endTime ?? -1;
329
+ if (beginTime === 0)
330
+ beginTime = -1;
331
+ if (endTime === 0)
332
+ endTime = -1;
333
+ const acc = [];
334
+ while (acc.length < totalSize) {
335
+ const sub = {
336
+ contractCode: req.contractCode,
337
+ period: req.period,
338
+ beginTime,
339
+ endTime,
340
+ limit: pageSize,
341
+ lang: req.lang,
342
+ };
343
+ const pageOut = await this.callInto('future_kline', sub);
344
+ if (!pageOut || pageOut.length === 0 || !pageOut[0].items || pageOut[0].items.length === 0) {
345
+ break;
346
+ }
347
+ const items = pageOut[0].items;
348
+ acc.push(...items);
349
+ if (items.length < pageSize)
350
+ break;
351
+ let oldest = items[0].time;
352
+ for (const it of items) {
353
+ if (it.time < oldest)
354
+ oldest = it.time;
355
+ }
356
+ endTime = oldest - 1;
357
+ }
358
+ return acc;
359
+ }
360
+ /** Futures tick trades. wire: future_tick (API v3.0)
361
+ * Server returns {contractCode, items:[...]}; unwrap items and backfill contractCode.
362
+ * endIndex defaults to 30 when not set (consistent with Python/Go SDK). */
363
+ async getFutureTradeTicks(req) {
364
+ if (!req.endIndex)
365
+ req.endIndex = 30;
366
+ const wrap = await this.callInto('future_tick', req, '3.0');
367
+ const items = wrap?.items ?? [];
368
+ if (wrap?.contractCode) {
369
+ for (const item of items) {
370
+ if (!item.contractCode)
371
+ item.contractCode = wrap.contractCode;
372
+ }
373
+ }
374
+ return items;
375
+ }
376
+ /** Futures depth. wire: future_depth */
377
+ async getFutureDepth(req) {
378
+ return this.callInto('future_depth', req);
379
+ }
380
+ /** Futures trading times (single-object response). wire: future_trading_date */
381
+ async getFutureTradingTimes(req) {
382
+ return this.callInto('future_trading_date', req);
383
+ }
384
+ // ==========================================================================
385
+ // Batch 5: fund / warrant / industry / corporate / financial / calendar
386
+ // ==========================================================================
387
+ /** Fund symbols. wire: fund_all_symbols */
388
+ async getFundSymbols(req) {
389
+ return this.callInto('fund_all_symbols', req);
390
+ }
391
+ /** Fund contracts. wire: fund_contracts */
392
+ async getFundContracts(req) {
393
+ return this.callInto('fund_contracts', req);
394
+ }
395
+ /** Fund real-time NAV. wire: fund_quote */
396
+ async getFundQuote(req) {
397
+ return this.callInto('fund_quote', req);
398
+ }
399
+ /** Fund historical NAV. wire: fund_history_quote */
400
+ async getFundHistoryQuote(req) {
401
+ return this.callInto('fund_history_quote', req);
402
+ }
403
+ /** Warrant briefs. wire: warrant_briefs */
404
+ async getWarrantBriefs(req) {
405
+ return this.callInto('warrant_briefs', req);
406
+ }
407
+ /** Warrant filter (paged). wire: warrant_filter */
408
+ async getWarrantFilter(req) {
409
+ return this.callInto('warrant_filter', req);
410
+ }
411
+ /** Industry list. wire: industry_list */
412
+ async getIndustryList(req) {
413
+ return this.callInto('industry_list', req);
414
+ }
415
+ /** Stocks inside an industry. wire: industry_stock_list */
416
+ async getIndustryStocks(req) {
417
+ return this.callInto('industry_stock_list', req);
418
+ }
419
+ /** Corporate split (flattened). wire: corporate_action (action_type=split) */
420
+ async getCorporateSplit(req) {
421
+ const body = { ...req, actionType: 'split' };
422
+ const grouped = await this.callInto('corporate_action', body);
423
+ if (!grouped || typeof grouped !== 'object')
424
+ return [];
425
+ return Object.values(grouped).flat();
426
+ }
427
+ /** Corporate dividend (flattened). wire: corporate_action (action_type=dividend) */
428
+ async getCorporateDividend(req) {
429
+ const body = { ...req, actionType: 'dividend' };
430
+ const grouped = await this.callInto('corporate_action', body);
431
+ if (!grouped || typeof grouped !== 'object')
432
+ return [];
433
+ return Object.values(grouped).flat();
434
+ }
435
+ /** Corporate earnings calendar (flattened). wire: corporate_action (action_type=earning) */
436
+ async getCorporateEarningsCalendar(req) {
437
+ const body = { ...req, actionType: 'earning' };
438
+ const grouped = await this.callInto('corporate_action', body);
439
+ if (!grouped || typeof grouped !== 'object')
440
+ return [];
441
+ return Object.values(grouped).flat();
442
+ }
443
+ /** Financial currency per symbol. wire: financial_currency */
444
+ async getFinancialCurrency(req) {
445
+ return this.callInto('financial_currency', req);
446
+ }
447
+ /** FX rates. wire: financial_exchange_rate */
448
+ async getFinancialExchangeRate(req) {
449
+ return this.callInto('financial_exchange_rate', req);
450
+ }
451
+ /** Trading calendar. wire: trading_calendar */
452
+ async getTradingCalendar(req) {
453
+ return this.callInto('trading_calendar', req);
454
+ }
455
+ /** Available market-scanner tags. wire: market_scanner_tags */
456
+ async getMarketScannerTags(req) {
457
+ return this.callInto('market_scanner_tags', req);
458
+ }
459
+ /** Overnight quote. wire: quote_overnight */
460
+ async getQuoteOvernight(req) {
461
+ return this.callInto('quote_overnight', req);
462
+ }
139
463
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * 认证层(RSA Signer)统一导出
3
3
  */
4
- export { loadPrivateKey, signWithRSA, verifyWithRSA } from './signer';
5
- export { getSignContent } from './sign-content';
4
+ export { loadPrivateKey, signWithRSA, verifyWithRSA } from './signer.js';
5
+ export { getSignContent } from './sign-content.js';
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * 交易模块导出
3
3
  */
4
- export { TradeClient } from './trade-client';
4
+ export { TradeClient } from './trade-client.js';
@@ -1,5 +1,25 @@
1
- import { createApiRequest } from '../client/api-request';
2
- import { unmarshalData } from '../client/api-response';
1
+ import { createApiRequest } from '../client/api-request.js';
2
+ import { unmarshalData } from '../client/api-response.js';
3
+ import { normalizeOrderStatus } from '../model/order-status.js';
4
+ /** Normalize `Order.status` field in-place (handles int → string). */
5
+ function normalizeOrderInPlace(o) {
6
+ if (o && o.status !== undefined && o.status !== null) {
7
+ o.status = normalizeOrderStatus(o.status);
8
+ }
9
+ }
10
+ /** Normalize every Order in a list in-place. */
11
+ function normalizeOrders(orders) {
12
+ for (const o of orders)
13
+ normalizeOrderInPlace(o);
14
+ return orders;
15
+ }
16
+ /** Shallow-copy a request object and fill account if empty. */
17
+ function withAccount(req, account) {
18
+ const r = { ...(req ?? {}) };
19
+ if (!r.account)
20
+ r.account = account;
21
+ return r;
22
+ }
3
23
  /** Trading client wrapping all trade-related APIs. */
4
24
  export class TradeClient {
5
25
  constructor(httpClient, account) {
@@ -51,39 +71,198 @@ export class TradeClient {
51
71
  async cancelOrder(id) {
52
72
  return this.callInto('cancel_order', { account: this.account, id });
53
73
  }
54
- // === Order queries ===
55
- async getOrders() {
56
- return this.callIntoItems('orders', { account: this.account });
74
+ // === Order queries (BREAKING v0.4.0) ===
75
+ /**
76
+ * Query all historical orders. v0.4.0: optional OrdersRequest for filtering.
77
+ *
78
+ * @example
79
+ * // Default (unfiltered)
80
+ * await tc.getOrders();
81
+ * // Filter by status
82
+ * await tc.getOrders({ states: ['Filled'], limit: 100 });
83
+ */
84
+ async getOrders(req) {
85
+ return normalizeOrders(await this.callIntoItems('orders', withAccount(req, this.account)));
57
86
  }
58
- async getActiveOrders() {
59
- return this.callIntoItems('active_orders', { account: this.account });
87
+ /** Query active (open) orders. v0.4.0: supports ParentId to filter attached legs. */
88
+ async getActiveOrders(req) {
89
+ return normalizeOrders(await this.callIntoItems('active_orders', withAccount(req, this.account)));
60
90
  }
61
- async getInactiveOrders() {
62
- return this.callIntoItems('inactive_orders', { account: this.account });
91
+ /** Query inactive/cancelled orders. */
92
+ async getInactiveOrders(req) {
93
+ return normalizeOrders(await this.callIntoItems('inactive_orders', withAccount(req, this.account)));
63
94
  }
64
95
  /**
65
- * Filled orders in a time range (ms timestamps required by the server).
66
- * Use `Date.now() - 30*24*3600*1000` for "last 30 days".
96
+ * Query filled orders. v0.4.0 BREAKING: signature changed from positional
97
+ * (startDateMs, endDateMs) to OrdersRequest object.
98
+ *
99
+ * @example
100
+ * // Last 30 days
101
+ * const now = Date.now();
102
+ * await tc.getFilledOrders({ startDate: now - 30*24*3600*1000, endDate: now });
67
103
  */
68
- async getFilledOrders(startDateMs, endDateMs) {
69
- return this.callIntoItems('filled_orders', {
70
- account: this.account, startDate: startDateMs, endDate: endDateMs,
71
- });
104
+ async getFilledOrders(req) {
105
+ return normalizeOrders(await this.callIntoItems('filled_orders', withAccount(req, this.account)));
72
106
  }
73
- /** Transactions for a specific order; `symbol` and `secType` are required. */
74
- async getOrderTransactions(id, symbol, secType) {
75
- return this.callIntoItems('order_transactions', {
76
- account: this.account, orderId: id, symbol, secType,
77
- });
107
+ /**
108
+ * Get a single order by ID (v0.4.0 new).
109
+ * Wire method: `orders` with id/order_id param; server returns a single Order object
110
+ * (not `{items:[]}` envelope).
111
+ *
112
+ * Returns `undefined` if no match.
113
+ */
114
+ async getOrder(req) {
115
+ const merged = withAccount(req, this.account);
116
+ const out = await this.callInto('orders', merged);
117
+ if (!out || (!out.id && !out.orderId))
118
+ return undefined;
119
+ normalizeOrderInPlace(out);
120
+ return out;
121
+ }
122
+ /**
123
+ * Query order transaction details. v0.4.0 BREAKING: all fields now optional
124
+ * (previously symbol/secType required).
125
+ */
126
+ async getOrderTransactions(req) {
127
+ return this.callIntoItems('order_transactions', withAccount(req, this.account));
128
+ }
129
+ // === Positions & assets (BREAKING v0.4.0) ===
130
+ /** Query positions. v0.4.0: supports Symbol / SecType / Currency / Market filters. */
131
+ async getPositions(req) {
132
+ return this.callIntoItems('positions', withAccount(req, this.account));
133
+ }
134
+ /** Query assets. v0.4.0: supports sub-account list and aggregation options. */
135
+ async getAssets(req) {
136
+ return this.callIntoItems('assets', withAccount(req, this.account));
137
+ }
138
+ /** Query prime assets. v0.4.0: takes AssetsRequest for filters. */
139
+ async getPrimeAssets(req) {
140
+ return this.callInto('prime_assets', withAccount(req, this.account));
141
+ }
142
+ // ===== v0.4.0 NEW: Account management =====
143
+ /** Query managed sub-accounts (institutional). */
144
+ async getManagedAccounts(req) {
145
+ return this.callIntoItems('accounts', withAccount(req, this.account));
146
+ }
147
+ /**
148
+ * Query derivative contracts list. Same wire as getQuoteContract but accepts
149
+ * full request struct. Python: `get_derivative_contracts`.
150
+ */
151
+ async getDerivativeContracts(req) {
152
+ return this.callIntoItems('quote_contract', withAccount(req, this.account));
153
+ }
154
+ // ===== v0.4.0 NEW: Asset analytics =====
155
+ /** Daily P&L / net-value / holding-value analytics. */
156
+ async getAnalyticsAsset(req) {
157
+ return this.callIntoItems('analytics_asset', withAccount(req, this.account));
158
+ }
159
+ /** Aggregate assets (prime) by base currency. */
160
+ async getAggregateAssets(req) {
161
+ return this.callInto('aggregate_assets', withAccount(req, this.account));
162
+ }
163
+ /** Estimate tradable quantity given order parameters. */
164
+ async getEstimateTradableQuantity(req) {
165
+ return this.callInto('estimate_tradable_quantity', withAccount(req, this.account));
166
+ }
167
+ // ===== v0.4.0 NEW: Forex =====
168
+ /** Place forex order (sub-account base-currency swap). */
169
+ async placeForexOrder(req) {
170
+ return this.callInto('place_forex_order', withAccount(req, this.account));
171
+ }
172
+ // ===== v0.4.0 NEW: Segment fund transfer =====
173
+ /** Query amount available for inter-segment transfer. Returns array. */
174
+ async getSegmentFundAvailable(req) {
175
+ return this.callInto('segment_fund_available', withAccount(req, this.account));
176
+ }
177
+ /** Query segment fund transfer history. Server returns plain array (no items wrapper). */
178
+ async getSegmentFundHistory(req) {
179
+ return this.callInto('segment_fund_history', withAccount(req, this.account));
180
+ }
181
+ /** Execute an inter-segment fund transfer. */
182
+ async transferSegmentFund(req) {
183
+ return this.callInto('transfer_segment_fund', withAccount(req, this.account));
184
+ }
185
+ /** Cancel a pending inter-segment transfer. */
186
+ async cancelSegmentFund(req) {
187
+ return this.callInto('cancel_segment_fund', withAccount(req, this.account));
188
+ }
189
+ // ===== v0.4.0 NEW: Fund details / history =====
190
+ /** Fund-movement details (by segment / currency / fund-type). */
191
+ async getFundDetails(req) {
192
+ return this.callIntoItems('fund_details', withAccount(req, this.account));
193
+ }
194
+ /** Funding history (wire method: `transfer_fund`).
195
+ * Server returns bare list (no items wrapper). */
196
+ async getFundingHistory(req) {
197
+ return this.callInto('transfer_fund', withAccount(req, this.account));
198
+ }
199
+ // ===== v0.4.0 NEW: Internal / external position transfer =====
200
+ /**
201
+ * Internal position transfer (cross sub-account).
202
+ * @note Uses `fromAccount` / `toAccount` (not `account`).
203
+ */
204
+ async transferPosition(req) {
205
+ const merged = { ...req };
206
+ if (!merged.fromAccount)
207
+ merged.fromAccount = this.account;
208
+ return this.callInto('position_transfer', merged);
209
+ }
210
+ /** Query internal position transfer records. Uses `accountId` (wire: `account_id`). */
211
+ async getPositionTransferRecords(req) {
212
+ const merged = { ...req };
213
+ if (!merged.accountId)
214
+ merged.accountId = this.account;
215
+ return this.callIntoItems('position_transfer_records', merged);
216
+ }
217
+ /** Query single internal position transfer detail by ID. */
218
+ async getPositionTransferDetail(req) {
219
+ const merged = { ...req };
220
+ if (!merged.accountId)
221
+ merged.accountId = this.account;
222
+ return this.callInto('position_transfer_detail', merged);
223
+ }
224
+ /** Query external position transfer records (DWAC / FOP / etc.). */
225
+ async getPositionTransferExternalRecords(req) {
226
+ const merged = { ...req };
227
+ if (!merged.accountId)
228
+ merged.accountId = this.account;
229
+ return this.callIntoItems('position_transfer_external_records', merged);
230
+ }
231
+ /** 行权检验:预估行权/作废后正股持仓变化 (wire: option_exercise_check) */
232
+ async checkOptionExercise(req) {
233
+ const merged = { ...req };
234
+ if (!merged.account)
235
+ merged.account = this.account;
236
+ return this.callInto('option_exercise_check', merged);
237
+ }
238
+ /** 查询可行权持仓列表 (wire: option_exercise_position) */
239
+ async getOptionExercisePositions(req) {
240
+ const merged = { ...req };
241
+ if (!merged.account)
242
+ merged.account = this.account;
243
+ return this.callInto('option_exercise_position', merged);
78
244
  }
79
- // === Positions & assets ===
80
- async getPositions() {
81
- return this.callIntoItems('positions', { account: this.account });
245
+ /** 提交行权/作废申请 (wire: option_exercise_submit) */
246
+ async submitOptionExercise(req) {
247
+ const merged = { ...req };
248
+ if (!merged.account)
249
+ merged.account = this.account;
250
+ const result = await this.callInto('option_exercise_submit', merged);
251
+ return result ?? false;
82
252
  }
83
- async getAssets() {
84
- return this.callIntoItems('assets', { account: this.account });
253
+ /** 分页查询行权记录 (wire: option_exercise_record) */
254
+ async getOptionExerciseRecords(req) {
255
+ const merged = { ...req };
256
+ if (!merged.account)
257
+ merged.account = this.account;
258
+ return this.callInto('option_exercise_record', merged);
85
259
  }
86
- async getPrimeAssets() {
87
- return this.callInto('prime_assets', { account: this.account });
260
+ /** 撤销行权申请 (wire: option_exercise_cancel) */
261
+ async cancelOptionExercise(req) {
262
+ const merged = { ...req };
263
+ if (!merged.account)
264
+ merged.account = this.account;
265
+ const result = await this.callInto('option_exercise_cancel', merged);
266
+ return result ?? false;
88
267
  }
89
268
  }
@@ -11,6 +11,8 @@ export declare function camelToSnake(key: string): string;
11
11
  /**
12
12
  * Recursively convert all object keys from camelCase to snake_case.
13
13
  * Preserves arrays, primitives, and Date/null/undefined.
14
- * Keys already containing an underscore are kept as-is (already snake_case).
14
+ *
15
+ * Note: camelToSnake is idempotent for pure snake_case keys (no uppercase
16
+ * letters → no replacements), so no pre-check is needed.
15
17
  */
16
18
  export declare function keysToSnakeCase(value: unknown): unknown;