@tigeropenapi/tigeropen 0.1.0 → 0.3.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.
Files changed (129) hide show
  1. package/README.md +475 -104
  2. package/dist/cjs/client/api-request.js +16 -10
  3. package/dist/cjs/client/api-response.js +23 -3
  4. package/dist/cjs/client/case-convert.js +35 -0
  5. package/dist/cjs/client/http-client.js +46 -20
  6. package/dist/cjs/client/index.js +6 -2
  7. package/dist/cjs/config/client-config.js +130 -49
  8. package/dist/cjs/config/domain.js +21 -2
  9. package/dist/cjs/config/index.js +3 -1
  10. package/dist/cjs/index.js +1 -1
  11. package/dist/cjs/model/contract.js +1 -2
  12. package/dist/cjs/model/order-helpers.js +9 -9
  13. package/dist/cjs/model/order.js +5 -2
  14. package/dist/cjs/model/position.js +1 -2
  15. package/dist/cjs/model/quote.js +7 -0
  16. package/dist/cjs/model/trade.js +2 -0
  17. package/dist/cjs/push/index.js +6 -3
  18. package/dist/cjs/push/pb/AssetData.js +208 -0
  19. package/dist/cjs/push/pb/KlineData.js +184 -0
  20. package/dist/cjs/push/pb/OptionTopData.js +427 -0
  21. package/dist/cjs/push/pb/OrderStatusData.js +568 -0
  22. package/dist/cjs/push/pb/OrderTransactionData.js +256 -0
  23. package/dist/cjs/push/pb/PositionData.js +316 -0
  24. package/dist/cjs/push/pb/PushData.js +219 -0
  25. package/dist/cjs/push/pb/QuoteBBOData.js +160 -0
  26. package/dist/cjs/push/pb/QuoteBasicData.js +329 -0
  27. package/dist/cjs/push/pb/QuoteData.js +507 -0
  28. package/dist/cjs/push/pb/QuoteDepthData.js +220 -0
  29. package/dist/cjs/push/pb/Request.js +278 -0
  30. package/dist/cjs/push/pb/Response.js +97 -0
  31. package/dist/cjs/push/pb/SocketCommon.js +86 -0
  32. package/dist/cjs/push/pb/StockTopData.js +199 -0
  33. package/dist/cjs/push/pb/TickData.js +202 -0
  34. package/dist/cjs/push/pb/TradeTickData.js +308 -0
  35. package/dist/cjs/push/pb/index.js +49 -0
  36. package/dist/cjs/push/proto-message.js +129 -0
  37. package/dist/cjs/push/push-client.js +292 -164
  38. package/dist/cjs/push/push-message.js +4 -60
  39. package/dist/cjs/push/varint.js +76 -0
  40. package/dist/cjs/quote/index.js +3 -2
  41. package/dist/cjs/quote/quote-client.js +128 -94
  42. package/dist/cjs/signer/signer.js +10 -10
  43. package/dist/cjs/trade/trade-client.js +56 -62
  44. package/dist/esm/client/api-request.js +14 -8
  45. package/dist/esm/client/api-response.js +22 -3
  46. package/dist/esm/client/case-convert.js +31 -0
  47. package/dist/esm/client/http-client.js +47 -21
  48. package/dist/esm/client/index.js +3 -2
  49. package/dist/esm/config/client-config.js +131 -51
  50. package/dist/esm/config/domain.js +20 -2
  51. package/dist/esm/config/index.js +2 -2
  52. package/dist/esm/index.js +1 -1
  53. package/dist/esm/model/contract.js +1 -2
  54. package/dist/esm/model/order-helpers.js +9 -9
  55. package/dist/esm/model/order.js +5 -2
  56. package/dist/esm/model/position.js +1 -2
  57. package/dist/esm/model/quote.js +6 -0
  58. package/dist/esm/model/trade.js +1 -0
  59. package/dist/esm/push/index.js +4 -2
  60. package/dist/esm/push/pb/AssetData.js +205 -0
  61. package/dist/esm/push/pb/KlineData.js +181 -0
  62. package/dist/esm/push/pb/OptionTopData.js +424 -0
  63. package/dist/esm/push/pb/OrderStatusData.js +565 -0
  64. package/dist/esm/push/pb/OrderTransactionData.js +253 -0
  65. package/dist/esm/push/pb/PositionData.js +313 -0
  66. package/dist/esm/push/pb/PushData.js +216 -0
  67. package/dist/esm/push/pb/QuoteBBOData.js +157 -0
  68. package/dist/esm/push/pb/QuoteBasicData.js +326 -0
  69. package/dist/esm/push/pb/QuoteData.js +504 -0
  70. package/dist/esm/push/pb/QuoteDepthData.js +217 -0
  71. package/dist/esm/push/pb/Request.js +275 -0
  72. package/dist/esm/push/pb/Response.js +94 -0
  73. package/dist/esm/push/pb/SocketCommon.js +83 -0
  74. package/dist/esm/push/pb/StockTopData.js +196 -0
  75. package/dist/esm/push/pb/TickData.js +199 -0
  76. package/dist/esm/push/pb/TradeTickData.js +305 -0
  77. package/dist/esm/push/pb/index.js +25 -0
  78. package/dist/esm/push/proto-message.js +121 -0
  79. package/dist/esm/push/push-client.js +260 -165
  80. package/dist/esm/push/push-message.js +3 -56
  81. package/dist/esm/push/varint.js +72 -0
  82. package/dist/esm/quote/index.js +2 -2
  83. package/dist/esm/quote/quote-client.js +127 -94
  84. package/dist/esm/signer/signer.js +10 -10
  85. package/dist/esm/trade/trade-client.js +56 -62
  86. package/dist/types/client/api-request.d.ts +12 -11
  87. package/dist/types/client/api-response.d.ts +15 -7
  88. package/dist/types/client/case-convert.d.ts +16 -0
  89. package/dist/types/client/http-client.d.ts +26 -14
  90. package/dist/types/client/index.d.ts +3 -2
  91. package/dist/types/config/client-config.d.ts +29 -13
  92. package/dist/types/config/domain.d.ts +9 -0
  93. package/dist/types/config/index.d.ts +2 -2
  94. package/dist/types/index.d.ts +1 -1
  95. package/dist/types/model/contract.d.ts +13 -29
  96. package/dist/types/model/order-helpers.d.ts +21 -20
  97. package/dist/types/model/order.d.ts +101 -55
  98. package/dist/types/model/position.d.ts +26 -24
  99. package/dist/types/model/quote.d.ts +311 -0
  100. package/dist/types/model/trade.d.ts +113 -0
  101. package/dist/types/push/callbacks.d.ts +32 -51
  102. package/dist/types/push/index.d.ts +5 -3
  103. package/dist/types/push/pb/AssetData.d.ts +47 -0
  104. package/dist/types/push/pb/KlineData.d.ts +43 -0
  105. package/dist/types/push/pb/OptionTopData.d.ts +76 -0
  106. package/dist/types/push/pb/OrderStatusData.d.ts +96 -0
  107. package/dist/types/push/pb/OrderTransactionData.d.ts +51 -0
  108. package/dist/types/push/pb/PositionData.d.ts +63 -0
  109. package/dist/types/push/pb/PushData.d.ts +46 -0
  110. package/dist/types/push/pb/QuoteBBOData.d.ts +35 -0
  111. package/dist/types/push/pb/QuoteBasicData.d.ts +66 -0
  112. package/dist/types/push/pb/QuoteData.d.ts +94 -0
  113. package/dist/types/push/pb/QuoteDepthData.d.ts +37 -0
  114. package/dist/types/push/pb/Request.d.ts +44 -0
  115. package/dist/types/push/pb/Response.d.ts +30 -0
  116. package/dist/types/push/pb/SocketCommon.d.ts +64 -0
  117. package/dist/types/push/pb/StockTopData.d.ts +37 -0
  118. package/dist/types/push/pb/TickData.d.ts +44 -0
  119. package/dist/types/push/pb/TradeTickData.d.ts +53 -0
  120. package/dist/types/push/pb/index.d.ts +39 -0
  121. package/dist/types/push/proto-message.d.ts +33 -0
  122. package/dist/types/push/push-client.d.ts +69 -68
  123. package/dist/types/push/push-message.d.ts +3 -147
  124. package/dist/types/push/varint.d.ts +23 -0
  125. package/dist/types/quote/index.d.ts +2 -2
  126. package/dist/types/quote/quote-client.d.ts +41 -47
  127. package/dist/types/signer/signer.d.ts +6 -6
  128. package/dist/types/trade/trade-client.d.ts +34 -38
  129. package/package.json +11 -6
