@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,110 @@
1
+ "use strict";
2
+ /**
3
+ * 枚举类型定义
4
+ * 所有枚举值与 API JSON 保持一致
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.TimeInForce = exports.License = exports.QuoteRight = exports.Language = exports.BarPeriod = exports.OrderStatus = exports.OrderType = exports.Currency = exports.SecurityType = exports.Market = void 0;
8
+ /** 市场枚举 */
9
+ var Market;
10
+ (function (Market) {
11
+ Market["All"] = "ALL";
12
+ Market["US"] = "US";
13
+ Market["HK"] = "HK";
14
+ Market["CN"] = "CN";
15
+ Market["SG"] = "SG";
16
+ })(Market || (exports.Market = Market = {}));
17
+ /** 证券类型枚举 */
18
+ var SecurityType;
19
+ (function (SecurityType) {
20
+ SecurityType["All"] = "ALL";
21
+ SecurityType["STK"] = "STK";
22
+ SecurityType["OPT"] = "OPT";
23
+ SecurityType["WAR"] = "WAR";
24
+ SecurityType["IOPT"] = "IOPT";
25
+ SecurityType["FUT"] = "FUT";
26
+ SecurityType["FOP"] = "FOP";
27
+ SecurityType["CASH"] = "CASH";
28
+ SecurityType["MLEG"] = "MLEG";
29
+ SecurityType["FUND"] = "FUND";
30
+ })(SecurityType || (exports.SecurityType = SecurityType = {}));
31
+ /** 货币枚举 */
32
+ var Currency;
33
+ (function (Currency) {
34
+ Currency["All"] = "ALL";
35
+ Currency["USD"] = "USD";
36
+ Currency["HKD"] = "HKD";
37
+ Currency["CNH"] = "CNH";
38
+ Currency["SGD"] = "SGD";
39
+ })(Currency || (exports.Currency = Currency = {}));
40
+ /** 订单类型枚举 */
41
+ var OrderType;
42
+ (function (OrderType) {
43
+ OrderType["MKT"] = "MKT";
44
+ OrderType["LMT"] = "LMT";
45
+ OrderType["STP"] = "STP";
46
+ OrderType["STP_LMT"] = "STP_LMT";
47
+ OrderType["TRAIL"] = "TRAIL";
48
+ OrderType["AM"] = "AM";
49
+ OrderType["AL"] = "AL";
50
+ OrderType["TWAP"] = "TWAP";
51
+ OrderType["VWAP"] = "VWAP";
52
+ OrderType["OCA"] = "OCA";
53
+ })(OrderType || (exports.OrderType = OrderType = {}));
54
+ /** 订单状态枚举 */
55
+ var OrderStatus;
56
+ (function (OrderStatus) {
57
+ OrderStatus["PendingNew"] = "PendingNew";
58
+ OrderStatus["Initial"] = "Initial";
59
+ OrderStatus["Submitted"] = "Submitted";
60
+ OrderStatus["PartiallyFilled"] = "PartiallyFilled";
61
+ OrderStatus["Filled"] = "Filled";
62
+ OrderStatus["Cancelled"] = "Cancelled";
63
+ OrderStatus["PendingCancel"] = "PendingCancel";
64
+ OrderStatus["Inactive"] = "Inactive";
65
+ OrderStatus["Invalid"] = "Invalid";
66
+ })(OrderStatus || (exports.OrderStatus = OrderStatus = {}));
67
+ /** K 线周期枚举 */
68
+ var BarPeriod;
69
+ (function (BarPeriod) {
70
+ BarPeriod["Day"] = "day";
71
+ BarPeriod["Week"] = "week";
72
+ BarPeriod["Month"] = "month";
73
+ BarPeriod["Year"] = "year";
74
+ BarPeriod["Min1"] = "1min";
75
+ BarPeriod["Min5"] = "5min";
76
+ BarPeriod["Min15"] = "15min";
77
+ BarPeriod["Min30"] = "30min";
78
+ BarPeriod["Min60"] = "60min";
79
+ })(BarPeriod || (exports.BarPeriod = BarPeriod = {}));
80
+ /** 语言枚举 */
81
+ var Language;
82
+ (function (Language) {
83
+ Language["ZhCN"] = "zh_CN";
84
+ Language["ZhTW"] = "zh_TW";
85
+ Language["EnUS"] = "en_US";
86
+ })(Language || (exports.Language = Language = {}));
87
+ /** 复权类型枚举 */
88
+ var QuoteRight;
89
+ (function (QuoteRight) {
90
+ /** 前复权 */
91
+ QuoteRight["Br"] = "br";
92
+ /** 不复权 */
93
+ QuoteRight["Nr"] = "nr";
94
+ })(QuoteRight || (exports.QuoteRight = QuoteRight = {}));
95
+ /** 牌照类型枚举 */
96
+ var License;
97
+ (function (License) {
98
+ License["TBNZ"] = "TBNZ";
99
+ License["TBSG"] = "TBSG";
100
+ License["TBHK"] = "TBHK";
101
+ License["TBAU"] = "TBAU";
102
+ License["TBUS"] = "TBUS";
103
+ })(License || (exports.License = License = {}));
104
+ /** 订单有效期枚举 */
105
+ var TimeInForce;
106
+ (function (TimeInForce) {
107
+ TimeInForce["DAY"] = "DAY";
108
+ TimeInForce["GTC"] = "GTC";
109
+ TimeInForce["OPG"] = "OPG";
110
+ })(TimeInForce || (exports.TimeInForce = TimeInForce = {}));
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.marketOrder = marketOrder;
4
+ exports.limitOrder = limitOrder;
5
+ exports.stopOrder = stopOrder;
6
+ exports.stopLimitOrder = stopLimitOrder;
7
+ exports.trailOrder = trailOrder;
8
+ exports.auctionLimitOrder = auctionLimitOrder;
9
+ exports.auctionMarketOrder = auctionMarketOrder;
10
+ exports.algoOrder = algoOrder;
11
+ exports.orderLeg = orderLeg;
12
+ const enums_1 = require("./enums");
13
+ /** 构造市价单 */
14
+ function marketOrder(account, symbol, secType, action, quantity) {
15
+ return {
16
+ account, symbol, secType, action,
17
+ orderType: enums_1.OrderType.MKT,
18
+ totalQuantity: quantity,
19
+ timeInForce: enums_1.TimeInForce.DAY,
20
+ outsideRth: false,
21
+ };
22
+ }
23
+ /** 构造限价单 */
24
+ function limitOrder(account, symbol, secType, action, quantity, limitPrice) {
25
+ return {
26
+ account, symbol, secType, action,
27
+ orderType: enums_1.OrderType.LMT,
28
+ totalQuantity: quantity,
29
+ limitPrice,
30
+ timeInForce: enums_1.TimeInForce.DAY,
31
+ outsideRth: false,
32
+ };
33
+ }
34
+ /** 构造止损单 */
35
+ function stopOrder(account, symbol, secType, action, quantity, auxPrice) {
36
+ return {
37
+ account, symbol, secType, action,
38
+ orderType: enums_1.OrderType.STP,
39
+ totalQuantity: quantity,
40
+ auxPrice,
41
+ timeInForce: enums_1.TimeInForce.DAY,
42
+ outsideRth: false,
43
+ };
44
+ }
45
+ /** 构造止损限价单 */
46
+ function stopLimitOrder(account, symbol, secType, action, quantity, limitPrice, auxPrice) {
47
+ return {
48
+ account, symbol, secType, action,
49
+ orderType: enums_1.OrderType.STP_LMT,
50
+ totalQuantity: quantity,
51
+ limitPrice,
52
+ auxPrice,
53
+ timeInForce: enums_1.TimeInForce.DAY,
54
+ outsideRth: false,
55
+ };
56
+ }
57
+ /** 构造跟踪止损单 */
58
+ function trailOrder(account, symbol, secType, action, quantity, trailingPercent) {
59
+ return {
60
+ account, symbol, secType, action,
61
+ orderType: enums_1.OrderType.TRAIL,
62
+ totalQuantity: quantity,
63
+ trailingPercent,
64
+ timeInForce: enums_1.TimeInForce.DAY,
65
+ outsideRth: false,
66
+ };
67
+ }
68
+ /** 构造竞价限价单 */
69
+ function auctionLimitOrder(account, symbol, secType, action, quantity, limitPrice) {
70
+ return {
71
+ account, symbol, secType, action,
72
+ orderType: enums_1.OrderType.AL,
73
+ totalQuantity: quantity,
74
+ limitPrice,
75
+ timeInForce: enums_1.TimeInForce.DAY,
76
+ outsideRth: false,
77
+ };
78
+ }
79
+ /** 构造竞价市价单 */
80
+ function auctionMarketOrder(account, symbol, secType, action, quantity) {
81
+ return {
82
+ account, symbol, secType, action,
83
+ orderType: enums_1.OrderType.AM,
84
+ totalQuantity: quantity,
85
+ timeInForce: enums_1.TimeInForce.DAY,
86
+ outsideRth: false,
87
+ };
88
+ }
89
+ /** 构造算法订单(TWAP/VWAP) */
90
+ function algoOrder(account, symbol, secType, action, quantity, limitPrice, algoType, params) {
91
+ return {
92
+ account, symbol, secType, action,
93
+ orderType: algoType,
94
+ totalQuantity: quantity,
95
+ limitPrice,
96
+ algoParams: params,
97
+ timeInForce: enums_1.TimeInForce.DAY,
98
+ outsideRth: false,
99
+ };
100
+ }
101
+ /** 构造附加订单(止盈/止损) */
102
+ function orderLeg(legType, price, timeInForce) {
103
+ return { legType, price, timeInForce };
104
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Order 订单接口
4
+ * 字段名 camelCase 与 API JSON 天然一致,不改名、不加封装层
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Position 持仓接口
4
+ * 字段名 camelCase 与 API JSON 天然一致,不改名、不加封装层
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ConnectionState = exports.PushClient = void 0;
18
+ /**
19
+ * 推送模块导出
20
+ */
21
+ __exportStar(require("./push-message"), exports);
22
+ __exportStar(require("./callbacks"), exports);
23
+ var push_client_1 = require("./push-client");
24
+ Object.defineProperty(exports, "PushClient", { enumerable: true, get: function () { return push_client_1.PushClient; } });
25
+ Object.defineProperty(exports, "ConnectionState", { enumerable: true, get: function () { return push_client_1.ConnectionState; } });
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PushClient = exports.ConnectionState = void 0;
4
+ const signer_1 = require("../signer/signer");
5
+ const push_message_1 = require("./push-message");
6
+ /** 默认推送服务器地址 */
7
+ const DEFAULT_PUSH_URL = 'wss://openapi-push.tigerfintech.com';
8
+ /** 默认心跳间隔(毫秒) */
9
+ const DEFAULT_HEARTBEAT_INTERVAL = 10000;
10
+ /** 默认重连间隔(毫秒) */
11
+ const DEFAULT_RECONNECT_INTERVAL = 5000;
12
+ /** 最大重连间隔(毫秒) */
13
+ const MAX_RECONNECT_INTERVAL = 60000;
14
+ /** 默认连接超时(毫秒) */
15
+ const DEFAULT_CONNECT_TIMEOUT = 30000;
16
+ /** 连接状态 */
17
+ var ConnectionState;
18
+ (function (ConnectionState) {
19
+ ConnectionState[ConnectionState["Disconnected"] = 0] = "Disconnected";
20
+ ConnectionState[ConnectionState["Connecting"] = 1] = "Connecting";
21
+ ConnectionState[ConnectionState["Connected"] = 2] = "Connected";
22
+ })(ConnectionState || (exports.ConnectionState = ConnectionState = {}));
23
+ /**
24
+ * PushClient WebSocket 推送客户端
25
+ */
26
+ class PushClient {
27
+ constructor(config, options) {
28
+ this.ws = null;
29
+ this._state = ConnectionState.Disconnected;
30
+ this.callbacks = {};
31
+ /** 订阅状态管理:subject -> Set<symbol> */
32
+ this.subscriptions = new Map();
33
+ /** 账户级别订阅 */
34
+ this.accountSubs = new Set();
35
+ this.heartbeatTimer = null;
36
+ this.reconnectTimer = null;
37
+ this.stopped = false;
38
+ /** 可注入的 WebSocket 工厂(用于测试) */
39
+ this.wsFactory = null;
40
+ this.config = config;
41
+ this.pushUrl = options?.pushUrl ?? DEFAULT_PUSH_URL;
42
+ this.heartbeatInterval = options?.heartbeatInterval ?? DEFAULT_HEARTBEAT_INTERVAL;
43
+ this.reconnectInterval = options?.reconnectInterval ?? DEFAULT_RECONNECT_INTERVAL;
44
+ this.autoReconnect = options?.autoReconnect ?? true;
45
+ this.connectTimeout = options?.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT;
46
+ }
47
+ /** 获取当前连接状态 */
48
+ get state() {
49
+ return this._state;
50
+ }
51
+ /** 设置回调函数集合 */
52
+ setCallbacks(cb) {
53
+ this.callbacks = cb;
54
+ }
55
+ /** 连接到推送服务器并进行认证 */
56
+ connect() {
57
+ return new Promise((resolve, reject) => {
58
+ if (this._state !== ConnectionState.Disconnected) {
59
+ reject(new Error('客户端已连接或正在连接中'));
60
+ return;
61
+ }
62
+ this._state = ConnectionState.Connecting;
63
+ this.stopped = false;
64
+ const ws = this.createWebSocket(this.pushUrl);
65
+ this.ws = ws;
66
+ const timeout = setTimeout(() => {
67
+ ws.close();
68
+ this._state = ConnectionState.Disconnected;
69
+ this.ws = null;
70
+ reject(new Error('连接超时'));
71
+ }, this.connectTimeout);
72
+ ws.onopen = () => {
73
+ clearTimeout(timeout);
74
+ // 发送认证消息
75
+ try {
76
+ this.authenticate();
77
+ this._state = ConnectionState.Connected;
78
+ this.startHeartbeat();
79
+ this.callbacks.onConnect?.();
80
+ resolve();
81
+ }
82
+ catch (err) {
83
+ ws.close();
84
+ this._state = ConnectionState.Disconnected;
85
+ this.ws = null;
86
+ reject(err);
87
+ }
88
+ };
89
+ ws.onmessage = (ev) => {
90
+ this.handleMessage(String(ev.data));
91
+ };
92
+ ws.onclose = () => {
93
+ if (this.stopped)
94
+ return;
95
+ this.stopHeartbeat();
96
+ const wasConnected = this._state === ConnectionState.Connected;
97
+ this._state = ConnectionState.Disconnected;
98
+ this.ws = null;
99
+ if (wasConnected && this.autoReconnect && !this.stopped) {
100
+ this.scheduleReconnect();
101
+ }
102
+ };
103
+ ws.onerror = (ev) => {
104
+ if (this._state === ConnectionState.Connecting) {
105
+ clearTimeout(timeout);
106
+ this._state = ConnectionState.Disconnected;
107
+ this.ws = null;
108
+ reject(new Error('WebSocket 连接失败'));
109
+ }
110
+ else {
111
+ this.callbacks.onError?.(new Error('WebSocket 错误'));
112
+ }
113
+ };
114
+ });
115
+ }
116
+ /** 断开连接 */
117
+ disconnect() {
118
+ this.stopped = true;
119
+ this.stopHeartbeat();
120
+ this.clearReconnectTimer();
121
+ if (this.ws) {
122
+ this.ws.onclose = null;
123
+ this.ws.onerror = null;
124
+ this.ws.onmessage = null;
125
+ this.ws.close();
126
+ this.ws = null;
127
+ }
128
+ this._state = ConnectionState.Disconnected;
129
+ this.callbacks.onDisconnect?.();
130
+ }
131
+ /** 发送认证消息 */
132
+ authenticate() {
133
+ const ts = new Date().toISOString().replace('T', ' ').substring(0, 19);
134
+ const sign = (0, signer_1.signWithRSA)(this.config.privateKey, this.config.tigerId);
135
+ const req = {
136
+ tigerId: this.config.tigerId,
137
+ sign,
138
+ timestamp: ts,
139
+ version: '2.0',
140
+ };
141
+ const msg = (0, push_message_1.createPushMessage)(push_message_1.MessageType.Connect, undefined, req);
142
+ this.sendMessage(msg);
143
+ }
144
+ /** 发送消息 */
145
+ sendMessage(msg) {
146
+ if (!this.ws)
147
+ throw new Error('WebSocket 连接未建立');
148
+ this.ws.send((0, push_message_1.serializeMessage)(msg));
149
+ }
150
+ /** 创建 WebSocket 实例 */
151
+ createWebSocket(url) {
152
+ if (this.wsFactory)
153
+ return this.wsFactory(url);
154
+ // 动态导入 ws 库(Node.js 环境)
155
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
156
+ const WS = require('ws');
157
+ return new WS(url);
158
+ }
159
+ /** 心跳保活 */
160
+ startHeartbeat() {
161
+ this.stopHeartbeat();
162
+ this.heartbeatTimer = setInterval(() => {
163
+ try {
164
+ const msg = (0, push_message_1.createPushMessage)(push_message_1.MessageType.Heartbeat);
165
+ this.sendMessage(msg);
166
+ }
167
+ catch {
168
+ // 心跳发送失败,连接可能已断开
169
+ }
170
+ }, this.heartbeatInterval);
171
+ }
172
+ stopHeartbeat() {
173
+ if (this.heartbeatTimer) {
174
+ clearInterval(this.heartbeatTimer);
175
+ this.heartbeatTimer = null;
176
+ }
177
+ }
178
+ /** 自动重连 */
179
+ scheduleReconnect() {
180
+ let interval = this.reconnectInterval;
181
+ const attempt = () => {
182
+ if (this.stopped)
183
+ return;
184
+ this.connect().then(() => {
185
+ this.resubscribe();
186
+ }).catch(() => {
187
+ interval = Math.min(interval * 2, MAX_RECONNECT_INTERVAL);
188
+ if (!this.stopped) {
189
+ this.reconnectTimer = setTimeout(attempt, interval);
190
+ }
191
+ });
192
+ };
193
+ this.reconnectTimer = setTimeout(attempt, interval);
194
+ }
195
+ clearReconnectTimer() {
196
+ if (this.reconnectTimer) {
197
+ clearTimeout(this.reconnectTimer);
198
+ this.reconnectTimer = null;
199
+ }
200
+ }
201
+ /** 重连后恢复订阅 */
202
+ resubscribe() {
203
+ for (const [subject, symbols] of this.subscriptions) {
204
+ this.doSubscribe(subject, Array.from(symbols));
205
+ }
206
+ for (const subject of this.accountSubs) {
207
+ this.doSubscribe(subject, undefined, this.config.account);
208
+ }
209
+ }
210
+ /** 处理收到的消息 */
211
+ handleMessage(raw) {
212
+ let msg;
213
+ try {
214
+ msg = (0, push_message_1.deserializeMessage)(raw);
215
+ }
216
+ catch {
217
+ this.callbacks.onError?.(new Error('反序列化消息失败'));
218
+ return;
219
+ }
220
+ const cb = this.callbacks;
221
+ switch (msg.type) {
222
+ case push_message_1.MessageType.Kickout:
223
+ cb.onKickout?.(msg.data);
224
+ break;
225
+ case push_message_1.MessageType.Error:
226
+ cb.onError?.(new Error(`服务端错误: ${msg.data}`));
227
+ break;
228
+ case push_message_1.MessageType.Quote:
229
+ cb.onQuote?.(msg.data);
230
+ break;
231
+ case push_message_1.MessageType.Tick:
232
+ cb.onTick?.(msg.data);
233
+ break;
234
+ case push_message_1.MessageType.Depth:
235
+ cb.onDepth?.(msg.data);
236
+ break;
237
+ case push_message_1.MessageType.Option:
238
+ cb.onOption?.(msg.data);
239
+ break;
240
+ case push_message_1.MessageType.Future:
241
+ cb.onFuture?.(msg.data);
242
+ break;
243
+ case push_message_1.MessageType.Kline:
244
+ cb.onKline?.(msg.data);
245
+ break;
246
+ case push_message_1.MessageType.Asset:
247
+ cb.onAsset?.(msg.data);
248
+ break;
249
+ case push_message_1.MessageType.Position:
250
+ cb.onPosition?.(msg.data);
251
+ break;
252
+ case push_message_1.MessageType.Order:
253
+ cb.onOrder?.(msg.data);
254
+ break;
255
+ case push_message_1.MessageType.Transaction:
256
+ cb.onTransaction?.(msg.data);
257
+ break;
258
+ case push_message_1.MessageType.StockTop:
259
+ cb.onStockTop?.(msg.data);
260
+ break;
261
+ case push_message_1.MessageType.OptionTop:
262
+ cb.onOptionTop?.(msg.data);
263
+ break;
264
+ case push_message_1.MessageType.FullTick:
265
+ cb.onFullTick?.(msg.data);
266
+ break;
267
+ case push_message_1.MessageType.QuoteBBO:
268
+ cb.onQuoteBBO?.(msg.data);
269
+ break;
270
+ }
271
+ }
272
+ /** 内部订阅方法 */
273
+ doSubscribe(subject, symbols, account, market) {
274
+ const req = { subject, symbols, account, market };
275
+ const msg = (0, push_message_1.createPushMessage)(push_message_1.MessageType.Subscribe, subject, req);
276
+ this.sendMessage(msg);
277
+ }
278
+ /** 内部退订方法 */
279
+ doUnsubscribe(subject, symbols) {
280
+ const req = { subject, symbols };
281
+ const msg = (0, push_message_1.createPushMessage)(push_message_1.MessageType.Unsubscribe, subject, req);
282
+ this.sendMessage(msg);
283
+ }
284
+ /** 添加订阅记录 */
285
+ addSubscription(subject, symbols) {
286
+ if (!this.subscriptions.has(subject)) {
287
+ this.subscriptions.set(subject, new Set());
288
+ }
289
+ const set = this.subscriptions.get(subject);
290
+ for (const s of symbols)
291
+ set.add(s);
292
+ }
293
+ /** 移除订阅记录 */
294
+ removeSubscription(subject, symbols) {
295
+ if (!symbols) {
296
+ this.subscriptions.delete(subject);
297
+ return;
298
+ }
299
+ const set = this.subscriptions.get(subject);
300
+ if (set) {
301
+ for (const s of symbols)
302
+ set.delete(s);
303
+ if (set.size === 0)
304
+ this.subscriptions.delete(subject);
305
+ }
306
+ }
307
+ // ===== 行情订阅/退订 =====
308
+ /** 订阅行情 */
309
+ subscribeQuote(symbols) {
310
+ this.doSubscribe(push_message_1.SubjectType.Quote, symbols);
311
+ this.addSubscription(push_message_1.SubjectType.Quote, symbols);
312
+ }
313
+ /** 退订行情 */
314
+ unsubscribeQuote(symbols) {
315
+ this.doUnsubscribe(push_message_1.SubjectType.Quote, symbols);
316
+ this.removeSubscription(push_message_1.SubjectType.Quote, symbols);
317
+ }
318
+ /** 订阅逐笔成交 */
319
+ subscribeTick(symbols) {
320
+ this.doSubscribe(push_message_1.SubjectType.Tick, symbols);
321
+ this.addSubscription(push_message_1.SubjectType.Tick, symbols);
322
+ }
323
+ /** 退订逐笔成交 */
324
+ unsubscribeTick(symbols) {
325
+ this.doUnsubscribe(push_message_1.SubjectType.Tick, symbols);
326
+ this.removeSubscription(push_message_1.SubjectType.Tick, symbols);
327
+ }
328
+ /** 订阅深度行情 */
329
+ subscribeDepth(symbols) {
330
+ this.doSubscribe(push_message_1.SubjectType.Depth, symbols);
331
+ this.addSubscription(push_message_1.SubjectType.Depth, symbols);
332
+ }
333
+ /** 退订深度行情 */
334
+ unsubscribeDepth(symbols) {
335
+ this.doUnsubscribe(push_message_1.SubjectType.Depth, symbols);
336
+ this.removeSubscription(push_message_1.SubjectType.Depth, symbols);
337
+ }
338
+ /** 订阅期权行情 */
339
+ subscribeOption(symbols) {
340
+ this.doSubscribe(push_message_1.SubjectType.Option, symbols);
341
+ this.addSubscription(push_message_1.SubjectType.Option, symbols);
342
+ }
343
+ /** 退订期权行情 */
344
+ unsubscribeOption(symbols) {
345
+ this.doUnsubscribe(push_message_1.SubjectType.Option, symbols);
346
+ this.removeSubscription(push_message_1.SubjectType.Option, symbols);
347
+ }
348
+ /** 订阅期货行情 */
349
+ subscribeFuture(symbols) {
350
+ this.doSubscribe(push_message_1.SubjectType.Future, symbols);
351
+ this.addSubscription(push_message_1.SubjectType.Future, symbols);
352
+ }
353
+ /** 退订期货行情 */
354
+ unsubscribeFuture(symbols) {
355
+ this.doUnsubscribe(push_message_1.SubjectType.Future, symbols);
356
+ this.removeSubscription(push_message_1.SubjectType.Future, symbols);
357
+ }
358
+ /** 订阅 K 线 */
359
+ subscribeKline(symbols) {
360
+ this.doSubscribe(push_message_1.SubjectType.Kline, symbols);
361
+ this.addSubscription(push_message_1.SubjectType.Kline, symbols);
362
+ }
363
+ /** 退订 K 线 */
364
+ unsubscribeKline(symbols) {
365
+ this.doUnsubscribe(push_message_1.SubjectType.Kline, symbols);
366
+ this.removeSubscription(push_message_1.SubjectType.Kline, symbols);
367
+ }
368
+ // ===== 账户推送订阅/退订 =====
369
+ /** 订阅资产变动 */
370
+ subscribeAsset(account) {
371
+ this.doSubscribe(push_message_1.SubjectType.Asset, undefined, account || this.config.account);
372
+ this.accountSubs.add(push_message_1.SubjectType.Asset);
373
+ }
374
+ /** 退订资产变动 */
375
+ unsubscribeAsset() {
376
+ this.doUnsubscribe(push_message_1.SubjectType.Asset);
377
+ this.accountSubs.delete(push_message_1.SubjectType.Asset);
378
+ }
379
+ /** 订阅持仓变动 */
380
+ subscribePosition(account) {
381
+ this.doSubscribe(push_message_1.SubjectType.Position, undefined, account || this.config.account);
382
+ this.accountSubs.add(push_message_1.SubjectType.Position);
383
+ }
384
+ /** 退订持仓变动 */
385
+ unsubscribePosition() {
386
+ this.doUnsubscribe(push_message_1.SubjectType.Position);
387
+ this.accountSubs.delete(push_message_1.SubjectType.Position);
388
+ }
389
+ /** 订阅订单状态 */
390
+ subscribeOrder(account) {
391
+ this.doSubscribe(push_message_1.SubjectType.Order, undefined, account || this.config.account);
392
+ this.accountSubs.add(push_message_1.SubjectType.Order);
393
+ }
394
+ /** 退订订单状态 */
395
+ unsubscribeOrder() {
396
+ this.doUnsubscribe(push_message_1.SubjectType.Order);
397
+ this.accountSubs.delete(push_message_1.SubjectType.Order);
398
+ }
399
+ /** 订阅成交明细 */
400
+ subscribeTransaction(account) {
401
+ this.doSubscribe(push_message_1.SubjectType.Transaction, undefined, account || this.config.account);
402
+ this.accountSubs.add(push_message_1.SubjectType.Transaction);
403
+ }
404
+ /** 退订成交明细 */
405
+ unsubscribeTransaction() {
406
+ this.doUnsubscribe(push_message_1.SubjectType.Transaction);
407
+ this.accountSubs.delete(push_message_1.SubjectType.Transaction);
408
+ }
409
+ // ===== 查询订阅状态 =====
410
+ /** 获取当前行情订阅状态 */
411
+ getSubscriptions() {
412
+ const result = new Map();
413
+ for (const [subject, symbols] of this.subscriptions) {
414
+ result.set(subject, Array.from(symbols));
415
+ }
416
+ return result;
417
+ }
418
+ /** 获取账户级别订阅状态 */
419
+ getAccountSubscriptions() {
420
+ return Array.from(this.accountSubs);
421
+ }
422
+ }
423
+ exports.PushClient = PushClient;