@tigeropenapi/tigeropen 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/cjs/client/api-request.js +26 -0
  4. package/dist/cjs/client/api-response.js +18 -0
  5. package/dist/cjs/client/errors.js +51 -0
  6. package/dist/cjs/client/http-client.js +149 -0
  7. package/dist/cjs/client/index.js +19 -0
  8. package/dist/cjs/client/retry.js +54 -0
  9. package/dist/cjs/config/client-config.js +114 -0
  10. package/dist/cjs/config/config-parser.js +142 -0
  11. package/dist/cjs/config/domain.js +97 -0
  12. package/dist/cjs/config/index.js +14 -0
  13. package/dist/cjs/config/token-manager.js +116 -0
  14. package/dist/cjs/index.js +21 -0
  15. package/dist/cjs/logger/index.js +20 -0
  16. package/dist/cjs/logger/logger.js +68 -0
  17. package/dist/cjs/model/contract-helpers.js +38 -0
  18. package/dist/cjs/model/contract.js +6 -0
  19. package/dist/cjs/model/enums.js +110 -0
  20. package/dist/cjs/model/order-helpers.js +104 -0
  21. package/dist/cjs/model/order.js +6 -0
  22. package/dist/cjs/model/position.js +6 -0
  23. package/dist/cjs/push/callbacks.js +2 -0
  24. package/dist/cjs/push/index.js +25 -0
  25. package/dist/cjs/push/push-client.js +423 -0
  26. package/dist/cjs/push/push-message.js +83 -0
  27. package/dist/cjs/quote/index.js +8 -0
  28. package/dist/cjs/quote/quote-client.js +110 -0
  29. package/dist/cjs/signer/index.js +12 -0
  30. package/dist/cjs/signer/sign-content.js +19 -0
  31. package/dist/cjs/signer/signer.js +93 -0
  32. package/dist/cjs/trade/index.js +8 -0
  33. package/dist/cjs/trade/trade-client.js +99 -0
  34. package/dist/esm/client/api-request.js +23 -0
  35. package/dist/esm/client/api-response.js +15 -0
  36. package/dist/esm/client/errors.js +46 -0
  37. package/dist/esm/client/http-client.js +145 -0
  38. package/dist/esm/client/index.js +8 -0
  39. package/dist/esm/client/retry.js +48 -0
  40. package/dist/esm/config/client-config.js +111 -0
  41. package/dist/esm/config/config-parser.js +105 -0
  42. package/dist/esm/config/domain.js +93 -0
  43. package/dist/esm/config/index.js +6 -0
  44. package/dist/esm/config/token-manager.js +112 -0
  45. package/dist/esm/index.js +18 -0
  46. package/dist/esm/logger/index.js +4 -0
  47. package/dist/esm/logger/logger.js +61 -0
  48. package/dist/esm/model/contract-helpers.js +29 -0
  49. package/dist/esm/model/contract.js +5 -0
  50. package/dist/esm/model/enums.js +107 -0
  51. package/dist/esm/model/order-helpers.js +93 -0
  52. package/dist/esm/model/order.js +5 -0
  53. package/dist/esm/model/position.js +5 -0
  54. package/dist/esm/push/callbacks.js +1 -0
  55. package/dist/esm/push/index.js +6 -0
  56. package/dist/esm/push/push-client.js +419 -0
  57. package/dist/esm/push/push-message.js +77 -0
  58. package/dist/esm/quote/index.js +4 -0
  59. package/dist/esm/quote/quote-client.js +106 -0
  60. package/dist/esm/signer/index.js +5 -0
  61. package/dist/esm/signer/sign-content.js +16 -0
  62. package/dist/esm/signer/signer.js +88 -0
  63. package/dist/esm/trade/index.js +4 -0
  64. package/dist/esm/trade/trade-client.js +95 -0
  65. package/dist/types/client/api-request.d.ts +18 -0
  66. package/dist/types/client/api-response.d.ts +16 -0
  67. package/dist/types/client/errors.d.ts +19 -0
  68. package/dist/types/client/http-client.d.ts +45 -0
  69. package/dist/types/client/index.d.ts +8 -0
  70. package/dist/types/client/retry.d.ts +37 -0
  71. package/dist/types/config/client-config.d.ts +43 -0
  72. package/dist/types/config/config-parser.d.ts +16 -0
  73. package/dist/types/config/domain.d.ts +18 -0
  74. package/dist/types/config/index.d.ts +7 -0
  75. package/dist/types/config/token-manager.d.ts +38 -0
  76. package/dist/types/index.d.ts +18 -0
  77. package/dist/types/logger/index.d.ts +4 -0
  78. package/dist/types/logger/logger.d.ts +42 -0
  79. package/dist/types/model/contract-helpers.d.ts +18 -0
  80. package/dist/types/model/contract.d.ts +60 -0
  81. package/dist/types/model/enums.d.ts +97 -0
  82. package/dist/types/model/order-helpers.d.ts +22 -0
  83. package/dist/types/model/order.d.ts +95 -0
  84. package/dist/types/model/position.d.ts +39 -0
  85. package/dist/types/push/callbacks.d.ts +57 -0
  86. package/dist/types/push/index.d.ts +7 -0
  87. package/dist/types/push/push-client.d.ts +139 -0
  88. package/dist/types/push/push-message.d.ts +167 -0
  89. package/dist/types/quote/index.d.ts +4 -0
  90. package/dist/types/quote/quote-client.d.ts +58 -0
  91. package/dist/types/signer/index.d.ts +5 -0
  92. package/dist/types/signer/sign-content.d.ts +13 -0
  93. package/dist/types/signer/signer.d.ts +36 -0
  94. package/dist/types/trade/index.d.ts +4 -0
  95. package/dist/types/trade/trade-client.d.ts +48 -0
  96. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Tiger Fintech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # Tiger OpenAPI TypeScript SDK