@@ -1,39 +1,9 @@
1
1
  /**
2
- * 推送消息类型定义和数据结构
2
+ * 推送消息类型定义
3
3
  *
4
- * 定义 WebSocket 推送消息的类型、主题和数据结构,
5
- * 使用 JSON 序列化/反序列化(简化替代 Protobuf)。
4
+ * 仅保留 SubjectType 枚举,用于订阅/退订 API。
5
+ * JSON 消息类型定义和序列化函数已移除,改用 Protobuf 协议。
6
6
  */
7
- /** 推送消息类型 */
8
- export var MessageType;
9
- (function (MessageType) {
10
- // 连接相关
11
- MessageType["Connect"] = "connect";
12
- MessageType["Connected"] = "connected";
13
- MessageType["Disconnect"] = "disconnect";
14
- MessageType["Heartbeat"] = "heartbeat";
15
- MessageType["Kickout"] = "kickout";
16
- MessageType["Error"] = "error";
17
- // 订阅相关
18
- MessageType["Subscribe"] = "subscribe";
19
- MessageType["Unsubscribe"] = "unsubscribe";
20
- // 行情推送
21
- MessageType["Quote"] = "quote";
22
- MessageType["Tick"] = "tick";
23
- MessageType["Depth"] = "depth";
24
- MessageType["Option"] = "option";
25
- MessageType["Future"] = "future";
26
- MessageType["Kline"] = "kline";
27
- MessageType["StockTop"] = "stock_top";
28
- MessageType["OptionTop"] = "option_top";
29
- MessageType["FullTick"] = "full_tick";
30
- MessageType["QuoteBBO"] = "quote_bbo";
31
- // 账户推送
32
- MessageType["Asset"] = "asset";
33
- MessageType["Position"] = "position";
34
- MessageType["Order"] = "order";
35
- MessageType["Transaction"] = "transaction";
36
- })(MessageType || (MessageType = {}));
37
7
  /** 订阅主题类型 */
