@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,16 +1,42 @@
1
+ /**
2
+ * PushClient - TCP + TLS push client (Protobuf protocol)
3
+ *
4
+ * Connects to the push server via raw TCP + TLS to receive real-time
5
+ * market data and account push notifications.
6
+ * Uses varint32 length-prefixed + Protobuf binary frame format,
7
+ * aligned with the Java SDK's Netty + Protobuf implementation.
8
+ * Supports connection authentication, subscribe/unsubscribe, callbacks,
9
+ * heartbeat keep-alive, and automatic reconnection.
10
+ */
11
+ import * as tls from 'tls';
1
12
  import { signWithRSA } from '../signer/signer';
2
- import { MessageType, SubjectType, createPushMessage, serializeMessage, deserializeMessage, } from './push-message';
3
- /** 默认推送服务器地址 */
4
- const DEFAULT_PUSH_URL = 'wss://openapi-push.tigerfintech.com';
5
- /** 默认心跳间隔(毫秒) */
13
+ import { SubjectType } from './push-message';
14
+ import { Request } from './pb/Request';
15
+ import { Response } from './pb/Response';
16
+ import { SocketCommon_Command, SocketCommon_DataType } from './pb/SocketCommon';
17
+ import { encodeVarint32, decodeVarint32 } from './varint';
18
+ import { buildConnectMessage, buildHeartBeatMessage, buildSubscribeMessage, buildUnSubscribeMessage, buildDisconnectMessage, subjectToDataType, } from './proto-message';
19
+ /** Default push server host */
20
+ const DEFAULT_PUSH_HOST = 'openapi.tigerfintech.com';
21
+ /** Default push server port */
22
+ const DEFAULT_PUSH_PORT = 9883;
23
+ /** Default heartbeat interval (ms) */
6
24
  const DEFAULT_HEARTBEAT_INTERVAL = 10000;
7
- /** 默认重连间隔(毫秒) */
25
+ /** Default reconnect interval (ms) */
8
26
  const DEFAULT_RECONNECT_INTERVAL = 5000;
9
- /** 最大重连间隔(毫秒) */
27
+ /** Max reconnect interval (ms) */
10
28
  const MAX_RECONNECT_INTERVAL = 60000;
11
- /** 默认连接超时(毫秒) */
29
+ /** Default connect timeout (ms) */
12
30
  const DEFAULT_CONNECT_TIMEOUT = 30000;
13
- /** 连接状态 */
31
+ /** SDK version identifier */
32
+ const SDK_VERSION = 'typescript/0.1.0';
33
+ /** Protocol version */
34
+ const ACCEPT_VERSION = '1.0';
35
+ /** Default send heartbeat interval (ms) */
36
+ const DEFAULT_SEND_INTERVAL = 10000;
37
+ /** Default receive heartbeat interval (ms) */
38
+ const DEFAULT_RECEIVE_INTERVAL = 10000;
39
+ /** Connection state */
14
40
  export var ConnectionState;
15
41
  (function (ConnectionState) {
16
42
  ConnectionState[ConnectionState["Disconnected"] = 0] = "Disconnected";
@@ -18,151 +44,220 @@ export var ConnectionState;
18
44
  ConnectionState[ConnectionState["Connected"] = 2] = "Connected";
19
45
  })(ConnectionState || (ConnectionState = {}));
20
46
  /**
21
- * PushClient WebSocket 推送客户端
47
+ * PushClient - TCP + TLS push client (Protobuf protocol)
22
48
  */