2
+
3
+ 老虎证券 OpenAPI 的 TypeScript SDK,提供行情查询、交易下单、账户管理和实时推送等功能。
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@tigeropenapi/tigeropen.svg)](https://www.npmjs.com/package/@tigeropenapi/tigeropen)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## 安装
9
+
10
+ ```bash
11
+ npm install @tigeropenapi/tigeropen
12
+ # 或
13
+ yarn add @tigeropenapi/tigeropen
14
+ # 或
15
+ pnpm add @tigeropenapi/tigeropen
16
+ ```
17
+
18
+ 要求 Node.js >= 16.0.0。
19
+
20
+ ## Quick Start
21
+
22
+ 以下是一个完整的示例,从配置到查询行情:
23
+
24
+ ```typescript
25
+ import { createClientConfig } from '@tigeropenapi/tigeropen';
26
+ import { HttpClient } from '@tigeropenapi/tigeropen/client/http-client';
27
+ import { QuoteClient } from '@tigeropenapi/tigeropen/quote/quote-client';
28
+
29
+ // 1. 创建配置(从 properties 文件加载)
30
+ const config = createClientConfig({
31
+ propertiesFilePath: 'tiger_openapi_config.properties',
32
+ });
33
+
34
+ // 2. 创建 HTTP 客户端
35
+ const httpClient = new HttpClient(config);
36
+
37
+ // 3. 创建行情客户端并查询
38
+ const qc = new QuoteClient(httpClient);
39
+ const states = await qc.getMarketState('US');
40
+ console.log('美股市场状态:', states);
41
+ ```
42
+
43
+ ## 配置
44
+
45
+ SDK 支持三种配置方式,优先级:**环境变量 > 代码设置(含配置文件) > 默认值**。
46
+
47
+ ### 方式一:代码直接设置
48
+
49
+ ```typescript
50
+ import { createClientConfig } from '@tigeropenapi/tigeropen';
51
+
52
+ const config = createClientConfig({
53
+ tigerId: '你的 tiger_id',
54
+ privateKey: '你的 RSA 私钥',
55
+ account: '你的交易账户',
56
+ });
57
+ ```
58
+
59
+ ### 方式二:从 properties 配置文件加载
60
+
61
+ ```typescript
62
+ const config = createClientConfig({
63
+ propertiesFilePath: 'tiger_openapi_config.properties',
64
+ });
65
+ ```
66
+
67
+ 配置文件格式:
68
+
69
+ ```properties
70
+ tiger_id=你的开发者ID
71
+ private_key=你的RSA私钥
72
+ account=你的交易账户
73
+ ```
74
+
75
+ ### 方式三:环境变量
76
+
77
+ ```bash
78
+ export TIGEROPEN_TIGER_ID=你的开发者ID
79
+ export TIGEROPEN_PRIVATE_KEY=你的RSA私钥
80
+ export TIGEROPEN_ACCOUNT=你的交易账户
81
+ ```
82
+
83
+ ### 配置项说明
84
+
85
+ | 配置项 | 说明 | 必填 | 默认值 |
86
+ |--------|------|------|--------|
87
+ | tigerId | 开发者 ID | 是 | - |
88
+ | privateKey | RSA 私钥 | 是 | - |
89
+ | account | 交易账户 | 否 | - |
90
+ | language | 语言(zh_CN/en_US) | 否 | zh_CN |
91
+ | timeout | 请求超时(秒) | 否 | 15 |
92
+ | sandboxDebug | 是否使用沙箱环境 | 否 | false |
93
+
94
+ ## 行情查询
95
+
96
+ ```typescript
97
+ import { HttpClient } from '@tigeropenapi/tigeropen/client/http-client';
98
+ import { QuoteClient } from '@tigeropenapi/tigeropen/quote/quote-client';
99
+
100
+ const httpClient = new HttpClient(config);
101
+ const qc = new QuoteClient(httpClient);
102
+
103
+ // 获取市场状态
104
+ const states = await qc.getMarketState('US');
105
+
106
+ // 获取实时报价
107
+ const briefs = await qc.getBrief(['AAPL', 'TSLA']);
108
+
109
+ // 获取 K 线数据
110
+ const klines = await qc.getKline('AAPL', 'day');
111
+
112
+ // 获取分时数据
113
+ const timeline = await qc.getTimeline(['AAPL']);
114
+
115
+ // 获取深度行情
116
+ const depth = await qc.getQuoteDepth('AAPL');
117
+
118
+ // 获取期权到期日
119
+ const expiry = await qc.getOptionExpiration('AAPL');
120
+
121
+ // 获取期权链
122
+ const chain = await qc.getOptionChain('AAPL', '2024-01-19');
123
+
124
+ // 获取期货交易所列表
125
+ const exchanges = await qc.getFutureExchange();
126
+ ```
127
+
128
+ ## 交易操作
129
+
130
+ ```typescript
131
+ import { HttpClient } from '@tigeropenapi/tigeropen/client/http-client';
132
+ import { TradeClient } from '@tigeropenapi/tigeropen/trade/trade-client';
133
+
134
+ const httpClient = new HttpClient(config);
135
+ const tc = new TradeClient(httpClient, config.account);
136
+
137
+ // 构造限价单
138
+ const order = {
139
+ symbol: 'AAPL',
140
+ secType: 'STK',
141
+ action: 'BUY',
142
+ orderType: 'LMT',
143
+ totalQuantity: 100,
144
+ limitPrice: 150.0,
145
+ timeInForce: 'DAY',
146
+ };
147
+
148
+ // 下单
149
+ const result = await tc.placeOrder(order);
150
+
151
+ // 预览订单(不实际下单)
152
+ const preview = await tc.previewOrder(order);
153
+
154
+ // 修改订单
155
+ const modifiedOrder = { ...order, limitPrice: 155.0 };
156
+ await tc.modifyOrder(orderId, modifiedOrder);
157
+
158
+ // 取消订单
159
+ await tc.cancelOrder(orderId);
160
+
161
+ // 查询全部订单
162
+ const orders = await tc.getOrders();
163
+
164
+ // 查询持仓
165
+ const positions = await tc.getPositions();
166
+
167
+ // 查询资产
168
+ const assets = await tc.getAssets();
169
+ ```
170
+
171
+ ## 通用方法(execute)
172
+
173
+ 当 SDK 尚未封装某个 API 时,可以使用 `HttpClient.execute` 直接调用:
174
+
175
+ ```typescript
176
+ const httpClient = new HttpClient(config);
177
+
178
+ // 直接传入 API 方法名和 JSON 参数
179
+ const resp = await httpClient.execute('market_state', JSON.stringify({ market: 'US' }));
180
+ console.log('原始响应:', resp);
181
+ ```
182
+
183
+ ## 实时推送
184
+
185
+ 通过 WebSocket 长连接接收实时行情和账户推送,支持自动重连和心跳保活:
186
+
187
+ ```typescript
188
+ import { PushClient } from '@tigeropenapi/tigeropen/push/push-client';
189
+
190
+ const pc = new PushClient(config);
191
+
192
+ // 设置回调
193
+ pc.setCallbacks({
194
+ onQuote: (data) => {
195
+ console.log(`行情推送: ${data.symbol} 最新价: ${data.latestPrice}`);
196
+ },
197
+ onOrder: (data) => {
198
+ console.log(`订单推送: ${data.symbol} 状态: ${data.status}`);
199
+ },
200
+ onAsset: (data) => {
201
+ console.log('资产变动推送');
202
+ },
203
+ onPosition: (data) => {
204
+ console.log('持仓变动推送');
205
+ },
206
+ onConnect: () => {
207
+ console.log('推送连接成功');
208
+ },
209
+ onDisconnect: () => {
210
+ console.log('推送连接断开');
211
+ },
212
+ onError: (err) => {
213
+ console.error('推送错误:', err);
214
+ },
215
+ });
216
+
217
+ // 连接
218
+ await pc.connect();
219
+
220
+ // 订阅行情
221
+ pc.subscribeQuote(['AAPL', 'TSLA']);
222
+
223
+ // 订阅账户推送
224
+ pc.subscribeAsset();
225
+ pc.subscribeOrder();
226
+ pc.subscribePosition();
227
+
228
+ // 退订
229
+ pc.unsubscribeQuote(['TSLA']);
230
+
231
+ // 断开连接
232
+ pc.disconnect();
233
+ ```
234
+
235
+ ## 项目结构
236
+
237
+ ```
238
+ openapi-typescript-sdk/
239
+ ├── src/
240
+ │ ├── config/ # 配置管理(ClientConfig、ConfigParser、动态域名)
241
+ │ ├── signer/ # RSA 签名
242
+ │ ├── client/ # HTTP 客户端(请求/响应、重试策略、execute)
243
+ │ ├── model/ # 数据模型(Order、Contract、Position、枚举)
244
+ │ ├── quote/ # 行情查询客户端
245
+ │ ├── trade/ # 交易客户端
246
+ │ ├── push/ # WebSocket 实时推送客户端
247
+ │ ├── logger/ # 日志模块
248
+ │ └── index.ts # 统一导出
249
+ ├── examples/ # 示例代码
250
+ └── tests/ # 测试
251
+ ```
252
+
253
+ ## ESM 和 CommonJS
254
+
255
+ 本 SDK 同时支持 ESM 和 CommonJS:
256
+
257
+ ```typescript
258
+ // ESM
259
+ import { createClientConfig } from '@tigeropenapi/tigeropen';
260
+
261
+ // CommonJS
262
+ const { createClientConfig } = require('@tigeropenapi/tigeropen');
263
+ ```
264
+
265
+ ## API 参考
266
+
267
+ - [老虎证券 OpenAPI 文档](https://quant.itigerup.com/openapi/zh/python/overview/introduction.html)
268
+ - [npm 包主页](https://www.npmjs.com/package/@tigeropenapi/tigeropen)
269
+
270
+ ## 许可证
271
+
272
+ [MIT License](LICENSE)
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /**
3
+ * API 请求构造模块
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createApiRequest = createApiRequest;
7
+ /**
8
+ * 创建 API 请求,将业务参数序列化为 JSON 字符串作为 bizContent。
9
+ *
10
+ * @param method - API 方法名
11
+ * @param bizParams - 业务参数(对象、字符串或 null)
12
+ * @returns ApiRequest 对象
13
+ */
14
+ function createApiRequest(method, bizParams) {
15
+ let bizContent;
16
+ if (typeof bizParams === 'string') {
17
+ bizContent = bizParams;
18
+ }
19
+ else if (bizParams == null) {
20
+ bizContent = '{}';
21
+ }
22
+ else {
23
+ bizContent = JSON.stringify(bizParams);
24
+ }
25
+ return { method, bizContent };
26
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseApiResponse = parseApiResponse;
4
+ /**
5
+ * API 响应解析模块
6
+ */
7
+ const errors_1 = require("./errors");
8
+ /**
9
+ * 解析 API 响应 JSON 字符串。
10
+ * code 为 0 时返回 ApiResponse;code 不为 0 时抛出 TigerError。
11
+ */
12
+ function parseApiResponse(body) {
13
+ const resp = JSON.parse(body);
14
+ if (resp.code !== 0) {
15
+ throw new errors_1.TigerError(resp.code, resp.message);
16
+ }
17
+ return resp;
18
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * 错误类型定义模块
4
+ *
5
+ * 定义 TigerError 及错误码分类逻辑。
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.TigerError = void 0;
9
+ exports.classifyErrorCode = classifyErrorCode;
10
+ /**
11
+ * 根据错误码返回对应的错误分类
12
+ */
13
+ function classifyErrorCode(code) {
14
+ if (code === 0)
15
+ return 'success';
16
+ if (code === 5)
17
+ return 'rate_limit';
18
+ if (code >= 1000 && code < 1010)
19
+ return 'common_param_error';
20
+ if (code >= 1010 && code < 1100)
21
+ return 'biz_param_error';
22
+ if (code >= 1100 && code < 1200)
23
+ return 'trade_global_error';
24
+ if (code >= 1200 && code < 1300)
25
+ return 'trade_prime_error';
26
+ if (code >= 1300 && code < 2100)
27
+ return 'trade_simulation_error';
28
+ if (code >= 2100 && code < 2200)
29
+ return 'quote_stock_error';
30
+ if (code >= 2200 && code < 2300)
31
+ return 'quote_option_error';
32
+ if (code >= 2300 && code < 2400)
33
+ return 'quote_future_error';
34
+ if (code >= 2400 && code < 4000)
35
+ return 'token_error';
36
+ if (code >= 4000 && code < 5000)
37
+ return 'permission_error';
38
+ return 'unknown_error';
39
+ }
40
+ /**
41
+ * TigerError - 统一错误类型
42
+ */
43
+ class TigerError extends Error {
44
+ constructor(code, message) {
45
+ super(message);
46
+ this.name = 'TigerError';
47
+ this.code = code;
48
+ this.category = classifyErrorCode(code);
49
+ }
50
+ }
51
+ exports.TigerError = TigerError;
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpClient = void 0;
4
+ const sign_content_1 = require("../signer/sign-content");
5
+ const signer_1 = require("../signer/signer");
6
+ const errors_1 = require("./errors");
7
+ const retry_1 = require("./retry");
8
+ const api_response_1 = require("./api-response");
9
+ /** SDK 版本号 */
10
+ const SDK_VERSION = '0.1.0';
11
+ /** User-Agent 字符串 */
12
+ const USER_AGENT = `openapi-typescript-sdk-${SDK_VERSION}`;
13
+ /** 默认字符集 */
14
+ const DEFAULT_CHARSET = 'UTF-8';
15
+ /** 默认签名类型 */
16
+ const DEFAULT_SIGN_TYPE = 'RSA';
17
+ /** 默认 API 版本 */
18
+ const DEFAULT_VERSION = '2.0';
19
+ /**
20
+ * HttpClient 封装 HTTP 请求、签名、重试、超时
21
+ */
22
+ class HttpClient {
23
+ constructor(config, retryPolicy) {
24
+ this.config = config;
25
+ this.retryPolicy = retryPolicy ?? (0, retry_1.defaultRetryPolicy)();
26
+ }
27
+ /**
28
+ * 构造公共请求参数
29
+ */
30
+ buildCommonParams(apiMethod, bizContent) {
31
+ const params = {
32
+ tiger_id: this.config.tigerId,
33
+ method: apiMethod,
34
+ charset: DEFAULT_CHARSET,
35
+ sign_type: DEFAULT_SIGN_TYPE,
36
+ timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),
37
+ version: DEFAULT_VERSION,
38
+ biz_content: bizContent,
39
+ };
40
+ if (this.config.language) {
41
+ params['language'] = this.config.language;
42
+ }
43
+ return params;
44
+ }
45
+ /**
46
+ * 对参数进行签名
47
+ */
48
+ signParams(params) {
49
+ const content = (0, sign_content_1.getSignContent)(params);
50
+ return (0, signer_1.signWithRSA)(this.config.privateKey, content);
51
+ }
52
+ /**
53
+ * 发送 HTTP POST 请求
54
+ */
55
+ async doHttpPost(params) {
56
+ const body = JSON.stringify(params);
57
+ const headers = {
58
+ 'Content-Type': 'application/json;charset=UTF-8',
59
+ 'User-Agent': USER_AGENT,
60
+ };
61
+ if (this.config.token) {
62
+ headers['Authorization'] = this.config.token;
63
+ }
64
+ const response = await fetch(this.config.serverUrl, {
65
+ method: 'POST',
66
+ headers,
67
+ body,
68
+ signal: AbortSignal.timeout(this.config.timeout * 1000),
69
+ });
70
+ return response.text();
71
+ }
72
+ /**
73
+ * 执行结构化 API 请求,返回解析后的 ApiResponse。
74
+ * 供 QuoteClient/TradeClient 内部使用。
75
+ */
76
+ async executeRequest(request) {
77
+ const params = this.buildCommonParams(request.method, request.bizContent);
78
+ const sign = this.signParams(params);
79
+ params['sign'] = sign;
80
+ let lastErr;
81
+ const maxAttempts = this.retryPolicy.shouldRetry(request.method)
82
+ ? this.retryPolicy.maxRetries + 1
83
+ : 1;
84
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
85
+ if (attempt > 0) {
86
+ const backoff = this.retryPolicy.calculateBackoff(attempt - 1);
87
+ await this.sleep(backoff);
88
+ }
89
+ try {
90
+ const body = await this.doHttpPost(params);
91
+ return (0, api_response_1.parseApiResponse)(body);
92
+ }
93
+ catch (err) {
94
+ lastErr = err;
95
+ if (!this.retryPolicy.shouldRetry(request.method)) {
96
+ throw err;
97
+ }
98
+ }
99
+ }
100
+ throw lastErr;
101
+ }
102
+ /**
103
+ * 通用 API 调用方法。
104
+ *
105
+ * @param apiMethod - API 方法名(如 "market_state"、"place_order")
106
+ * @param requestJson - 原始 biz_content JSON 字符串
107
+ * @returns 原始 response JSON 字符串,不做任何解析
108
+ */
109
+ async execute(apiMethod, requestJson) {
110
+ // 参数校验
111
+ if (!apiMethod) {
112
+ throw new errors_1.TigerError(-1, 'api_method 不能为空');
113
+ }
114
+ try {
115
+ JSON.parse(requestJson);
116
+ }
117
+ catch {
118
+ throw new errors_1.TigerError(-1, 'request_json 不是有效的 JSON');
119
+ }
120
+ const params = this.buildCommonParams(apiMethod, requestJson);
121
+ const sign = this.signParams(params);
122
+ params['sign'] = sign;
123
+ let lastErr;
124
+ const maxAttempts = this.retryPolicy.shouldRetry(apiMethod)
125
+ ? this.retryPolicy.maxRetries + 1
126
+ : 1;
127
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
128
+ if (attempt > 0) {
129
+ const backoff = this.retryPolicy.calculateBackoff(attempt - 1);
130
+ await this.sleep(backoff);
131
+ }
132
+ try {
133
+ return await this.doHttpPost(params);
134
+ }
135
+ catch (err) {
136
+ lastErr = err;
137
+ if (!this.retryPolicy.shouldRetry(apiMethod)) {
138
+ throw err;
139
+ }
140
+ }
141
+ }
142
+ throw lastErr;
143
+ }
144
+ /** 延迟指定毫秒 */
145
+ sleep(ms) {
146
+ return new Promise((resolve) => setTimeout(resolve, ms));
147
+ }
148
+ }
149
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseApiResponse = exports.createApiRequest = exports.isTradeOperation = exports.defaultRetryPolicy = exports.RetryPolicy = exports.classifyErrorCode = exports.TigerError = exports.HttpClient = void 0;
4
+ /**
5
+ * 传输层模块导出
6
+ */
7
+ var http_client_1 = require("./http-client");
8
+ Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return http_client_1.HttpClient; } });
9
+ var errors_1 = require("./errors");
10
+ Object.defineProperty(exports, "TigerError", { enumerable: true, get: function () { return errors_1.TigerError; } });
11
+ Object.defineProperty(exports, "classifyErrorCode", { enumerable: true, get: function () { return errors_1.classifyErrorCode; } });
12
+ var retry_1 = require("./retry");
13
+ Object.defineProperty(exports, "RetryPolicy", { enumerable: true, get: function () { return retry_1.RetryPolicy; } });
14
+ Object.defineProperty(exports, "defaultRetryPolicy", { enumerable: true, get: function () { return retry_1.defaultRetryPolicy; } });
15
+ Object.defineProperty(exports, "isTradeOperation", { enumerable: true, get: function () { return retry_1.isTradeOperation; } });
16
+ var api_request_1 = require("./api-request");
17
+ Object.defineProperty(exports, "createApiRequest", { enumerable: true, get: function () { return api_request_1.createApiRequest; } });
18
+ var api_response_1 = require("./api-response");
19
+ Object.defineProperty(exports, "parseApiResponse", { enumerable: true, get: function () { return api_response_1.parseApiResponse; } });
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * 重试策略模块
4
+ *
5
+ * 提供指数退避重试策略,交易操作(place_order/modify_order/cancel_order)跳过重试。
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.RetryPolicy = void 0;
9
+ exports.isTradeOperation = isTradeOperation;
10
+ exports.defaultRetryPolicy = defaultRetryPolicy;
11
+ /** 交易操作方法名集合 */
12
+ const TRADE_OPERATIONS = new Set(['place_order', 'modify_order', 'cancel_order']);
13
+ /**
14
+ * 判断是否为交易操作
15
+ */
16
+ function isTradeOperation(apiMethod) {
17
+ return TRADE_OPERATIONS.has(apiMethod);
18
+ }
19
+ /**
20
+ * 重试策略
21
+ */
22
+ class RetryPolicy {
23
+ constructor(options) {
24
+ this.maxRetries = options?.maxRetries ?? 5;
25
+ this.maxRetryTime = options?.maxRetryTime ?? 60000;
26
+ this.baseDelay = options?.baseDelay ?? 1000;
27
+ this.maxDelay = options?.maxDelay ?? 16000;
28
+ }
29
+ /**
30
+ * 判断指定的 API 方法是否应该重试。
31
+ * 交易操作跳过重试。
32
+ */
33
+ shouldRetry(apiMethod) {
34
+ return !isTradeOperation(apiMethod);
35
+ }
36
+ /**
37
+ * 计算第 n 次重试的退避等待时间(毫秒,从 0 开始计数)。
38
+ * 退避公式:min(2^n * baseDelay, maxDelay)
39
+ */
40
+ calculateBackoff(retryCount) {
41
+ if (retryCount < 0) {
42
+ return this.baseDelay;
43
+ }
44
+ const delay = Math.pow(2, retryCount) * this.baseDelay;
45
+ return Math.min(delay, this.maxDelay);
46
+ }
47
+ }
48
+ exports.RetryPolicy = RetryPolicy;
49
+ /**
50
+ * 返回默认重试策略
51
+ */
52
+ function defaultRetryPolicy() {
53
+ return new RetryPolicy();
54
+ }