38
8
  export var SubjectType;
39
9
  (function (SubjectType) {
@@ -52,26 +22,3 @@ export var SubjectType;
52
22
  SubjectType["Order"] = "order";
53
23
  SubjectType["Transaction"] = "transaction";
54
24
  })(SubjectType || (SubjectType = {}));
55
- /**
56
- * 创建推送消息
57
- */
58
- export function createPushMessage(type, subject, data) {
59
- const msg = { type };
60
- if (subject)
61
- msg.subject = subject;
62
- if (data !== undefined)
63
- msg.data = data;
64
- return msg;
65
- }
66
- /**
67
- * 序列化推送消息为 JSON 字符串
68
- */
69
- export function serializeMessage(msg) {
70
- return JSON.stringify(msg);
71
- }
72
- /**
73
- * 反序列化 JSON 字符串为推送消息
74
- */
75
- export function deserializeMessage(data) {
76
- return JSON.parse(data);
77
- }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Varint32 帧编解码器
3
+ *
4
+ * 兼容 Netty 的 ProtobufVarint32FrameDecoder / ProtobufVarint32LengthFieldPrepender。
5
+ * 每个字节低 7 位存数据,最高位为延续标志(1=后续还有字节,0=最后一个字节),最大 5 字节。
6
+ */
7
+ /**
8
+ * 在 protobuf 字节前添加 varint32 长度前缀
9
+ *
10
+ * @param data - 待编码的 protobuf 二进制数据
11
+ * @returns varint32 长度前缀 + 原始数据
12
+ */
13
+ export function encodeVarint32(data) {
14
+ const length = data.length;
15
+ const header = encodeVarint32Length(length);
16
+ const result = new Uint8Array(header.length + data.length);
17
+ result.set(header, 0);
18
+ result.set(data, header.length);
19
+ return result;
20
+ }
21
+ /**
22
+ * 将一个非负整数编码为 varint32 字节序列
23
+ */
24
+ function encodeVarint32Length(value) {
25
+ const bytes = [];
26
+ while (value > 0x7f) {
27
+ bytes.push((value & 0x7f) | 0x80);
28
+ value >>>= 7;
29
+ }
30
+ bytes.push(value & 0x7f);
31
+ return new Uint8Array(bytes);
32
+ }
33
+ /**
34
+ * 从缓冲区解码一个 varint32 帧
35
+ *
36
+ * @param buffer - 包含 varint32 长度前缀 + protobuf 数据的缓冲区
37
+ * @returns 解码结果 `{ message, remaining }`,数据不足时返回 `null`
38
+ */
39
+ export function decodeVarint32(buffer) {
40
+ if (buffer.length === 0) {
41
+ return null;
42
+ }
43
+ // 读取 varint32 长度前缀
44
+ let value = 0;
45
+ let shift = 0;
46
+ let i = 0;
47
+ while (i < buffer.length) {
48
+ // varint32 最多 5 字节
49
+ if (i >= 5) {
50
+ throw new Error('varint32 overflow: more than 5 bytes');
51
+ }
52
+ const byte = buffer[i];
53
+ value |= (byte & 0x7f) << shift;
54
+ i++;
55
+ if ((byte & 0x80) === 0) {
56
+ // 最后一个字节,延续标志为 0
57
+ const messageLength = value >>> 0; // 确保无符号
58
+ const totalNeeded = i + messageLength;
59
+ if (buffer.length < totalNeeded) {
60
+ // 数据不足,等待更多数据
61
+ return null;
62
+ }
63
+ return {
64
+ message: buffer.slice(i, i + messageLength),
65
+ remaining: buffer.slice(i + messageLength),
66
+ };
67
+ }
68
+ shift += 7;
69
+ }
70
+ // 缓冲区中 varint 前缀不完整,等待更多数据
71
+ return null;
72
+ }
@@ -1,4 +1,4 @@
1
1
  /**
2
- * 行情模块导出
2
+ * Quote module exports
3
3
  */
