@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
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * 推送消息类型定义和数据结构
4
+ *
5
+ * 定义 WebSocket 推送消息的类型、主题和数据结构,
6
+ * 使用 JSON 序列化/反序列化(简化替代 Protobuf)。
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SubjectType = exports.MessageType = void 0;
10
+ exports.createPushMessage = createPushMessage;
11
+ exports.serializeMessage = serializeMessage;
12
+ exports.deserializeMessage = deserializeMessage;
13
+ /** 推送消息类型 */
14
+ var MessageType;
15
+ (function (MessageType) {
16
+ // 连接相关
17
+ MessageType["Connect"] = "connect";
18
+ MessageType["Connected"] = "connected";
19
+ MessageType["Disconnect"] = "disconnect";
20
+ MessageType["Heartbeat"] = "heartbeat";
21
+ MessageType["Kickout"] = "kickout";
22
+ MessageType["Error"] = "error";
23
+ // 订阅相关
24
+ MessageType["Subscribe"] = "subscribe";
25
+ MessageType["Unsubscribe"] = "unsubscribe";
26
+ // 行情推送
27
+ MessageType["Quote"] = "quote";
28
+ MessageType["Tick"] = "tick";
29
+ MessageType["Depth"] = "depth";
30
+ MessageType["Option"] = "option";
31
+ MessageType["Future"] = "future";
32
+ MessageType["Kline"] = "kline";
33
+ MessageType["StockTop"] = "stock_top";
34
+ MessageType["OptionTop"] = "option_top";
35
+ MessageType["FullTick"] = "full_tick";
36
+ MessageType["QuoteBBO"] = "quote_bbo";
37
+ // 账户推送
38
+ MessageType["Asset"] = "asset";
39
+ MessageType["Position"] = "position";
40
+ MessageType["Order"] = "order";
41
+ MessageType["Transaction"] = "transaction";
42
+ })(MessageType || (exports.MessageType = MessageType = {}));
43
+ /** 订阅主题类型 */
44
+ var SubjectType;
45
+ (function (SubjectType) {
46
+ SubjectType["Quote"] = "quote";
47
+ SubjectType["Tick"] = "tick";
48
+ SubjectType["Depth"] = "depth";
49
+ SubjectType["Option"] = "option";
50
+ SubjectType["Future"] = "future";
51
+ SubjectType["Kline"] = "kline";
52
+ SubjectType["StockTop"] = "stock_top";
53
+ SubjectType["OptionTop"] = "option_top";
54
+ SubjectType["FullTick"] = "full_tick";
55
+ SubjectType["QuoteBBO"] = "quote_bbo";
56
+ SubjectType["Asset"] = "asset";
57
+ SubjectType["Position"] = "position";
58
+ SubjectType["Order"] = "order";
59
+ SubjectType["Transaction"] = "transaction";
60
+ })(SubjectType || (exports.SubjectType = SubjectType = {}));
61
+ /**
62
+ * 创建推送消息
63
+ */
64
+ function createPushMessage(type, subject, data) {
65
+ const msg = { type };
66
+ if (subject)
67
+ msg.subject = subject;
68
+ if (data !== undefined)
69
+ msg.data = data;
70
+ return msg;
71
+ }
72
+ /**
73
+ * 序列化推送消息为 JSON 字符串
74
+ */
75
+ function serializeMessage(msg) {
76
+ return JSON.stringify(msg);
77
+ }
78
+ /**
79
+ * 反序列化 JSON 字符串为推送消息
80
+ */
81
+ function deserializeMessage(data) {
82
+ return JSON.parse(data);
83
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuoteClient = void 0;
4
+ /**
5
+ * 行情模块导出
6
+ */
7
+ var quote_client_1 = require("./quote-client");
8
+ Object.defineProperty(exports, "QuoteClient", { enumerable: true, get: function () { return quote_client_1.QuoteClient; } });
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuoteClient = void 0;
4
+ const api_request_1 = require("../client/api-request");
5
+ /**
6
+ * 行情查询客户端,封装所有行情相关 API。
7
+ */
8
+ class QuoteClient {
9
+ constructor(httpClient) {
10
+ this.httpClient = httpClient;
11
+ }
12
+ /**
13
+ * 内部通用方法:构造请求、发送、返回 data 字段
14
+ */
15
+ async execute(method, bizParams) {
16
+ const request = (0, api_request_1.createApiRequest)(method, bizParams);
17
+ const response = await this.httpClient.executeRequest(request);
18
+ return response.data;
19
+ }
20
+ // === 基础行情方法 ===
21
+ /** 获取市场状态 */
22
+ async marketState(market) {
23
+ return this.execute('market_state', { market });
24
+ }
25
+ /** 获取实时报价 */
26
+ async quoteRealTime(symbols) {
27
+ return this.execute('quote_real_time', { symbols });
28
+ }
29
+ /** 获取 K 线数据 */
30
+ async kline(symbol, period) {
31
+ return this.execute('kline', { symbols: [symbol], period });
32
+ }
33
+ /** 获取分时数据 */
34
+ async timeline(symbols) {
35
+ return this.execute('timeline', { symbols });
36
+ }
37
+ /** 获取逐笔成交数据 */
38
+ async tradeTick(symbols) {
39
+ return this.execute('trade_tick', { symbols });
40
+ }
41
+ /** 获取深度行情 */
42
+ async quoteDepth(symbol) {
43
+ return this.execute('quote_depth', { symbol });
44
+ }
45
+ // === 期权行情方法 ===
46
+ /** 获取期权到期日 */
47
+ async optionExpiration(symbol) {
48
+ return this.execute('option_expiration', { symbols: [symbol] });
49
+ }
50
+ /** 获取期权链 */
51
+ async optionChain(symbol, expiry) {
52
+ return this.execute('option_chain', { symbol, expiry });
53
+ }
54
+ /** 获取期权报价 */
55
+ async optionBrief(identifiers) {
56
+ return this.execute('option_brief', { identifiers });
57
+ }
58
+ /** 获取期权 K 线 */
59
+ async optionKline(identifier, period) {
60
+ return this.execute('option_kline', { identifier, period });
61
+ }
62
+ // === 期货行情方法 ===
63
+ /** 获取期货交易所列表 */
64
+ async futureExchange() {
65
+ return this.execute('future_exchange', { sec_type: 'FUT' });
66
+ }
67
+ /** 获取期货合约列表 */
68
+ async futureContracts(exchange) {
69
+ return this.execute('future_contracts', { exchange });
70
+ }
71
+ /** 获取期货实时报价 */
72
+ async futureRealTimeQuote(symbols) {
73
+ return this.execute('future_real_time_quote', { symbols });
74
+ }
75
+ /** 获取期货 K 线 */
76
+ async futureKline(symbol, period) {
77
+ return this.execute('future_kline', { symbol, period });
78
+ }
79
+ // === 基本面和资金流向方法 ===
80
+ /** 获取财务日报 */
81
+ async financialDaily(symbol) {
82
+ return this.execute('financial_daily', { symbol });
83
+ }
84
+ /** 获取财务报告 */
85
+ async financialReport(symbol) {
86
+ return this.execute('financial_report', { symbol });
87
+ }
88
+ /** 获取公司行动 */
89
+ async corporateAction(symbol) {
90
+ return this.execute('corporate_action', { symbol });
91
+ }
92
+ /** 获取资金流向 */
93
+ async capitalFlow(symbol) {
94
+ return this.execute('capital_flow', { symbol });
95
+ }
96
+ /** 获取资金分布 */
97
+ async capitalDistribution(symbol) {
98
+ return this.execute('capital_distribution', { symbol });
99
+ }
100
+ // === 选股器和行情权限方法 ===
101
+ /** 选股器 */
102
+ async marketScanner(params) {
103
+ return this.execute('market_scanner', params);
104
+ }
105
+ /** 获取行情权限 */
106
+ async grabQuotePermission() {
107
+ return this.execute('grab_quote_permission');
108
+ }
109
+ }
110
+ exports.QuoteClient = QuoteClient;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSignContent = exports.verifyWithRSA = exports.signWithRSA = exports.loadPrivateKey = void 0;
4
+ /**
5
+ * 认证层(RSA Signer)统一导出
6
+ */
7
+ var signer_1 = require("./signer");
8
+ Object.defineProperty(exports, "loadPrivateKey", { enumerable: true, get: function () { return signer_1.loadPrivateKey; } });
9
+ Object.defineProperty(exports, "signWithRSA", { enumerable: true, get: function () { return signer_1.signWithRSA; } });
10
+ Object.defineProperty(exports, "verifyWithRSA", { enumerable: true, get: function () { return signer_1.verifyWithRSA; } });
11
+ var sign_content_1 = require("./sign-content");
12
+ Object.defineProperty(exports, "getSignContent", { enumerable: true, get: function () { return sign_content_1.getSignContent; } });
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * 请求参数排序拼接模块
4
+ *
5
+ * 按参数名字母序排列所有参数,拼接为 key=value&key=value 格式,
6
+ * 用于构造 RSA 签名的待签名内容。
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getSignContent = getSignContent;
10
+ /**
11
+ * 按参数名字母序排列所有参数,拼接为 key=value&key=value 格式。
12
+ *
13
+ * @param params - 参数名-值映射
14
+ * @returns 拼接后的字符串
15
+ */
16
+ function getSignContent(params) {
17
+ const keys = Object.keys(params).sort();
18
+ return keys.map((k) => `${k}=${params[k]}`).join('&');
19
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadPrivateKey = loadPrivateKey;
4
+ exports.signWithRSA = signWithRSA;
5
+ exports.verifyWithRSA = verifyWithRSA;
6
+ /**
7
+ * RSA 签名模块
8
+ *
9
+ * 提供 RSA 私钥加载、SHA1WithRSA 签名和验签功能。
10
+ * 支持 PKCS#1、PKCS#8 PEM 格式以及裸 Base64 编码。
11
+ */
12
+ const crypto_1 = require("crypto");
13
+ /**
14
+ * 加载 RSA 私钥,支持以下格式:
15
+ * - PKCS#1 PEM(BEGIN RSA PRIVATE KEY)
16
+ * - PKCS#8 PEM(BEGIN PRIVATE KEY)
17
+ * - 裸 Base64 编码的 DER 数据(无 PEM 头尾)
18
+ *
19
+ * @param keyStr - 私钥字符串
20
+ * @returns KeyObject 私钥对象
21
+ * @throws 私钥为空或格式无效时抛出错误
22
+ */
23
+ function loadPrivateKey(keyStr) {
24
+ if (!keyStr) {
25
+ throw new Error('私钥不能为空');
26
+ }
27
+ // 尝试 PEM 格式(PKCS#1 或 PKCS#8)
28
+ if (keyStr.includes('-----BEGIN')) {
29
+ try {
30
+ return (0, crypto_1.createPrivateKey)(keyStr);
31
+ }
32
+ catch {
33
+ throw new Error('无法解析私钥:PEM 格式无效');
34
+ }
35
+ }
36
+ // 非 PEM 格式,尝试作为裸 Base64 解码
37
+ // 先尝试 PKCS#1,再尝试 PKCS#8
38
+ const derBuffer = Buffer.from(keyStr, 'base64');
39
+ if (derBuffer.length === 0) {
40
+ throw new Error('无法解析私钥:不是有效的 PEM 或 Base64 格式');
41
+ }
42
+ // 尝试 PKCS#1 DER
43
+ try {
44
+ return (0, crypto_1.createPrivateKey)({
45
+ key: derBuffer,
46
+ format: 'der',
47
+ type: 'pkcs1',
48
+ });
49
+ }
50
+ catch {
51
+ // 继续尝试 PKCS#8
52
+ }
53
+ // 尝试 PKCS#8 DER
54
+ try {
55
+ return (0, crypto_1.createPrivateKey)({
56
+ key: derBuffer,
57
+ format: 'der',
58
+ type: 'pkcs8',
59
+ });
60
+ }
61
+ catch {
62
+ throw new Error('无法解析私钥:不是有效的 PKCS#1 或 PKCS#8 格式');
63
+ }
64
+ }
65
+ /**
66
+ * 使用 RSA 私钥对内容进行 SHA1WithRSA 签名,返回 Base64 编码的签名字符串。
67
+ *
68
+ * @param privateKeyStr - 私钥字符串(支持 PKCS#1/PKCS#8 PEM 或裸 Base64)
69
+ * @param content - 待签名内容
70
+ * @returns Base64 编码的签名字符串
71
+ * @throws 私钥无效或签名失败时抛出错误
72
+ */
73
+ function signWithRSA(privateKeyStr, content) {
74
+ const key = loadPrivateKey(privateKeyStr);
75
+ const sign = (0, crypto_1.createSign)('SHA1');
76
+ sign.update(content);
77
+ sign.end();
78
+ return sign.sign(key, 'base64');
79
+ }
80
+ /**
81
+ * 使用 RSA 公钥验证 SHA1WithRSA 签名。
82
+ *
83
+ * @param publicKey - 公钥对象
84
+ * @param content - 原始内容
85
+ * @param signature - Base64 编码的签名字符串
86
+ * @returns 验签是否成功
87
+ */
88
+ function verifyWithRSA(publicKey, content, signature) {
89
+ const verify = (0, crypto_1.createVerify)('SHA1');
90
+ verify.update(content);
91
+ verify.end();
92
+ return verify.verify(publicKey, signature, 'base64');
93
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TradeClient = void 0;
4
+ /**
5
+ * 交易模块导出
6
+ */
7
+ var trade_client_1 = require("./trade-client");
8
+ Object.defineProperty(exports, "TradeClient", { enumerable: true, get: function () { return trade_client_1.TradeClient; } });
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TradeClient = void 0;
4
+ const api_request_1 = require("../client/api-request");
5
+ /**
6
+ * 交易客户端,封装所有交易相关 API。
7
+ */
8
+ class TradeClient {
9
+ constructor(httpClient, account) {
10
+ this.httpClient = httpClient;
11
+ this.account = account;
12
+ }
13
+ /**
14
+ * 内部通用方法:构造请求、发送、返回 data 字段
15
+ */
16
+ async execute(method, bizParams) {
17
+ const request = (0, api_request_1.createApiRequest)(method, bizParams);
18
+ const response = await this.httpClient.executeRequest(request);
19
+ return response.data;
20
+ }
21
+ // === 合约查询方法 ===
22
+ /** 查询单个合约 */
23
+ async contract(symbol, secType) {
24
+ return this.execute('contract', {
25
+ account: this.account, symbol, secType,
26
+ });
27
+ }
28
+ /** 批量查询合约 */
29
+ async contracts(symbols, secType) {
30
+ return this.execute('contracts', {
31
+ account: this.account, symbols, secType,
32
+ });
33
+ }
34
+ /** 查询衍生品合约 */
35
+ async quoteContract(symbol, secType) {
36
+ return this.execute('quote_contract', {
37
+ account: this.account, symbol, secType,
38
+ });
39
+ }
40
+ // === 订单操作方法 ===
41
+ /** 下单 */
42
+ async placeOrder(order) {
43
+ const params = { ...order, account: this.account };
44
+ return this.execute('place_order', params);
45
+ }
46
+ /** 预览订单 */
47
+ async previewOrder(order) {
48
+ const params = { ...order, account: this.account };
49
+ return this.execute('preview_order', params);
50
+ }
51
+ /** 修改订单 */
52
+ async modifyOrder(id, order) {
53
+ const params = { ...order, account: this.account, id };
54
+ return this.execute('modify_order', params);
55
+ }
56
+ /** 取消订单 */
57
+ async cancelOrder(id) {
58
+ return this.execute('cancel_order', {
59
+ account: this.account, id,
60
+ });
61
+ }
62
+ // === 订单查询方法 ===
63
+ /** 查询全部订单 */
64
+ async orders() {
65
+ return this.execute('orders', { account: this.account });
66
+ }
67
+ /** 查询待成交订单 */
68
+ async activeOrders() {
69
+ return this.execute('active_orders', { account: this.account });
70
+ }
71
+ /** 查询已撤销订单 */
72
+ async inactiveOrders() {
73
+ return this.execute('inactive_orders', { account: this.account });
74
+ }
75
+ /** 查询已成交订单 */
76
+ async filledOrders() {
77
+ return this.execute('filled_orders', { account: this.account });
78
+ }
79
+ // === 持仓和资产查询方法 ===
80
+ /** 查询持仓 */
81
+ async positions() {
82
+ return this.execute('positions', { account: this.account });
83
+ }
84
+ /** 查询资产 */
85
+ async assets() {
86
+ return this.execute('assets', { account: this.account });
87
+ }
88
+ /** 查询综合账户资产 */
89
+ async primeAssets() {
90
+ return this.execute('prime_assets', { account: this.account });
91
+ }
92
+ /** 查询订单成交明细 */
93
+ async orderTransactions(id) {
94
+ return this.execute('order_transactions', {
95
+ account: this.account, id,
96
+ });
97
+ }
98
+ }
99
+ exports.TradeClient = TradeClient;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * API 请求构造模块
3
+ */
4
+ /**
5
+ * 创建 API 请求,将业务参数序列化为 JSON 字符串作为 bizContent。
6
+ *
7
+ * @param method - API 方法名
8
+ * @param bizParams - 业务参数(对象、字符串或 null)
9
+ * @returns ApiRequest 对象
10
+ */
11
+ export function createApiRequest(method, bizParams) {
12
+ let bizContent;
13
+ if (typeof bizParams === 'string') {
14
+ bizContent = bizParams;
15
+ }
16
+ else if (bizParams == null) {
17
+ bizContent = '{}';
18
+ }
19
+ else {
20
+ bizContent = JSON.stringify(bizParams);
21
+ }
22
+ return { method, bizContent };
23
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * API 响应解析模块
3
+ */
4
+ import { TigerError } from './errors';
5
+ /**
6
+ * 解析 API 响应 JSON 字符串。
7
+ * code 为 0 时返回 ApiResponse;code 不为 0 时抛出 TigerError。
8
+ */
9
+ export function parseApiResponse(body) {
10
+ const resp = JSON.parse(body);
11
+ if (resp.code !== 0) {
12
+ throw new TigerError(resp.code, resp.message);
13
+ }
14
+ return resp;
15
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 错误类型定义模块
3
+ *
4
+ * 定义 TigerError 及错误码分类逻辑。
5
+ */
6
+ /**
7
+ * 根据错误码返回对应的错误分类
8
+ */
9
+ export function classifyErrorCode(code) {
10
+ if (code === 0)
11
+ return 'success';
12
+ if (code === 5)
13
+ return 'rate_limit';
14
+ if (code >= 1000 && code < 1010)
15
+ return 'common_param_error';
16
+ if (code >= 1010 && code < 1100)
17
+ return 'biz_param_error';
18
+ if (code >= 1100 && code < 1200)
19
+ return 'trade_global_error';
20
+ if (code >= 1200 && code < 1300)
21
+ return 'trade_prime_error';
22
+ if (code >= 1300 && code < 2100)
23
+ return 'trade_simulation_error';
24
+ if (code >= 2100 && code < 2200)
25
+ return 'quote_stock_error';
26
+ if (code >= 2200 && code < 2300)
27
+ return 'quote_option_error';
28
+ if (code >= 2300 && code < 2400)
29
+ return 'quote_future_error';
30
+ if (code >= 2400 && code < 4000)
31
+ return 'token_error';
32
+ if (code >= 4000 && code < 5000)
33
+ return 'permission_error';
34
+ return 'unknown_error';
35
+ }
36
+ /**
37
+ * TigerError - 统一错误类型
38
+ */
39
+ export class TigerError extends Error {
40
+ constructor(code, message) {
41
+ super(message);
42
+ this.name = 'TigerError';
43
+ this.code = code;
44
+ this.category = classifyErrorCode(code);
45
+ }
46
+ }
@@ -0,0 +1,145 @@
1
+ import { getSignContent } from '../signer/sign-content';
2
+ import { signWithRSA } from '../signer/signer';
3
+ import { TigerError } from './errors';
4
+ import { defaultRetryPolicy } from './retry';
5
+ import { parseApiResponse } from './api-response';
6
+ /** SDK 版本号 */
7
+ const SDK_VERSION = '0.1.0';
8
+ /** User-Agent 字符串 */
9
+ const USER_AGENT = `openapi-typescript-sdk-${SDK_VERSION}`;
10
+ /** 默认字符集 */
11
+ const DEFAULT_CHARSET = 'UTF-8';
12
+ /** 默认签名类型 */
13
+ const DEFAULT_SIGN_TYPE = 'RSA';
14
+ /** 默认 API 版本 */
15
+ const DEFAULT_VERSION = '2.0';
16
+ /**
17
+ * HttpClient 封装 HTTP 请求、签名、重试、超时
18
+ */
19
+ export class HttpClient {
20
+ constructor(config, retryPolicy) {
21
+ this.config = config;
22
+ this.retryPolicy = retryPolicy ?? defaultRetryPolicy();
23
+ }
24
+ /**
25
+ * 构造公共请求参数
26
+ */
27
+ buildCommonParams(apiMethod, bizContent) {
28
+ const params = {
29
+ tiger_id: this.config.tigerId,
30
+ method: apiMethod,
31
+ charset: DEFAULT_CHARSET,
32
+ sign_type: DEFAULT_SIGN_TYPE,
33
+ timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),
34
+ version: DEFAULT_VERSION,
35
+ biz_content: bizContent,
36
+ };
37
+ if (this.config.language) {
38
+ params['language'] = this.config.language;
39
+ }
40
+ return params;
41
+ }
42
+ /**
43
+ * 对参数进行签名
44
+ */
45
+ signParams(params) {
46
+ const content = getSignContent(params);
47
+ return signWithRSA(this.config.privateKey, content);
48
+ }
49
+ /**
50
+ * 发送 HTTP POST 请求
51
+ */
52
+ async doHttpPost(params) {
53
+ const body = JSON.stringify(params);
54
+ const headers = {
55
+ 'Content-Type': 'application/json;charset=UTF-8',
56
+ 'User-Agent': USER_AGENT,
57
+ };
58
+ if (this.config.token) {
59
+ headers['Authorization'] = this.config.token;
60
+ }
61
+ const response = await fetch(this.config.serverUrl, {
62
+ method: 'POST',
63
+ headers,
64
+ body,
65
+ signal: AbortSignal.timeout(this.config.timeout * 1000),
66
+ });
67
+ return response.text();
68
+ }
69
+ /**
70
+ * 执行结构化 API 请求,返回解析后的 ApiResponse。
71
+ * 供 QuoteClient/TradeClient 内部使用。
72
+ */
73
+ async executeRequest(request) {
74
+ const params = this.buildCommonParams(request.method, request.bizContent);
75
+ const sign = this.signParams(params);
76
+ params['sign'] = sign;
77
+ let lastErr;
78
+ const maxAttempts = this.retryPolicy.shouldRetry(request.method)
79
+ ? this.retryPolicy.maxRetries + 1
80
+ : 1;
81
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
82
+ if (attempt > 0) {
83
+ const backoff = this.retryPolicy.calculateBackoff(attempt - 1);
84
+ await this.sleep(backoff);
85
+ }
86
+ try {
87
+ const body = await this.doHttpPost(params);
88
+ return parseApiResponse(body);
89
+ }
90
+ catch (err) {
91
+ lastErr = err;
92
+ if (!this.retryPolicy.shouldRetry(request.method)) {
93
+ throw err;
94
+ }
95
+ }
96
+ }
97
+ throw lastErr;
98
+ }
99
+ /**
100
+ * 通用 API 调用方法。
101
+ *
102
+ * @param apiMethod - API 方法名(如 "market_state"、"place_order")
103
+ * @param requestJson - 原始 biz_content JSON 字符串
104
+ * @returns 原始 response JSON 字符串,不做任何解析
105
+ */
106
+ async execute(apiMethod, requestJson) {
107
+ // 参数校验
108
+ if (!apiMethod) {
109
+ throw new TigerError(-1, 'api_method 不能为空');
110
+ }
111
+ try {
112
+ JSON.parse(requestJson);
113
+ }
114
+ catch {
115
+ throw new TigerError(-1, 'request_json 不是有效的 JSON');
116
+ }
117
+ const params = this.buildCommonParams(apiMethod, requestJson);
118
+ const sign = this.signParams(params);
119
+ params['sign'] = sign;
120
+ let lastErr;
121
+ const maxAttempts = this.retryPolicy.shouldRetry(apiMethod)
122
+ ? this.retryPolicy.maxRetries + 1
123
+ : 1;
124
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
125
+ if (attempt > 0) {
126
+ const backoff = this.retryPolicy.calculateBackoff(attempt - 1);
127
+ await this.sleep(backoff);
128
+ }
129
+ try {
130
+ return await this.doHttpPost(params);
131
+ }
132
+ catch (err) {
133
+ lastErr = err;
134
+ if (!this.retryPolicy.shouldRetry(apiMethod)) {
135
+ throw err;
136
+ }
137
+ }
138
+ }
139
+ throw lastErr;
140
+ }
141
+ /** 延迟指定毫秒 */
142
+ sleep(ms) {
143
+ return new Promise((resolve) => setTimeout(resolve, ms));
144
+ }
145
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 传输层模块导出
3
+ */
4
+ export { HttpClient } from './http-client';
5
+ export { TigerError, classifyErrorCode } from './errors';
6
+ export { RetryPolicy, defaultRetryPolicy, isTradeOperation } from './retry';
7
+ export { createApiRequest } from './api-request';
8
+ export { parseApiResponse } from './api-response';