23
49
  export class PushClient {
24
50
  constructor(config, options) {
25
- this.ws = null;
51
+ this.socket = null;
26
52
  this._state = ConnectionState.Disconnected;
27
53
  this.callbacks = {};
28
- /** 订阅状态管理:subject -> Set<symbol> */
54
+ /** Subscription state: subject -> Set<symbol> */
29
55
  this.subscriptions = new Map();
30
- /** 账户级别订阅 */
56
+ /** Account-level subscriptions */
31
57
  this.accountSubs = new Set();
32
58
  this.heartbeatTimer = null;
33
59
  this.reconnectTimer = null;
34
60
  this.stopped = false;
35
- /** 可注入的 WebSocket 工厂(用于测试) */
36
- this.wsFactory = null;
61
+ /** TCP stream receive buffer */
62
+ this.recvBuffer = Buffer.alloc(0);
63
+ /** Injectable TLS socket factory (for testing) */
64
+ this.socketFactory = null;
37
65
  this.config = config;
38
- this.pushUrl = options?.pushUrl ?? DEFAULT_PUSH_URL;
66
+ this.pushHost = options?.pushHost ?? DEFAULT_PUSH_HOST;
67
+ this.pushPort = options?.pushPort ?? DEFAULT_PUSH_PORT;
39
68
  this.heartbeatInterval = options?.heartbeatInterval ?? DEFAULT_HEARTBEAT_INTERVAL;
40
69
  this.reconnectInterval = options?.reconnectInterval ?? DEFAULT_RECONNECT_INTERVAL;
41
70
  this.autoReconnect = options?.autoReconnect ?? true;
42
71
  this.connectTimeout = options?.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT;
72
+ this.useFullTick = options?.useFullTick ?? false;
43
73
  }
44
- /** 获取当前连接状态 */
74
+ /** Get current connection state */
45
75
  get state() {
46
76
  return this._state;
47
77
  }
48
- /** 设置回调函数集合 */
78
+ /** Set callback functions */
49
79
  setCallbacks(cb) {
50
80
  this.callbacks = cb;
51
81
  }
52
- /** 连接到推送服务器并进行认证 */
82
+ /** Connect to the push server and authenticate */
53
83
  connect() {
54
84
  return new Promise((resolve, reject) => {
55
85
  if (this._state !== ConnectionState.Disconnected) {
56
- reject(new Error('客户端已连接或正在连接中'));
86
+ reject(new Error('Client is already connected or connecting'));
57
87
  return;
58
88
  }
59
89
  this._state = ConnectionState.Connecting;
60
90
  this.stopped = false;
61
- const ws = this.createWebSocket(this.pushUrl);
62
- this.ws = ws;
91
+ this.recvBuffer = Buffer.alloc(0);
92
+ const socket = this.createSocket(this.pushHost, this.pushPort);
93
+ this.socket = socket;
94
+ let settled = false;
63
95
  const timeout = setTimeout(() => {
64
- ws.close();
65
- this._state = ConnectionState.Disconnected;
66
- this.ws = null;
67
- reject(new Error('连接超时'));
96
+ if (!settled) {
97
+ settled = true;
98
+ socket.destroy();
99
+ this._state = ConnectionState.Disconnected;
100
+ this.socket = null;
101
+ reject(new Error('Connect timeout'));
102
+ }
68
103
  }, this.connectTimeout);
69
- ws.onopen = () => {
70
- clearTimeout(timeout);
71
- // 发送认证消息
72
- try {
73
- this.authenticate();
104
+ // Resolve once we receive CONNECTED response from server
105
+ const onConnected = () => {
106
+ if (!settled) {
107
+ settled = true;
108
+ clearTimeout(timeout);
74
109
  this._state = ConnectionState.Connected;
75
110
  this.startHeartbeat();
76
111
  this.callbacks.onConnect?.();
77
112
  resolve();
78
113
  }
114
+ };
115
+ socket.on('connect', () => {
116
+ // TLS handshake complete, send authentication message
117
+ try {
118
+ this.authenticate();
119
+ }
79
120
  catch (err) {
80
- ws.close();
81
- this._state = ConnectionState.Disconnected;
82
- this.ws = null;
83
- reject(err);
121
+ if (!settled) {
122
+ settled = true;
123
+ clearTimeout(timeout);
124
+ socket.destroy();
125
+ this._state = ConnectionState.Disconnected;
126
+ this.socket = null;
127
+ reject(err);
128
+ }
84
129
  }
85
- };
86
- ws.onmessage = (ev) => {
87
- this.handleMessage(String(ev.data));
88
- };
89
- ws.onclose = () => {
130
+ });
131
+ socket.on('data', (chunk) => {
132
+ this.handleData(chunk, onConnected);
133
+ });
134
+ socket.on('close', () => {
90
135
  if (this.stopped)
91
136
  return;
92
137
  this.stopHeartbeat();
93
138
  const wasConnected = this._state === ConnectionState.Connected;
94
139
  this._state = ConnectionState.Disconnected;
95
- this.ws = null;
140
+ this.socket = null;
96
141
  if (wasConnected && this.autoReconnect && !this.stopped) {
97
142
  this.scheduleReconnect();
98
143
  }
99
- };
100
- ws.onerror = (ev) => {
101
- if (this._state === ConnectionState.Connecting) {
144
+ });
145
+ socket.on('error', (err) => {
146
+ if (!settled) {
147
+ settled = true;
102
148
  clearTimeout(timeout);
103
149
  this._state = ConnectionState.Disconnected;
104
- this.ws = null;
105
- reject(new Error('WebSocket 连接失败'));
150
+ this.socket = null;
151
+ reject(new Error(`TLS connection failed: ${err.message}`));
106
152
  }
107
153
  else {
108
- this.callbacks.onError?.(new Error('WebSocket 错误'));
154
+ this.callbacks.onError?.(new Error(`TLS error: ${err.message}`));
109
155
  }
110
- };
156
+ });
111
157
  });
112
158
  }
113
- /** 断开连接 */
159
+ /** Disconnect from the push server */
114
160
  disconnect() {
115
161
  this.stopped = true;
116
162
  this.stopHeartbeat();
117
163
  this.clearReconnectTimer();
118
- if (this.ws) {
119
- this.ws.onclose = null;
120
- this.ws.onerror = null;
121
- this.ws.onmessage = null;
122
- this.ws.close();
123
- this.ws = null;
164
+ if (this.socket) {
165
+ // Send DISCONNECT message before closing
166
+ try {
167
+ const req = buildDisconnectMessage();
168
+ this.sendMessage(req);
169
+ }
170
+ catch {
171
+ // Ignore send failure, continue closing
172
+ }
173
+ this.socket.destroy();
174
+ this.socket = null;
124
175
  }
125
176
  this._state = ConnectionState.Disconnected;
177
+ this.recvBuffer = Buffer.alloc(0);
126
178
  this.callbacks.onDisconnect?.();
127
179
  }
128
- /** 发送认证消息 */
180
+ /** Send authentication message */
129
181
  authenticate() {
130
- const ts = new Date().toISOString().replace('T', ' ').substring(0, 19);
182
+ // Sign content is the tigerId string itself (aligned with Java SDK)
131
183
  const sign = signWithRSA(this.config.privateKey, this.config.tigerId);
132
- const req = {
133
- tigerId: this.config.tigerId,
134
- sign,
135
- timestamp: ts,
136
- version: '2.0',
137
- };
138
- const msg = createPushMessage(MessageType.Connect, undefined, req);
139
- this.sendMessage(msg);
184
+ const req = buildConnectMessage(this.config.tigerId, sign, SDK_VERSION, ACCEPT_VERSION, DEFAULT_SEND_INTERVAL, DEFAULT_RECEIVE_INTERVAL, this.useFullTick);
185
+ this.sendMessage(req);
140
186
  }
141
- /** 发送消息 */
187
+ /** Send a Protobuf Request message (varint32 length prefix + binary) */
142
188
  sendMessage(msg) {
143
- if (!this.ws)
144
- throw new Error('WebSocket 连接未建立');
145
- this.ws.send(serializeMessage(msg));
146
- }
147
- /** 创建 WebSocket 实例 */
148
- createWebSocket(url) {
149
- if (this.wsFactory)
150
- return this.wsFactory(url);
151
- // 动态导入 ws 库(Node.js 环境)
152
- // eslint-disable-next-line @typescript-eslint/no-require-imports
153
- const WS = require('ws');
154
- return new WS(url);
155
- }
156
- /** 心跳保活 */
189
+ if (!this.socket)
190
+ throw new Error('TLS connection not established');
191
+ const encoded = Request.encode(msg).finish();
192
+ const framed = encodeVarint32(encoded);
193
+ this.socket.write(framed);
194
+ }
195
+ /** Create a TLS socket instance */
196
+ createSocket(host, port) {
197
+ if (this.socketFactory)
198
+ return this.socketFactory(host, port);
199
+ return tls.connect({ host, port, rejectUnauthorized: false });
200
+ }
201
+ /** Handle incoming TCP data: buffer + decode varint32 frames */
202
+ handleData(chunk, onConnected) {
203
+ this.recvBuffer = Buffer.concat([this.recvBuffer, chunk]);
204
+ while (this.recvBuffer.length > 0) {
205
+ const frame = decodeVarint32(new Uint8Array(this.recvBuffer));
206
+ if (!frame)
207
+ break; // Incomplete frame, wait for more data
208
+ this.recvBuffer = Buffer.from(frame.remaining);
209
+ // Deserialize Protobuf Response
210
+ let response;
211
+ try {
212
+ response = Response.decode(frame.message);
213
+ }
214
+ catch {
215
+ this.callbacks.onError?.(new Error('Protobuf deserialization failed'));
216
+ continue;
217
+ }
218
+ this.handleResponse(response, onConnected);
219
+ }
220
+ }
221
+ /** Handle a decoded Response message */
222
+ handleResponse(response, onConnected) {
223
+ const cb = this.callbacks;
224
+ switch (response.command) {
225
+ case SocketCommon_Command.CONNECTED:
226
+ // Server confirmed authentication
227
+ onConnected?.();
228
+ break;
229
+ case SocketCommon_Command.HEARTBEAT:
230
+ // Heartbeat response, ignore
231
+ break;
232
+ case SocketCommon_Command.MESSAGE:
233
+ if (response.body) {
234
+ this.dispatchPushData(response.body);
235
+ }
236
+ break;
237
+ case SocketCommon_Command.ERROR:
238
+ cb.onError?.(new Error(`Server error: ${response.msg ?? 'unknown error'}`));
239
+ // Check for kickout
240
+ if (response.msg && response.msg.toLowerCase().includes('kickout')) {
241
+ cb.onKickout?.(response.msg);
242
+ }
243
+ break;
244
+ case SocketCommon_Command.DISCONNECT:
245
+ cb.onDisconnect?.();
246
+ break;
247
+ default:
248
+ break;
249
+ }
250
+ }
251
+ /** Heartbeat keep-alive */
157
252
  startHeartbeat() {
158
253
  this.stopHeartbeat();
159
254
  this.heartbeatTimer = setInterval(() => {
160
255
  try {
161
- const msg = createPushMessage(MessageType.Heartbeat);
162
- this.sendMessage(msg);
256
+ const req = buildHeartBeatMessage();
257
+ this.sendMessage(req);
163
258
  }
164
259
  catch {
165
- // 心跳发送失败,连接可能已断开
260
+ // Heartbeat send failed, connection may be broken
166
261
  }
167
262
  }, this.heartbeatInterval);
168
263
  }
@@ -172,7 +267,7 @@ export class PushClient {
172
267
  this.heartbeatTimer = null;
173
268
  }
174
269
  }
175
- /** 自动重连 */
270
+ /** Auto reconnect with exponential backoff */
176
271
  scheduleReconnect() {
177
272
  let interval = this.reconnectInterval;
178
273
  const attempt = () => {
@@ -195,7 +290,7 @@ export class PushClient {
195
290
  this.reconnectTimer = null;
196
291
  }
197
292
  }
198
- /** 重连后恢复订阅 */
293
+ /** Resubscribe after reconnection */
199
294
  resubscribe() {
200
295
  for (const [subject, symbols] of this.subscriptions) {
201
296
  this.doSubscribe(subject, Array.from(symbols));
@@ -204,81 +299,81 @@ export class PushClient {
204
299
  this.doSubscribe(subject, undefined, this.config.account);
205
300
  }
206
301
  }
207
- /** 处理收到的消息 */
208
- handleMessage(raw) {
209
- let msg;
210
- try {
211
- msg = deserializeMessage(raw);
212
- }
213
- catch {
214
- this.callbacks.onError?.(new Error('反序列化消息失败'));
215
- return;
216
- }
302
+ /** Dispatch push data to the appropriate callback based on dataType */
303
+ dispatchPushData(pushData) {
217
304
  const cb = this.callbacks;
218
- switch (msg.type) {
219
- case MessageType.Kickout:
220
- cb.onKickout?.(msg.data);
221
- break;
222
- case MessageType.Error:
223
- cb.onError?.(new Error(`服务端错误: ${msg.data}`));
224
- break;
225
- case MessageType.Quote:
226
- cb.onQuote?.(msg.data);
227
- break;
228
- case MessageType.Tick:
229
- cb.onTick?.(msg.data);
305
+ switch (pushData.dataType) {
306
+ case SocketCommon_DataType.Quote:
307
+ if (pushData.quoteData)
308
+ cb.onQuote?.(pushData.quoteData);
230
309
  break;
231
- case MessageType.Depth:
232
- cb.onDepth?.(msg.data);
310
+ case SocketCommon_DataType.Option:
311
+ if (pushData.quoteData)
312
+ cb.onOption?.(pushData.quoteData);
233
313
  break;
234
- case MessageType.Option:
235
- cb.onOption?.(msg.data);
314
+ case SocketCommon_DataType.Future:
315
+ if (pushData.quoteData)
316
+ cb.onFuture?.(pushData.quoteData);
236
317
  break;
237
- case MessageType.Future:
238
- cb.onFuture?.(msg.data);
318
+ case SocketCommon_DataType.QuoteDepth:
319
+ if (pushData.quoteDepthData)
320
+ cb.onDepth?.(pushData.quoteDepthData);
239
321
  break;
240
- case MessageType.Kline:
241
- cb.onKline?.(msg.data);
322
+ case SocketCommon_DataType.TradeTick:
323
+ if (pushData.tradeTickData)
324
+ cb.onTick?.(pushData.tradeTickData);
242
325
  break;
243
- case MessageType.Asset:
244
- cb.onAsset?.(msg.data);
326
+ case SocketCommon_DataType.Asset:
327
+ if (pushData.assetData)
328
+ cb.onAsset?.(pushData.assetData);
245
329
  break;
246
- case MessageType.Position:
247
- cb.onPosition?.(msg.data);
330
+ case SocketCommon_DataType.Position:
331
+ if (pushData.positionData)
332
+ cb.onPosition?.(pushData.positionData);
248
333
  break;
249
- case MessageType.Order:
250
- cb.onOrder?.(msg.data);
334
+ case SocketCommon_DataType.OrderStatus:
335
+ if (pushData.orderStatusData)
336
+ cb.onOrder?.(pushData.orderStatusData);
251
337
  break;
252
- case MessageType.Transaction:
253
- cb.onTransaction?.(msg.data);
338
+ case SocketCommon_DataType.OrderTransaction:
339
+ if (pushData.orderTransactionData)
340
+ cb.onTransaction?.(pushData.orderTransactionData);
254
341
  break;
255
- case MessageType.StockTop:
256
- cb.onStockTop?.(msg.data);
342
+ case SocketCommon_DataType.StockTop:
343
+ if (pushData.stockTopData)
344
+ cb.onStockTop?.(pushData.stockTopData);
257
345
  break;
258
- case MessageType.OptionTop:
259
- cb.onOptionTop?.(msg.data);
346
+ case SocketCommon_DataType.OptionTop:
347
+ if (pushData.optionTopData)
348
+ cb.onOptionTop?.(pushData.optionTopData);
260
349
  break;
261
- case MessageType.FullTick:
262
- cb.onFullTick?.(msg.data);
350
+ case SocketCommon_DataType.Kline:
351
+ if (pushData.klineData)
352
+ cb.onKline?.(pushData.klineData);
263
353
  break;
264
- case MessageType.QuoteBBO:
265
- cb.onQuoteBBO?.(msg.data);
354
+ default:
355
+ // FullTick and QuoteBBO use TradeTick/Quote dataType
356
+ // TickData (fullTick) via tickData field
357
+ if (pushData.tickData)
358
+ cb.onFullTick?.(pushData.tickData);
266
359
  break;
267
360
  }
268
361
  }
269
- /** 内部订阅方法 */
362
+ /** Internal subscribe method */
270
363
  doSubscribe(subject, symbols, account, market) {
271
- const req = { subject, symbols, account, market };
272
- const msg = createPushMessage(MessageType.Subscribe, subject, req);
273
- this.sendMessage(msg);
364
+ const dataType = subjectToDataType(subject);
365
+ const symbolsStr = symbols ? symbols.join(',') : undefined;
366
+ const req = buildSubscribeMessage(dataType, symbolsStr, account, market);
367
+ this.sendMessage(req);
274
368
  }
275
- /** 内部退订方法 */
369
+ /** Internal unsubscribe method */
276
370
  doUnsubscribe(subject, symbols) {
277
- const req = { subject, symbols };
278
- const msg = createPushMessage(MessageType.Unsubscribe, subject, req);
279
- this.sendMessage(msg);
371
+ const dataType = subjectToDataType(subject);
372
+ const symbolsStr = symbols ? symbols.join(',') : undefined;
373
+ const req = buildUnSubscribeMessage(dataType, symbolsStr);
374
+ this.sendMessage(req);
280
375
  }
281
- /** 添加订阅记录 */
376
+ /** Add subscription record */
282
377
  addSubscription(subject, symbols) {
283
378
  if (!this.subscriptions.has(subject)) {
284
379
  this.subscriptions.set(subject, new Set());
@@ -287,7 +382,7 @@ export class PushClient {
287
382
  for (const s of symbols)
288
383
  set.add(s);
289
384
  }
290
- /** 移除订阅记录 */
385
+ /** Remove subscription record */
291
386
  removeSubscription(subject, symbols) {
292
387
  if (!symbols) {
293
388
  this.subscriptions.delete(subject);
@@ -301,110 +396,110 @@ export class PushClient {
301
396
  this.subscriptions.delete(subject);
302
397
  }
303
398
  }
304
- // ===== 行情订阅/退订 =====
305
- /** 订阅行情 */
399
+ // ===== Market data subscribe/unsubscribe =====
400
+ /** Subscribe to quotes */
306
401
  subscribeQuote(symbols) {
307
402
  this.doSubscribe(SubjectType.Quote, symbols);
308
403
  this.addSubscription(SubjectType.Quote, symbols);
309
404
  }
310
- /** 退订行情 */
405
+ /** Unsubscribe from quotes */
311
406
  unsubscribeQuote(symbols) {
312
407
  this.doUnsubscribe(SubjectType.Quote, symbols);
313
408
  this.removeSubscription(SubjectType.Quote, symbols);
314
409
  }
315
- /** 订阅逐笔成交 */
410
+ /** Subscribe to trade ticks */
316
411
  subscribeTick(symbols) {
317
412
  this.doSubscribe(SubjectType.Tick, symbols);
318
413
  this.addSubscription(SubjectType.Tick, symbols);
319
414
  }
320
- /** 退订逐笔成交 */
415
+ /** Unsubscribe from trade ticks */
321
416
  unsubscribeTick(symbols) {
322
417
  this.doUnsubscribe(SubjectType.Tick, symbols);
323
418
  this.removeSubscription(SubjectType.Tick, symbols);
324
419
  }
325
- /** 订阅深度行情 */
420
+ /** Subscribe to depth data */
326
421
  subscribeDepth(symbols) {
327
422
  this.doSubscribe(SubjectType.Depth, symbols);
328
423
  this.addSubscription(SubjectType.Depth, symbols);
329
424
  }
330
- /** 退订深度行情 */
425
+ /** Unsubscribe from depth data */
331
426
  unsubscribeDepth(symbols) {
332
427
  this.doUnsubscribe(SubjectType.Depth, symbols);
333
428
  this.removeSubscription(SubjectType.Depth, symbols);
334
429
  }
335
- /** 订阅期权行情 */
430
+ /** Subscribe to option quotes */
336
431
  subscribeOption(symbols) {
337
432
  this.doSubscribe(SubjectType.Option, symbols);
338
433
  this.addSubscription(SubjectType.Option, symbols);
339
434
  }
340
- /** 退订期权行情 */
435
+ /** Unsubscribe from option quotes */
341
436
  unsubscribeOption(symbols) {
342
437
  this.doUnsubscribe(SubjectType.Option, symbols);
343
438
  this.removeSubscription(SubjectType.Option, symbols);
344
439
  }
345
- /** 订阅期货行情 */
440
+ /** Subscribe to futures quotes */
346
441
  subscribeFuture(symbols) {
347
442
  this.doSubscribe(SubjectType.Future, symbols);
348
443
  this.addSubscription(SubjectType.Future, symbols);
349
444
  }
350
- /** 退订期货行情 */
445
+ /** Unsubscribe from futures quotes */
351
446
  unsubscribeFuture(symbols) {
352
447
  this.doUnsubscribe(SubjectType.Future, symbols);
353
448
  this.removeSubscription(SubjectType.Future, symbols);
354
449
  }
355
- /** 订阅 K 线 */
450
+ /** Subscribe to kline data */
356
451
  subscribeKline(symbols) {
357
452
  this.doSubscribe(SubjectType.Kline, symbols);
358
453
  this.addSubscription(SubjectType.Kline, symbols);
359
454
  }
360
- /** 退订 K 线 */
455
+ /** Unsubscribe from kline data */
361
456
  unsubscribeKline(symbols) {
362
457
  this.doUnsubscribe(SubjectType.Kline, symbols);
363
458
  this.removeSubscription(SubjectType.Kline, symbols);
364
459
  }
365
- // ===== 账户推送订阅/退订 =====
366
- /** 订阅资产变动 */
460
+ // ===== Account push subscribe/unsubscribe =====
461
+ /** Subscribe to asset changes */
367
462
  subscribeAsset(account) {
368
463
  this.doSubscribe(SubjectType.Asset, undefined, account || this.config.account);
369
464
  this.accountSubs.add(SubjectType.Asset);
370
465
  }
371
- /** 退订资产变动 */
466
+ /** Unsubscribe from asset changes */
372
467
  unsubscribeAsset() {
373
468
  this.doUnsubscribe(SubjectType.Asset);
374
469
  this.accountSubs.delete(SubjectType.Asset);
375
470
  }
376
- /** 订阅持仓变动 */
471
+ /** Subscribe to position changes */
377
472
  subscribePosition(account) {
378
473
  this.doSubscribe(SubjectType.Position, undefined, account || this.config.account);
379
474
  this.accountSubs.add(SubjectType.Position);
380
475
  }
381
- /** 退订持仓变动 */
476
+ /** Unsubscribe from position changes */
382
477
  unsubscribePosition() {
383
478
  this.doUnsubscribe(SubjectType.Position);
384
479
  this.accountSubs.delete(SubjectType.Position);
385
480
  }
386
- /** 订阅订单状态 */
481
+ /** Subscribe to order status */
387
482
  subscribeOrder(account) {
388
483
  this.doSubscribe(SubjectType.Order, undefined, account || this.config.account);
389
484
  this.accountSubs.add(SubjectType.Order);
390
485
  }
391
- /** 退订订单状态 */
486
+ /** Unsubscribe from order status */
392
487
  unsubscribeOrder() {
393
488
  this.doUnsubscribe(SubjectType.Order);
394
489
  this.accountSubs.delete(SubjectType.Order);
395
490
  }
396
- /** 订阅成交明细 */
491
+ /** Subscribe to transaction details */
397
492
  subscribeTransaction(account) {
398
493
  this.doSubscribe(SubjectType.Transaction, undefined, account || this.config.account);
399
494
  this.accountSubs.add(SubjectType.Transaction);
400
495
  }
401
- /** 退订成交明细 */
496
+ /** Unsubscribe from transaction details */
402
497
  unsubscribeTransaction() {
403
498
  this.doUnsubscribe(SubjectType.Transaction);
404
499
  this.accountSubs.delete(SubjectType.Transaction);
405
500
  }
406
- // ===== 查询订阅状态 =====
407
- /** 获取当前行情订阅状态 */
501
+ // ===== Query subscription state =====
502
+ /** Get current market data subscriptions */
408
503
  getSubscriptions() {
409
504
  const result = new Map();
410
505
  for (const [subject, symbols] of this.subscriptions) {
@@ -412,7 +507,7 @@ export class PushClient {
412
507
  }
413
508
  return result;
414
509
  }
415
- /** 获取账户级别订阅状态 */
510
+ /** Get account-level subscriptions */
416
511
  getAccountSubscriptions() {
417
512
  return Array.from(this.accountSubs);
418
513
  }