4
- export { QuoteClient } from './quote-client';
4
+ export { QuoteClient, parseOptionIdentifier } from './quote-client';
@@ -1,106 +1,139 @@
1
1
  import { createApiRequest } from '../client/api-request';
2
+ import { unmarshalData } from '../client/api-response';
2
3
  /**
3
- * 行情查询客户端,封装所有行情相关 API。
4
+ * Parse an OCC-style option identifier like "AAPL 260619C00150000"
5
+ * into its component parts.
4
6
  */
7
+ export function parseOptionIdentifier(identifier) {
8
+ const trimmed = identifier.trim();
9
+ const spaceIdx = trimmed.indexOf(' ');
10
+ if (spaceIdx === -1) {
11
+ throw new Error(`invalid option identifier: ${identifier}`);
12
+ }
13
+ const symbol = trimmed.substring(0, spaceIdx);
14
+ const rest = trimmed.substring(spaceIdx + 1).trim();
15
+ if (rest.length < 15) {
16
+ throw new Error(`option code too short: ${rest}`);
17
+ }
18
+ const datePart = rest.substring(0, 6);
19
+ const rightChar = rest.substring(6, 7);
20
+ const strikePart = rest.substring(7);
21
+ const yy = parseInt(datePart.substring(0, 2), 10);
22
+ const mm = parseInt(datePart.substring(2, 4), 10);
23
+ const dd = parseInt(datePart.substring(4, 6), 10);
24
+ const expiryMs = Date.UTC(2000 + yy, mm - 1, dd);
25
+ const right = rightChar === 'C' ? 'CALL' : rightChar === 'P' ? 'PUT' : '';
26
+ if (!right)
27
+ throw new Error(`invalid right character: ${rightChar}`);
28
+ const strikeInt = parseInt(strikePart, 10);
29
+ if (Number.isNaN(strikeInt))
30
+ throw new Error(`invalid strike digits: ${strikePart}`);
31
+ const strike = strikeInt / 1000;
32
+ return { symbol, expiryMs, right, strike };
33
+ }
34
+ /** Market data client wrapping all quote-related APIs. */
5
35
  export class QuoteClient {
6
36
  constructor(httpClient) {
7
37
  this.httpClient = httpClient;
8
38
  }
39
+ async callInto(method, bizParams, version) {
40
+ const request = createApiRequest(method, bizParams, version);
41
+ const response = await this.httpClient.executeRequest(request);
42
+ return unmarshalData(response.data);
43
+ }
44
+ // === Basic market data ===
45
+ async getMarketState(market) {
46
+ return this.callInto('market_state', { market });
47
+ }
48
+ async getBrief(symbols) {
49
+ return this.callInto('quote_real_time', { symbols });
50
+ }
51
+ async getKline(symbol, period) {
52
+ return this.callInto('kline', { symbols: [symbol], period });
53
+ }
54
+ async getTimeline(symbols) {
55
+ return this.callInto('timeline', { symbols });
56
+ }
57
+ async getTradeTick(symbols) {
58
+ return this.callInto('trade_tick', { symbols });
59
+ }
60
+ /** Depth snapshot. market is required (US / HK supported). */
61
+ async getQuoteDepth(symbol, market) {
62
+ return this.callInto('quote_depth', { symbols: [symbol], market });
63
+ }
64
+ // === Options ===
65
+ async getOptionExpiration(symbol) {
66
+ return this.callInto('option_expiration', { symbols: [symbol] });
67
+ }
68
+ /** Option chain; `expiry` is "YYYY-MM-DD". */
69
+ async getOptionChain(symbol, expiry) {
70
+ const d = new Date(expiry + 'T00:00:00Z');
71
+ const expiryMs = d.getTime();
72
+ if (Number.isNaN(expiryMs)) {
73
+ throw new Error(`invalid expiry date, expected YYYY-MM-DD: ${expiry}`);
74
+ }
75
+ return this.callInto('option_chain', { option_basic: [{ symbol, expiry: expiryMs }] }, '3.0');
76
+ }
77
+ async getOptionBrief(identifiers) {
78
+ const optionBasic = identifiers.map((id) => {
79
+ const p = parseOptionIdentifier(id);
80
+ return { symbol: p.symbol, expiry: p.expiryMs, right: p.right, strike: p.strike };
81
+ });
82
+ return this.callInto('option_brief', { option_basic: optionBasic }, '2.0');
83
+ }
84
+ async getOptionKline(identifier, period) {
85
+ const p = parseOptionIdentifier(identifier);
86
+ return this.callInto('option_kline', {
87
+ option_query: [{ symbol: p.symbol, expiry: p.expiryMs, right: p.right, strike: p.strike, period }],
88
+ }, '2.0');
89
+ }
90
+ // === Futures ===
91
+ async getFutureExchange() {
92
+ return this.callInto('future_exchange', { secType: 'FUT' });
93
+ }
94
+ async getFutureContracts(exchange) {
95
+ return this.callInto('future_contract_by_exchange_code', { exchangeCode: exchange });
96
+ }
97
+ async getFutureRealTimeQuote(contractCodes) {
98
+ return this.callInto('future_real_time_quote', { contractCodes });
99
+ }
100
+ /** Futures K-line; use -1 for unbounded beginTime / endTime. */
101
+ async getFutureKline(req) {
102
+ const body = {
103
+ ...req,
104
+ beginTime: req.beginTime ?? -1,
105
+ endTime: req.endTime ?? -1,
106
+ };
107
+ return this.callInto('future_kline', body);
108
+ }
109
+ // === Fundamentals ===
110
+ async getFinancialDaily(req) {
111
+ return this.callInto('financial_daily', req);
112
+ }
113
+ async getFinancialReport(req) {
114
+ return this.callInto('financial_report', req);
115
+ }
9
116
  /**
10
- * 内部通用方法:构造请求、发送、返回 data 字段
117
+ * Corporate actions. Server returns {symbol: [...]}, this method flattens into a single list.
11
118
  */
12
- async execute(method, bizParams) {
13
- const request = createApiRequest(method, bizParams);
14
- const response = await this.httpClient.executeRequest(request);
15
- return response.data;
16
- }
17
- // === 基础行情方法 ===
18
- /** 获取市场状态 */
19
- async marketState(market) {
20
- return this.execute('market_state', { market });
21
- }
22
- /** 获取实时报价 */
23
- async quoteRealTime(symbols) {
24
- return this.execute('quote_real_time', { symbols });
25
- }
26
- /** 获取 K 线数据 */
27
- async kline(symbol, period) {
28
- return this.execute('kline', { symbols: [symbol], period });
29
- }
30
- /** 获取分时数据 */
31
- async timeline(symbols) {
32
- return this.execute('timeline', { symbols });
33
- }
34
- /** 获取逐笔成交数据 */
35
- async tradeTick(symbols) {
36
- return this.execute('trade_tick', { symbols });
37
- }
38
- /** 获取深度行情 */
39
- async quoteDepth(symbol) {
40
- return this.execute('quote_depth', { symbol });
41
- }
42
- // === 期权行情方法 ===
43
- /** 获取期权到期日 */
44
- async optionExpiration(symbol) {
45
- return this.execute('option_expiration', { symbols: [symbol] });
46
- }
47
- /** 获取期权链 */
48
- async optionChain(symbol, expiry) {
49
- return this.execute('option_chain', { symbol, expiry });
50
- }
51
- /** 获取期权报价 */
52
- async optionBrief(identifiers) {
53
- return this.execute('option_brief', { identifiers });
54
- }
55
- /** 获取期权 K 线 */
56
- async optionKline(identifier, period) {
57
- return this.execute('option_kline', { identifier, period });
58
- }
59
- // === 期货行情方法 ===
60
- /** 获取期货交易所列表 */
61
- async futureExchange() {
62
- return this.execute('future_exchange', { sec_type: 'FUT' });
63
- }
64
- /** 获取期货合约列表 */
65
- async futureContracts(exchange) {
66
- return this.execute('future_contracts', { exchange });
67
- }
68
- /** 获取期货实时报价 */
69
- async futureRealTimeQuote(symbols) {
70
- return this.execute('future_real_time_quote', { symbols });
71
- }
72
- /** 获取期货 K 线 */
73
- async futureKline(symbol, period) {
74
- return this.execute('future_kline', { symbol, period });
75
- }
76
- // === 基本面和资金流向方法 ===
77
- /** 获取财务日报 */
78
- async financialDaily(symbol) {
79
- return this.execute('financial_daily', { symbol });
80
- }
81
- /** 获取财务报告 */
82
- async financialReport(symbol) {
83
- return this.execute('financial_report', { symbol });
84
- }
85
- /** 获取公司行动 */
86
- async corporateAction(symbol) {
87
- return this.execute('corporate_action', { symbol });
88
- }
89
- /** 获取资金流向 */
90
- async capitalFlow(symbol) {
91
- return this.execute('capital_flow', { symbol });
92
- }
93
- /** 获取资金分布 */
94
- async capitalDistribution(symbol) {
95
- return this.execute('capital_distribution', { symbol });
96
- }
97
- // === 选股器和行情权限方法 ===
98
- /** 选股器 */
99
- async marketScanner(params) {
100
- return this.execute('market_scanner', params);
101
- }
102
- /** 获取行情权限 */
119
+ async getCorporateAction(req) {
120
+ const grouped = await this.callInto('corporate_action', req);
121
+ if (!grouped || typeof grouped !== 'object')
122
+ return [];
123
+ return Object.values(grouped).flat();
124
+ }
125
+ // === Capital flow ===
126
+ async getCapitalFlow(symbol, market, period) {
127
+ return this.callInto('capital_flow', { symbol, market, period });
128
+ }
129
+ async getCapitalDistribution(symbol, market) {
130
+ return this.callInto('capital_distribution', { symbol, market });
131
+ }
132
+ // === Scanner & permission ===
133
+ async marketScanner(req) {
134
+ return this.callInto('market_scanner', req);
135
+ }
103
136
  async grabQuotePermission() {
104
- return this.execute('grab_quote_permission');
137
+ return this.callInto('grab_quote_permission');
105
138
  }
106
139
  }
@@ -73,16 +73,16 @@ export function signWithRSA(privateKeyStr, content) {
73
73
  return sign.sign(key, 'base64');
74
74
  }
75
75
  /**
76
- * 使用 RSA 公钥验证 SHA1WithRSA 签名。
76
+ * Verify a SHA1WithRSA signature using an RSA public key.
77
77
  *
78
- * @param publicKey - 公钥对象
79
- * @param content - 原始内容
80
- * @param signature - Base64 编码的签名字符串
81
- * @returns 验签是否成功
78
+ * @param publicKeyBase64 - Base64-encoded public key (DER / PKCS#1 or SPKI)
79
+ * @param content - Original content that was signed
80
+ * @param signatureBase64 - Base64-encoded signature
81
+ * @returns Whether the signature is valid
82
82
  */
83
- export function verifyWithRSA(publicKey, content, signature) {
84
- const verify = createVerify('SHA1');
85
- verify.update(content);
86
- verify.end();
87
- return verify.verify(publicKey, signature, 'base64');
83
+ export function verifyWithRSA(publicKeyBase64, content, signatureBase64) {
84
+ const pem = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64}\n-----END PUBLIC KEY-----`;
85
+ const verifier = createVerify('SHA1');
86
+ verifier.update(content);
87
+ return verifier.verify(pem, signatureBase64, 'base64');
88
88
  }
@@ -1,95 +1,89 @@
1
1
  import { createApiRequest } from '../client/api-request';
2
- /**
3
- * 交易客户端,封装所有交易相关 API。
4
- */
2
+ import { unmarshalData } from '../client/api-response';
3
+ /** Trading client wrapping all trade-related APIs. */
5
4
  export class TradeClient {
6
5
  constructor(httpClient, account) {
7
6
  this.httpClient = httpClient;
8
7
  this.account = account;
9
8
  }
10
- /**
11
- * 内部通用方法:构造请求、发送、返回 data 字段
12
- */
13
- async execute(method, bizParams) {
9
+ async callInto(method, bizParams) {
14
10
  const request = createApiRequest(method, bizParams);
15
11
  const response = await this.httpClient.executeRequest(request);
16
- return response.data;
17
- }
18
- // === 合约查询方法 ===
19
- /** 查询单个合约 */
20
- async contract(symbol, secType) {
21
- return this.execute('contract', {
12
+ return unmarshalData(response.data);
13
+ }
14
+ /** Strip `{items: [...]}` envelope used by most trade read endpoints. */
15
+ async callIntoItems(method, bizParams) {
16
+ const wrap = await this.callInto(method, bizParams);
17
+ if (Array.isArray(wrap))
18
+ return wrap;
19
+ return wrap?.items ?? [];
20
+ }
21
+ // === Contracts ===
22
+ async getContract(symbol, secType) {
23
+ return this.callIntoItems('contract', {
22
24
  account: this.account, symbol, secType,
23
25
  });
24
26
  }
25
- /** 批量查询合约 */
26
- async contracts(symbols, secType) {
27
- return this.execute('contracts', {
27
+ async getContracts(symbols, secType) {
28
+ return this.callIntoItems('contracts', {
28
29
  account: this.account, symbols, secType,
29
30
  });
30
31
  }
31
- /** 查询衍生品合约 */
32
- async quoteContract(symbol, secType) {
33
- return this.execute('quote_contract', {
34
- account: this.account, symbol, secType,
32
+ /**
33
+ * Derivative contracts (OPT / WAR / IOPT only).
34
+ * `symbol` is the underlying (e.g. "AAPL"); `expiry` is "YYYYMMDD".
35
+ */
36
+ async getQuoteContract(symbol, secType, expiry) {
37
+ return this.callIntoItems('quote_contract', {
38
+ account: this.account, symbols: [symbol], secType, expiry,
35
39
  });
36
40
  }
37
- // === 订单操作方法 ===
38
- /** 下单 */
41
+ // === Order operations ===
39
42
  async placeOrder(order) {
40
- const params = { ...order, account: this.account };
41
- return this.execute('place_order', params);
43
+ return this.callInto('place_order', { ...order, account: this.account });
42
44
  }
43
- /** 预览订单 */
44
45
  async previewOrder(order) {
45
- const params = { ...order, account: this.account };
46
- return this.execute('preview_order', params);
46
+ return this.callInto('preview_order', { ...order, account: this.account });
47
47
  }
48
- /** 修改订单 */
49
48
  async modifyOrder(id, order) {
50
- const params = { ...order, account: this.account, id };
51
- return this.execute('modify_order', params);
49
+ return this.callInto('modify_order', { ...order, account: this.account, id });
52
50
  }
53
- /** 取消订单 */
54
51
  async cancelOrder(id) {
55
- return this.execute('cancel_order', {
56
- account: this.account, id,
57
- });
52
+ return this.callInto('cancel_order', { account: this.account, id });
58
53
  }
59
- // === 订单查询方法 ===
60
- /** 查询全部订单 */
61
- async orders() {
62
- return this.execute('orders', { account: this.account });
54
+ // === Order queries ===
55
+ async getOrders() {
56
+ return this.callIntoItems('orders', { account: this.account });
63
57
  }
64
- /** 查询待成交订单 */
65
- async activeOrders() {
66
- return this.execute('active_orders', { account: this.account });
58
+ async getActiveOrders() {
59
+ return this.callIntoItems('active_orders', { account: this.account });
67
60
  }
68
- /** 查询已撤销订单 */
69
- async inactiveOrders() {
70
- return this.execute('inactive_orders', { account: this.account });
61
+ async getInactiveOrders() {
62
+ return this.callIntoItems('inactive_orders', { account: this.account });
71
63
  }
72
- /** 查询已成交订单 */
73
- async filledOrders() {
74
- return this.execute('filled_orders', { account: this.account });
64
+ /**
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".
67
+ */
68
+ async getFilledOrders(startDateMs, endDateMs) {
69
+ return this.callIntoItems('filled_orders', {
70
+ account: this.account, startDate: startDateMs, endDate: endDateMs,
71
+ });
75
72
  }
76
- // === 持仓和资产查询方法 ===
77
- /** 查询持仓 */
78
- async positions() {
79
- return this.execute('positions', { account: this.account });
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
+ });
80
78
  }
81
- /** 查询资产 */
82
- async assets() {
83
- return this.execute('assets', { account: this.account });
79
+ // === Positions & assets ===
80
+ async getPositions() {
81
+ return this.callIntoItems('positions', { account: this.account });
84
82
  }
85
- /** 查询综合账户资产 */
86
- async primeAssets() {
87
- return this.execute('prime_assets', { account: this.account });
83
+ async getAssets() {
84
+ return this.callIntoItems('assets', { account: this.account });
88
85
  }
89
- /** 查询订单成交明细 */
90
- async orderTransactions(id) {
91
- return this.execute('order_transactions', {
92
- account: this.account, id,
93
- });
86
+ async getPrimeAssets() {
87
+ return this.callInto('prime_assets', { account: this.account });
94
88
  }
95
89
  }
@@ -1,18 +1,19 @@
1
- /**
2
- * API 请求构造模块
3
- */
4
- /** API 请求接口 */
1
+ /** API request interface */
5
2
  export interface ApiRequest {
6
- /** API 方法名(如 "market_state"、"place_order") */
3
+ /** API method name (e.g. "market_state", "place_order") */
7
4
  method: string;
8
- /** 业务参数 JSON 字符串 */
5
+ /** Business parameters as JSON string (already snake_case) */
9
6
  bizContent: string;
7
+ /** Optional API version override (default: "2.0") */
8
+ version?: string;
10
9
  }
11
10
  /**
12
- * 创建 API 请求,将业务参数序列化为 JSON 字符串作为 bizContent。
11
+ * Create an API request, serializing business parameters to JSON as bizContent.
12
+ * camelCase keys are automatically converted to snake_case to match the server.
13
13
  *
14
- * @param method - API 方法名
15
- * @param bizParams - 业务参数(对象、字符串或 null)
16
- * @returns ApiRequest 对象
14
+ * @param method - API method name
15
+ * @param bizParams - Business parameters (object, string, or null); objects are converted recursively
16
+ * @param version - Optional API version override
17
+ * @returns ApiRequest object
17
18
  */
18
- export declare function createApiRequest(method: string, bizParams: unknown): ApiRequest;
19
+ export declare function createApiRequest(method: string, bizParams: unknown, version?: string): ApiRequest;
@@ -1,16 +1,24 @@
1
- /** API 响应接口 */
1
+ /** API response envelope */
2
2
  export interface ApiResponse {
3
- /** 状态码(0=成功) */
3
+ /** Result code (0 = success) */
4
4
  code: number;
5
- /** 状态描述 */
5
+ /** Human-readable message */
6
6
  message: string;
7
- /** 业务数据 */
7
+ /** Business payload */
8
8
  data: unknown;
9
- /** 服务器时间戳 */
9
+ /** Server timestamp */
10
10
  timestamp: number;
11
+ /** Response signature for verification */
12
+ sign?: string;
11
13
  }
12
14
  /**
13
- * 解析 API 响应 JSON 字符串。
14
- * code 为 0 时返回 ApiResponse;code 不为 0 时抛出 TigerError。
15
+ * Parse the raw HTTP response body.
16
+ * Throws TigerError when code != 0.
15
17
  */
16
18
  export declare function parseApiResponse(body: string): ApiResponse;
19
+ /**
20
+ * Decode an ApiResponse.data payload into a typed value.
21
+ * Handles the server's occasional double-encoded JSON (where `data` is a
22
+ * JSON string that itself wraps JSON), seen on some trade endpoints.
23
+ */
24
+ export declare function unmarshalData<T>(data: unknown): T | undefined;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Case conversion utilities.
3
+ *
4
+ * TypeScript SDK uses camelCase idiomatically. The server expects
5
+ * snake_case for request field names and returns camelCase for responses.
6
+ * These helpers convert camelCase objects to snake_case before
7
+ * serialization; response side needs no conversion.
8
+ */
9
+ /** Convert a single camelCase key to snake_case. */
10
+ export declare function camelToSnake(key: string): string;
11
+ /**
12
+ * Recursively convert all object keys from camelCase to snake_case.
13
+ * Preserves arrays, primitives, and Date/null/undefined.
14
+ * Keys already containing an underscore are kept as-is (already snake_case).
15
+ */
16
+ export declare function keysToSnakeCase(value: unknown): unknown;