@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.
- package/README.md +475 -104
- package/dist/cjs/client/api-request.js +16 -10
- package/dist/cjs/client/api-response.js +23 -3
- package/dist/cjs/client/case-convert.js +35 -0
- package/dist/cjs/client/http-client.js +46 -20
- package/dist/cjs/client/index.js +6 -2
- package/dist/cjs/config/client-config.js +130 -49
- package/dist/cjs/config/domain.js +21 -2
- package/dist/cjs/config/index.js +3 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/model/contract.js +1 -2
- package/dist/cjs/model/order-helpers.js +9 -9
- package/dist/cjs/model/order.js +5 -2
- package/dist/cjs/model/position.js +1 -2
- package/dist/cjs/model/quote.js +7 -0
- package/dist/cjs/model/trade.js +2 -0
- package/dist/cjs/push/index.js +6 -3
- package/dist/cjs/push/pb/AssetData.js +208 -0
- package/dist/cjs/push/pb/KlineData.js +184 -0
- package/dist/cjs/push/pb/OptionTopData.js +427 -0
- package/dist/cjs/push/pb/OrderStatusData.js +568 -0
- package/dist/cjs/push/pb/OrderTransactionData.js +256 -0
- package/dist/cjs/push/pb/PositionData.js +316 -0
- package/dist/cjs/push/pb/PushData.js +219 -0
- package/dist/cjs/push/pb/QuoteBBOData.js +160 -0
- package/dist/cjs/push/pb/QuoteBasicData.js +329 -0
- package/dist/cjs/push/pb/QuoteData.js +507 -0
- package/dist/cjs/push/pb/QuoteDepthData.js +220 -0
- package/dist/cjs/push/pb/Request.js +278 -0
- package/dist/cjs/push/pb/Response.js +97 -0
- package/dist/cjs/push/pb/SocketCommon.js +86 -0
- package/dist/cjs/push/pb/StockTopData.js +199 -0
- package/dist/cjs/push/pb/TickData.js +202 -0
- package/dist/cjs/push/pb/TradeTickData.js +308 -0
- package/dist/cjs/push/pb/index.js +49 -0
- package/dist/cjs/push/proto-message.js +129 -0
- package/dist/cjs/push/push-client.js +292 -164
- package/dist/cjs/push/push-message.js +4 -60
- package/dist/cjs/push/varint.js +76 -0
- package/dist/cjs/quote/index.js +3 -2
- package/dist/cjs/quote/quote-client.js +128 -94
- package/dist/cjs/signer/signer.js +10 -10
- package/dist/cjs/trade/trade-client.js +56 -62
- package/dist/esm/client/api-request.js +14 -8
- package/dist/esm/client/api-response.js +22 -3
- package/dist/esm/client/case-convert.js +31 -0
- package/dist/esm/client/http-client.js +47 -21
- package/dist/esm/client/index.js +3 -2
- package/dist/esm/config/client-config.js +131 -51
- package/dist/esm/config/domain.js +20 -2
- package/dist/esm/config/index.js +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/model/contract.js +1 -2
- package/dist/esm/model/order-helpers.js +9 -9
- package/dist/esm/model/order.js +5 -2
- package/dist/esm/model/position.js +1 -2
- package/dist/esm/model/quote.js +6 -0
- package/dist/esm/model/trade.js +1 -0
- package/dist/esm/push/index.js +4 -2
- package/dist/esm/push/pb/AssetData.js +205 -0
- package/dist/esm/push/pb/KlineData.js +181 -0
- package/dist/esm/push/pb/OptionTopData.js +424 -0
- package/dist/esm/push/pb/OrderStatusData.js +565 -0
- package/dist/esm/push/pb/OrderTransactionData.js +253 -0
- package/dist/esm/push/pb/PositionData.js +313 -0
- package/dist/esm/push/pb/PushData.js +216 -0
- package/dist/esm/push/pb/QuoteBBOData.js +157 -0
- package/dist/esm/push/pb/QuoteBasicData.js +326 -0
- package/dist/esm/push/pb/QuoteData.js +504 -0
- package/dist/esm/push/pb/QuoteDepthData.js +217 -0
- package/dist/esm/push/pb/Request.js +275 -0
- package/dist/esm/push/pb/Response.js +94 -0
- package/dist/esm/push/pb/SocketCommon.js +83 -0
- package/dist/esm/push/pb/StockTopData.js +196 -0
- package/dist/esm/push/pb/TickData.js +199 -0
- package/dist/esm/push/pb/TradeTickData.js +305 -0
- package/dist/esm/push/pb/index.js +25 -0
- package/dist/esm/push/proto-message.js +121 -0
- package/dist/esm/push/push-client.js +260 -165
- package/dist/esm/push/push-message.js +3 -56
- package/dist/esm/push/varint.js +72 -0
- package/dist/esm/quote/index.js +2 -2
- package/dist/esm/quote/quote-client.js +127 -94
- package/dist/esm/signer/signer.js +10 -10
- package/dist/esm/trade/trade-client.js +56 -62
- package/dist/types/client/api-request.d.ts +12 -11
- package/dist/types/client/api-response.d.ts +15 -7
- package/dist/types/client/case-convert.d.ts +16 -0
- package/dist/types/client/http-client.d.ts +26 -14
- package/dist/types/client/index.d.ts +3 -2
- package/dist/types/config/client-config.d.ts +29 -13
- package/dist/types/config/domain.d.ts +9 -0
- package/dist/types/config/index.d.ts +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/model/contract.d.ts +13 -29
- package/dist/types/model/order-helpers.d.ts +21 -20
- package/dist/types/model/order.d.ts +101 -55
- package/dist/types/model/position.d.ts +26 -24
- package/dist/types/model/quote.d.ts +311 -0
- package/dist/types/model/trade.d.ts +113 -0
- package/dist/types/push/callbacks.d.ts +32 -51
- package/dist/types/push/index.d.ts +5 -3
- package/dist/types/push/pb/AssetData.d.ts +47 -0
- package/dist/types/push/pb/KlineData.d.ts +43 -0
- package/dist/types/push/pb/OptionTopData.d.ts +76 -0
- package/dist/types/push/pb/OrderStatusData.d.ts +96 -0
- package/dist/types/push/pb/OrderTransactionData.d.ts +51 -0
- package/dist/types/push/pb/PositionData.d.ts +63 -0
- package/dist/types/push/pb/PushData.d.ts +46 -0
- package/dist/types/push/pb/QuoteBBOData.d.ts +35 -0
- package/dist/types/push/pb/QuoteBasicData.d.ts +66 -0
- package/dist/types/push/pb/QuoteData.d.ts +94 -0
- package/dist/types/push/pb/QuoteDepthData.d.ts +37 -0
- package/dist/types/push/pb/Request.d.ts +44 -0
- package/dist/types/push/pb/Response.d.ts +30 -0
- package/dist/types/push/pb/SocketCommon.d.ts +64 -0
- package/dist/types/push/pb/StockTopData.d.ts +37 -0
- package/dist/types/push/pb/TickData.d.ts +44 -0
- package/dist/types/push/pb/TradeTickData.d.ts +53 -0
- package/dist/types/push/pb/index.d.ts +39 -0
- package/dist/types/push/proto-message.d.ts +33 -0
- package/dist/types/push/push-client.d.ts +69 -68
- package/dist/types/push/push-message.d.ts +3 -147
- package/dist/types/push/varint.d.ts +23 -0
- package/dist/types/quote/index.d.ts +2 -2
- package/dist/types/quote/quote-client.d.ts +41 -47
- package/dist/types/signer/signer.d.ts +6 -6
- package/dist/types/trade/trade-client.d.ts +34 -38
- package/package.json +11 -6
|
@@ -1,19 +1,78 @@
|
|
|
1
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.PushClient = exports.ConnectionState = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* PushClient - TCP + TLS push client (Protobuf protocol)
|
|
39
|
+
*
|
|
40
|
+
* Connects to the push server via raw TCP + TLS to receive real-time
|
|
41
|
+
* market data and account push notifications.
|
|
42
|
+
* Uses varint32 length-prefixed + Protobuf binary frame format,
|
|
43
|
+
* aligned with the Java SDK's Netty + Protobuf implementation.
|
|
44
|
+
* Supports connection authentication, subscribe/unsubscribe, callbacks,
|
|
45
|
+
* heartbeat keep-alive, and automatic reconnection.
|
|
46
|
+
*/
|
|
47
|
+
const tls = __importStar(require("tls"));
|
|
4
48
|
const signer_1 = require("../signer/signer");
|
|
5
49
|
const push_message_1 = require("./push-message");
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
50
|
+
const Request_1 = require("./pb/Request");
|
|
51
|
+
const Response_1 = require("./pb/Response");
|
|
52
|
+
const SocketCommon_1 = require("./pb/SocketCommon");
|
|
53
|
+
const varint_1 = require("./varint");
|
|
54
|
+
const proto_message_1 = require("./proto-message");
|
|
55
|
+
/** Default push server host */
|
|
56
|
+
const DEFAULT_PUSH_HOST = 'openapi.tigerfintech.com';
|
|
57
|
+
/** Default push server port */
|
|
58
|
+
const DEFAULT_PUSH_PORT = 9883;
|
|
59
|
+
/** Default heartbeat interval (ms) */
|
|
9
60
|
const DEFAULT_HEARTBEAT_INTERVAL = 10000;
|
|
10
|
-
/**
|
|
61
|
+
/** Default reconnect interval (ms) */
|
|
11
62
|
const DEFAULT_RECONNECT_INTERVAL = 5000;
|
|
12
|
-
/**
|
|
63
|
+
/** Max reconnect interval (ms) */
|
|
13
64
|
const MAX_RECONNECT_INTERVAL = 60000;
|
|
14
|
-
/**
|
|
65
|
+
/** Default connect timeout (ms) */
|
|
15
66
|
const DEFAULT_CONNECT_TIMEOUT = 30000;
|
|
16
|
-
/**
|
|
67
|
+
/** SDK version identifier */
|
|
68
|
+
const SDK_VERSION = 'typescript/0.1.0';
|
|
69
|
+
/** Protocol version */
|
|
70
|
+
const ACCEPT_VERSION = '1.0';
|
|
71
|
+
/** Default send heartbeat interval (ms) */
|
|
72
|
+
const DEFAULT_SEND_INTERVAL = 10000;
|
|
73
|
+
/** Default receive heartbeat interval (ms) */
|
|
74
|
+
const DEFAULT_RECEIVE_INTERVAL = 10000;
|
|
75
|
+
/** Connection state */
|
|
17
76
|
var ConnectionState;
|
|
18
77
|
(function (ConnectionState) {
|
|
19
78
|
ConnectionState[ConnectionState["Disconnected"] = 0] = "Disconnected";
|
|
@@ -21,151 +80,220 @@ var ConnectionState;
|
|
|
21
80
|
ConnectionState[ConnectionState["Connected"] = 2] = "Connected";
|
|
22
81
|
})(ConnectionState || (exports.ConnectionState = ConnectionState = {}));
|
|
23
82
|
/**
|
|
24
|
-
* PushClient
|
|
83
|
+
* PushClient - TCP + TLS push client (Protobuf protocol)
|
|
25
84
|
*/
|
|
26
85
|
class PushClient {
|
|
27
86
|
constructor(config, options) {
|
|
28
|
-
this.
|
|
87
|
+
this.socket = null;
|
|
29
88
|
this._state = ConnectionState.Disconnected;
|
|
30
89
|
this.callbacks = {};
|
|
31
|
-
/**
|
|
90
|
+
/** Subscription state: subject -> Set<symbol> */
|
|
32
91
|
this.subscriptions = new Map();
|
|
33
|
-
/**
|
|
92
|
+
/** Account-level subscriptions */
|
|
34
93
|
this.accountSubs = new Set();
|
|
35
94
|
this.heartbeatTimer = null;
|
|
36
95
|
this.reconnectTimer = null;
|
|
37
96
|
this.stopped = false;
|
|
38
|
-
/**
|
|
39
|
-
this.
|
|
97
|
+
/** TCP stream receive buffer */
|
|
98
|
+
this.recvBuffer = Buffer.alloc(0);
|
|
99
|
+
/** Injectable TLS socket factory (for testing) */
|
|
100
|
+
this.socketFactory = null;
|
|
40
101
|
this.config = config;
|
|
41
|
-
this.
|
|
102
|
+
this.pushHost = options?.pushHost ?? DEFAULT_PUSH_HOST;
|
|
103
|
+
this.pushPort = options?.pushPort ?? DEFAULT_PUSH_PORT;
|
|
42
104
|
this.heartbeatInterval = options?.heartbeatInterval ?? DEFAULT_HEARTBEAT_INTERVAL;
|
|
43
105
|
this.reconnectInterval = options?.reconnectInterval ?? DEFAULT_RECONNECT_INTERVAL;
|
|
44
106
|
this.autoReconnect = options?.autoReconnect ?? true;
|
|
45
107
|
this.connectTimeout = options?.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT;
|
|
108
|
+
this.useFullTick = options?.useFullTick ?? false;
|
|
46
109
|
}
|
|
47
|
-
/**
|
|
110
|
+
/** Get current connection state */
|
|
48
111
|
get state() {
|
|
49
112
|
return this._state;
|
|
50
113
|
}
|
|
51
|
-
/**
|
|
114
|
+
/** Set callback functions */
|
|
52
115
|
setCallbacks(cb) {
|
|
53
116
|
this.callbacks = cb;
|
|
54
117
|
}
|
|
55
|
-
/**
|
|
118
|
+
/** Connect to the push server and authenticate */
|
|
56
119
|
connect() {
|
|
57
120
|
return new Promise((resolve, reject) => {
|
|
58
121
|
if (this._state !== ConnectionState.Disconnected) {
|
|
59
|
-
reject(new Error('
|
|
122
|
+
reject(new Error('Client is already connected or connecting'));
|
|
60
123
|
return;
|
|
61
124
|
}
|
|
62
125
|
this._state = ConnectionState.Connecting;
|
|
63
126
|
this.stopped = false;
|
|
64
|
-
|
|
65
|
-
this.
|
|
127
|
+
this.recvBuffer = Buffer.alloc(0);
|
|
128
|
+
const socket = this.createSocket(this.pushHost, this.pushPort);
|
|
129
|
+
this.socket = socket;
|
|
130
|
+
let settled = false;
|
|
66
131
|
const timeout = setTimeout(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
132
|
+
if (!settled) {
|
|
133
|
+
settled = true;
|
|
134
|
+
socket.destroy();
|
|
135
|
+
this._state = ConnectionState.Disconnected;
|
|
136
|
+
this.socket = null;
|
|
137
|
+
reject(new Error('Connect timeout'));
|
|
138
|
+
}
|
|
71
139
|
}, this.connectTimeout);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
140
|
+
// Resolve once we receive CONNECTED response from server
|
|
141
|
+
const onConnected = () => {
|
|
142
|
+
if (!settled) {
|
|
143
|
+
settled = true;
|
|
144
|
+
clearTimeout(timeout);
|
|
77
145
|
this._state = ConnectionState.Connected;
|
|
78
146
|
this.startHeartbeat();
|
|
79
147
|
this.callbacks.onConnect?.();
|
|
80
148
|
resolve();
|
|
81
149
|
}
|
|
150
|
+
};
|
|
151
|
+
socket.on('connect', () => {
|
|
152
|
+
// TLS handshake complete, send authentication message
|
|
153
|
+
try {
|
|
154
|
+
this.authenticate();
|
|
155
|
+
}
|
|
82
156
|
catch (err) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
157
|
+
if (!settled) {
|
|
158
|
+
settled = true;
|
|
159
|
+
clearTimeout(timeout);
|
|
160
|
+
socket.destroy();
|
|
161
|
+
this._state = ConnectionState.Disconnected;
|
|
162
|
+
this.socket = null;
|
|
163
|
+
reject(err);
|
|
164
|
+
}
|
|
87
165
|
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
};
|
|
92
|
-
|
|
166
|
+
});
|
|
167
|
+
socket.on('data', (chunk) => {
|
|
168
|
+
this.handleData(chunk, onConnected);
|
|
169
|
+
});
|
|
170
|
+
socket.on('close', () => {
|
|
93
171
|
if (this.stopped)
|
|
94
172
|
return;
|
|
95
173
|
this.stopHeartbeat();
|
|
96
174
|
const wasConnected = this._state === ConnectionState.Connected;
|
|
97
175
|
this._state = ConnectionState.Disconnected;
|
|
98
|
-
this.
|
|
176
|
+
this.socket = null;
|
|
99
177
|
if (wasConnected && this.autoReconnect && !this.stopped) {
|
|
100
178
|
this.scheduleReconnect();
|
|
101
179
|
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
if (
|
|
180
|
+
});
|
|
181
|
+
socket.on('error', (err) => {
|
|
182
|
+
if (!settled) {
|
|
183
|
+
settled = true;
|
|
105
184
|
clearTimeout(timeout);
|
|
106
185
|
this._state = ConnectionState.Disconnected;
|
|
107
|
-
this.
|
|
108
|
-
reject(new Error(
|
|
186
|
+
this.socket = null;
|
|
187
|
+
reject(new Error(`TLS connection failed: ${err.message}`));
|
|
109
188
|
}
|
|
110
189
|
else {
|
|
111
|
-
this.callbacks.onError?.(new Error(
|
|
190
|
+
this.callbacks.onError?.(new Error(`TLS error: ${err.message}`));
|
|
112
191
|
}
|
|
113
|
-
};
|
|
192
|
+
});
|
|
114
193
|
});
|
|
115
194
|
}
|
|
116
|
-
/**
|
|
195
|
+
/** Disconnect from the push server */
|
|
117
196
|
disconnect() {
|
|
118
197
|
this.stopped = true;
|
|
119
198
|
this.stopHeartbeat();
|
|
120
199
|
this.clearReconnectTimer();
|
|
121
|
-
if (this.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
200
|
+
if (this.socket) {
|
|
201
|
+
// Send DISCONNECT message before closing
|
|
202
|
+
try {
|
|
203
|
+
const req = (0, proto_message_1.buildDisconnectMessage)();
|
|
204
|
+
this.sendMessage(req);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Ignore send failure, continue closing
|
|
208
|
+
}
|
|
209
|
+
this.socket.destroy();
|
|
210
|
+
this.socket = null;
|
|
127
211
|
}
|
|
128
212
|
this._state = ConnectionState.Disconnected;
|
|
213
|
+
this.recvBuffer = Buffer.alloc(0);
|
|
129
214
|
this.callbacks.onDisconnect?.();
|
|
130
215
|
}
|
|
131
|
-
/**
|
|
216
|
+
/** Send authentication message */
|
|
132
217
|
authenticate() {
|
|
133
|
-
|
|
218
|
+
// Sign content is the tigerId string itself (aligned with Java SDK)
|
|
134
219
|
const sign = (0, signer_1.signWithRSA)(this.config.privateKey, this.config.tigerId);
|
|
135
|
-
const req =
|
|
136
|
-
|
|
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);
|
|
220
|
+
const req = (0, proto_message_1.buildConnectMessage)(this.config.tigerId, sign, SDK_VERSION, ACCEPT_VERSION, DEFAULT_SEND_INTERVAL, DEFAULT_RECEIVE_INTERVAL, this.useFullTick);
|
|
221
|
+
this.sendMessage(req);
|
|
143
222
|
}
|
|
144
|
-
/**
|
|
223
|
+
/** Send a Protobuf Request message (varint32 length prefix + binary) */
|
|
145
224
|
sendMessage(msg) {
|
|
146
|
-
if (!this.
|
|
147
|
-
throw new Error('
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
225
|
+
if (!this.socket)
|
|
226
|
+
throw new Error('TLS connection not established');
|
|
227
|
+
const encoded = Request_1.Request.encode(msg).finish();
|
|
228
|
+
const framed = (0, varint_1.encodeVarint32)(encoded);
|
|
229
|
+
this.socket.write(framed);
|
|
230
|
+
}
|
|
231
|
+
/** Create a TLS socket instance */
|
|
232
|
+
createSocket(host, port) {
|
|
233
|
+
if (this.socketFactory)
|
|
234
|
+
return this.socketFactory(host, port);
|
|
235
|
+
return tls.connect({ host, port, rejectUnauthorized: false });
|
|
236
|
+
}
|
|
237
|
+
/** Handle incoming TCP data: buffer + decode varint32 frames */
|
|
238
|
+
handleData(chunk, onConnected) {
|
|
239
|
+
this.recvBuffer = Buffer.concat([this.recvBuffer, chunk]);
|
|
240
|
+
while (this.recvBuffer.length > 0) {
|
|
241
|
+
const frame = (0, varint_1.decodeVarint32)(new Uint8Array(this.recvBuffer));
|
|
242
|
+
if (!frame)
|
|
243
|
+
break; // Incomplete frame, wait for more data
|
|
244
|
+
this.recvBuffer = Buffer.from(frame.remaining);
|
|
245
|
+
// Deserialize Protobuf Response
|
|
246
|
+
let response;
|
|
247
|
+
try {
|
|
248
|
+
response = Response_1.Response.decode(frame.message);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
this.callbacks.onError?.(new Error('Protobuf deserialization failed'));
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
this.handleResponse(response, onConnected);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/** Handle a decoded Response message */
|
|
258
|
+
handleResponse(response, onConnected) {
|
|
259
|
+
const cb = this.callbacks;
|
|
260
|
+
switch (response.command) {
|
|
261
|
+
case SocketCommon_1.SocketCommon_Command.CONNECTED:
|
|
262
|
+
// Server confirmed authentication
|
|
263
|
+
onConnected?.();
|
|
264
|
+
break;
|
|
265
|
+
case SocketCommon_1.SocketCommon_Command.HEARTBEAT:
|
|
266
|
+
// Heartbeat response, ignore
|
|
267
|
+
break;
|
|
268
|
+
case SocketCommon_1.SocketCommon_Command.MESSAGE:
|
|
269
|
+
if (response.body) {
|
|
270
|
+
this.dispatchPushData(response.body);
|
|
271
|
+
}
|
|
272
|
+
break;
|
|
273
|
+
case SocketCommon_1.SocketCommon_Command.ERROR:
|
|
274
|
+
cb.onError?.(new Error(`Server error: ${response.msg ?? 'unknown error'}`));
|
|
275
|
+
// Check for kickout
|
|
276
|
+
if (response.msg && response.msg.toLowerCase().includes('kickout')) {
|
|
277
|
+
cb.onKickout?.(response.msg);
|
|
278
|
+
}
|
|
279
|
+
break;
|
|
280
|
+
case SocketCommon_1.SocketCommon_Command.DISCONNECT:
|
|
281
|
+
cb.onDisconnect?.();
|
|
282
|
+
break;
|
|
283
|
+
default:
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/** Heartbeat keep-alive */
|
|
160
288
|
startHeartbeat() {
|
|
161
289
|
this.stopHeartbeat();
|
|
162
290
|
this.heartbeatTimer = setInterval(() => {
|
|
163
291
|
try {
|
|
164
|
-
const
|
|
165
|
-
this.sendMessage(
|
|
292
|
+
const req = (0, proto_message_1.buildHeartBeatMessage)();
|
|
293
|
+
this.sendMessage(req);
|
|
166
294
|
}
|
|
167
295
|
catch {
|
|
168
|
-
//
|
|
296
|
+
// Heartbeat send failed, connection may be broken
|
|
169
297
|
}
|
|
170
298
|
}, this.heartbeatInterval);
|
|
171
299
|
}
|
|
@@ -175,7 +303,7 @@ class PushClient {
|
|
|
175
303
|
this.heartbeatTimer = null;
|
|
176
304
|
}
|
|
177
305
|
}
|
|
178
|
-
/**
|
|
306
|
+
/** Auto reconnect with exponential backoff */
|
|
179
307
|
scheduleReconnect() {
|
|
180
308
|
let interval = this.reconnectInterval;
|
|
181
309
|
const attempt = () => {
|
|
@@ -198,7 +326,7 @@ class PushClient {
|
|
|
198
326
|
this.reconnectTimer = null;
|
|
199
327
|
}
|
|
200
328
|
}
|
|
201
|
-
/**
|
|
329
|
+
/** Resubscribe after reconnection */
|
|
202
330
|
resubscribe() {
|
|
203
331
|
for (const [subject, symbols] of this.subscriptions) {
|
|
204
332
|
this.doSubscribe(subject, Array.from(symbols));
|
|
@@ -207,81 +335,81 @@ class PushClient {
|
|
|
207
335
|
this.doSubscribe(subject, undefined, this.config.account);
|
|
208
336
|
}
|
|
209
337
|
}
|
|
210
|
-
/**
|
|
211
|
-
|
|
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
|
-
}
|
|
338
|
+
/** Dispatch push data to the appropriate callback based on dataType */
|
|
339
|
+
dispatchPushData(pushData) {
|
|
220
340
|
const cb = this.callbacks;
|
|
221
|
-
switch (
|
|
222
|
-
case
|
|
223
|
-
|
|
224
|
-
|
|
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);
|
|
341
|
+
switch (pushData.dataType) {
|
|
342
|
+
case SocketCommon_1.SocketCommon_DataType.Quote:
|
|
343
|
+
if (pushData.quoteData)
|
|
344
|
+
cb.onQuote?.(pushData.quoteData);
|
|
233
345
|
break;
|
|
234
|
-
case
|
|
235
|
-
|
|
346
|
+
case SocketCommon_1.SocketCommon_DataType.Option:
|
|
347
|
+
if (pushData.quoteData)
|
|
348
|
+
cb.onOption?.(pushData.quoteData);
|
|
236
349
|
break;
|
|
237
|
-
case
|
|
238
|
-
|
|
350
|
+
case SocketCommon_1.SocketCommon_DataType.Future:
|
|
351
|
+
if (pushData.quoteData)
|
|
352
|
+
cb.onFuture?.(pushData.quoteData);
|
|
239
353
|
break;
|
|
240
|
-
case
|
|
241
|
-
|
|
354
|
+
case SocketCommon_1.SocketCommon_DataType.QuoteDepth:
|
|
355
|
+
if (pushData.quoteDepthData)
|
|
356
|
+
cb.onDepth?.(pushData.quoteDepthData);
|
|
242
357
|
break;
|
|
243
|
-
case
|
|
244
|
-
|
|
358
|
+
case SocketCommon_1.SocketCommon_DataType.TradeTick:
|
|
359
|
+
if (pushData.tradeTickData)
|
|
360
|
+
cb.onTick?.(pushData.tradeTickData);
|
|
245
361
|
break;
|
|
246
|
-
case
|
|
247
|
-
|
|
362
|
+
case SocketCommon_1.SocketCommon_DataType.Asset:
|
|
363
|
+
if (pushData.assetData)
|
|
364
|
+
cb.onAsset?.(pushData.assetData);
|
|
248
365
|
break;
|
|
249
|
-
case
|
|
250
|
-
|
|
366
|
+
case SocketCommon_1.SocketCommon_DataType.Position:
|
|
367
|
+
if (pushData.positionData)
|
|
368
|
+
cb.onPosition?.(pushData.positionData);
|
|
251
369
|
break;
|
|
252
|
-
case
|
|
253
|
-
|
|
370
|
+
case SocketCommon_1.SocketCommon_DataType.OrderStatus:
|
|
371
|
+
if (pushData.orderStatusData)
|
|
372
|
+
cb.onOrder?.(pushData.orderStatusData);
|
|
254
373
|
break;
|
|
255
|
-
case
|
|
256
|
-
|
|
374
|
+
case SocketCommon_1.SocketCommon_DataType.OrderTransaction:
|
|
375
|
+
if (pushData.orderTransactionData)
|
|
376
|
+
cb.onTransaction?.(pushData.orderTransactionData);
|
|
257
377
|
break;
|
|
258
|
-
case
|
|
259
|
-
|
|
378
|
+
case SocketCommon_1.SocketCommon_DataType.StockTop:
|
|
379
|
+
if (pushData.stockTopData)
|
|
380
|
+
cb.onStockTop?.(pushData.stockTopData);
|
|
260
381
|
break;
|
|
261
|
-
case
|
|
262
|
-
|
|
382
|
+
case SocketCommon_1.SocketCommon_DataType.OptionTop:
|
|
383
|
+
if (pushData.optionTopData)
|
|
384
|
+
cb.onOptionTop?.(pushData.optionTopData);
|
|
263
385
|
break;
|
|
264
|
-
case
|
|
265
|
-
|
|
386
|
+
case SocketCommon_1.SocketCommon_DataType.Kline:
|
|
387
|
+
if (pushData.klineData)
|
|
388
|
+
cb.onKline?.(pushData.klineData);
|
|
266
389
|
break;
|
|
267
|
-
|
|
268
|
-
|
|
390
|
+
default:
|
|
391
|
+
// FullTick and QuoteBBO use TradeTick/Quote dataType
|
|
392
|
+
// TickData (fullTick) via tickData field
|
|
393
|
+
if (pushData.tickData)
|
|
394
|
+
cb.onFullTick?.(pushData.tickData);
|
|
269
395
|
break;
|
|
270
396
|
}
|
|
271
397
|
}
|
|
272
|
-
/**
|
|
398
|
+
/** Internal subscribe method */
|
|
273
399
|
doSubscribe(subject, symbols, account, market) {
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
|
|
400
|
+
const dataType = (0, proto_message_1.subjectToDataType)(subject);
|
|
401
|
+
const symbolsStr = symbols ? symbols.join(',') : undefined;
|
|
402
|
+
const req = (0, proto_message_1.buildSubscribeMessage)(dataType, symbolsStr, account, market);
|
|
403
|
+
this.sendMessage(req);
|
|
277
404
|
}
|
|
278
|
-
/**
|
|
405
|
+
/** Internal unsubscribe method */
|
|
279
406
|
doUnsubscribe(subject, symbols) {
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
|
|
407
|
+
const dataType = (0, proto_message_1.subjectToDataType)(subject);
|
|
408
|
+
const symbolsStr = symbols ? symbols.join(',') : undefined;
|
|
409
|
+
const req = (0, proto_message_1.buildUnSubscribeMessage)(dataType, symbolsStr);
|
|
410
|
+
this.sendMessage(req);
|
|
283
411
|
}
|
|
284
|
-
/**
|
|
412
|
+
/** Add subscription record */
|
|
285
413
|
addSubscription(subject, symbols) {
|
|
286
414
|
if (!this.subscriptions.has(subject)) {
|
|
287
415
|
this.subscriptions.set(subject, new Set());
|
|
@@ -290,7 +418,7 @@ class PushClient {
|
|
|
290
418
|
for (const s of symbols)
|
|
291
419
|
set.add(s);
|
|
292
420
|
}
|
|
293
|
-
/**
|
|
421
|
+
/** Remove subscription record */
|
|
294
422
|
removeSubscription(subject, symbols) {
|
|
295
423
|
if (!symbols) {
|
|
296
424
|
this.subscriptions.delete(subject);
|
|
@@ -304,110 +432,110 @@ class PushClient {
|
|
|
304
432
|
this.subscriptions.delete(subject);
|
|
305
433
|
}
|
|
306
434
|
}
|
|
307
|
-
// =====
|
|
308
|
-
/**
|
|
435
|
+
// ===== Market data subscribe/unsubscribe =====
|
|
436
|
+
/** Subscribe to quotes */
|
|
309
437
|
subscribeQuote(symbols) {
|
|
310
438
|
this.doSubscribe(push_message_1.SubjectType.Quote, symbols);
|
|
311
439
|
this.addSubscription(push_message_1.SubjectType.Quote, symbols);
|
|
312
440
|
}
|
|
313
|
-
/**
|
|
441
|
+
/** Unsubscribe from quotes */
|
|
314
442
|
unsubscribeQuote(symbols) {
|
|
315
443
|
this.doUnsubscribe(push_message_1.SubjectType.Quote, symbols);
|
|
316
444
|
this.removeSubscription(push_message_1.SubjectType.Quote, symbols);
|
|
317
445
|
}
|
|
318
|
-
/**
|
|
446
|
+
/** Subscribe to trade ticks */
|
|
319
447
|
subscribeTick(symbols) {
|
|
320
448
|
this.doSubscribe(push_message_1.SubjectType.Tick, symbols);
|
|
321
449
|
this.addSubscription(push_message_1.SubjectType.Tick, symbols);
|
|
322
450
|
}
|
|
323
|
-
/**
|
|
451
|
+
/** Unsubscribe from trade ticks */
|
|
324
452
|
unsubscribeTick(symbols) {
|
|
325
453
|
this.doUnsubscribe(push_message_1.SubjectType.Tick, symbols);
|
|
326
454
|
this.removeSubscription(push_message_1.SubjectType.Tick, symbols);
|
|
327
455
|
}
|
|
328
|
-
/**
|
|
456
|
+
/** Subscribe to depth data */
|
|
329
457
|
subscribeDepth(symbols) {
|
|
330
458
|
this.doSubscribe(push_message_1.SubjectType.Depth, symbols);
|
|
331
459
|
this.addSubscription(push_message_1.SubjectType.Depth, symbols);
|
|
332
460
|
}
|
|
333
|
-
/**
|
|
461
|
+
/** Unsubscribe from depth data */
|
|
334
462
|
unsubscribeDepth(symbols) {
|
|
335
463
|
this.doUnsubscribe(push_message_1.SubjectType.Depth, symbols);
|
|
336
464
|
this.removeSubscription(push_message_1.SubjectType.Depth, symbols);
|
|
337
465
|
}
|
|
338
|
-
/**
|
|
466
|
+
/** Subscribe to option quotes */
|
|
339
467
|
subscribeOption(symbols) {
|
|
340
468
|
this.doSubscribe(push_message_1.SubjectType.Option, symbols);
|
|
341
469
|
this.addSubscription(push_message_1.SubjectType.Option, symbols);
|
|
342
470
|
}
|
|
343
|
-
/**
|
|
471
|
+
/** Unsubscribe from option quotes */
|
|
344
472
|
unsubscribeOption(symbols) {
|
|
345
473
|
this.doUnsubscribe(push_message_1.SubjectType.Option, symbols);
|
|
346
474
|
this.removeSubscription(push_message_1.SubjectType.Option, symbols);
|
|
347
475
|
}
|
|
348
|
-
/**
|
|
476
|
+
/** Subscribe to futures quotes */
|
|
349
477
|
subscribeFuture(symbols) {
|
|
350
478
|
this.doSubscribe(push_message_1.SubjectType.Future, symbols);
|
|
351
479
|
this.addSubscription(push_message_1.SubjectType.Future, symbols);
|
|
352
480
|
}
|
|
353
|
-
/**
|
|
481
|
+
/** Unsubscribe from futures quotes */
|
|
354
482
|
unsubscribeFuture(symbols) {
|
|
355
483
|
this.doUnsubscribe(push_message_1.SubjectType.Future, symbols);
|
|
356
484
|
this.removeSubscription(push_message_1.SubjectType.Future, symbols);
|
|
357
485
|
}
|
|
358
|
-
/**
|
|
486
|
+
/** Subscribe to kline data */
|
|
359
487
|
subscribeKline(symbols) {
|
|
360
488
|
this.doSubscribe(push_message_1.SubjectType.Kline, symbols);
|
|
361
489
|
this.addSubscription(push_message_1.SubjectType.Kline, symbols);
|
|
362
490
|
}
|
|
363
|
-
/**
|
|
491
|
+
/** Unsubscribe from kline data */
|
|
364
492
|
unsubscribeKline(symbols) {
|
|
365
493
|
this.doUnsubscribe(push_message_1.SubjectType.Kline, symbols);
|
|
366
494
|
this.removeSubscription(push_message_1.SubjectType.Kline, symbols);
|
|
367
495
|
}
|
|
368
|
-
// =====
|
|
369
|
-
/**
|
|
496
|
+
// ===== Account push subscribe/unsubscribe =====
|
|
497
|
+
/** Subscribe to asset changes */
|
|
370
498
|
subscribeAsset(account) {
|
|
371
499
|
this.doSubscribe(push_message_1.SubjectType.Asset, undefined, account || this.config.account);
|
|
372
500
|
this.accountSubs.add(push_message_1.SubjectType.Asset);
|
|
373
501
|
}
|
|
374
|
-
/**
|
|
502
|
+
/** Unsubscribe from asset changes */
|
|
375
503
|
unsubscribeAsset() {
|
|
376
504
|
this.doUnsubscribe(push_message_1.SubjectType.Asset);
|
|
377
505
|
this.accountSubs.delete(push_message_1.SubjectType.Asset);
|
|
378
506
|
}
|
|
379
|
-
/**
|
|
507
|
+
/** Subscribe to position changes */
|
|
380
508
|
subscribePosition(account) {
|
|
381
509
|
this.doSubscribe(push_message_1.SubjectType.Position, undefined, account || this.config.account);
|
|
382
510
|
this.accountSubs.add(push_message_1.SubjectType.Position);
|
|
383
511
|
}
|
|
384
|
-
/**
|
|
512
|
+
/** Unsubscribe from position changes */
|
|
385
513
|
unsubscribePosition() {
|
|
386
514
|
this.doUnsubscribe(push_message_1.SubjectType.Position);
|
|
387
515
|
this.accountSubs.delete(push_message_1.SubjectType.Position);
|
|
388
516
|
}
|
|
389
|
-
/**
|
|
517
|
+
/** Subscribe to order status */
|
|
390
518
|
subscribeOrder(account) {
|
|
391
519
|
this.doSubscribe(push_message_1.SubjectType.Order, undefined, account || this.config.account);
|
|
392
520
|
this.accountSubs.add(push_message_1.SubjectType.Order);
|
|
393
521
|
}
|
|
394
|
-
/**
|
|
522
|
+
/** Unsubscribe from order status */
|
|
395
523
|
unsubscribeOrder() {
|
|
396
524
|
this.doUnsubscribe(push_message_1.SubjectType.Order);
|
|
397
525
|
this.accountSubs.delete(push_message_1.SubjectType.Order);
|
|
398
526
|
}
|
|
399
|
-
/**
|
|
527
|
+
/** Subscribe to transaction details */
|
|
400
528
|
subscribeTransaction(account) {
|
|
401
529
|
this.doSubscribe(push_message_1.SubjectType.Transaction, undefined, account || this.config.account);
|
|
402
530
|
this.accountSubs.add(push_message_1.SubjectType.Transaction);
|
|
403
531
|
}
|
|
404
|
-
/**
|
|
532
|
+
/** Unsubscribe from transaction details */
|
|
405
533
|
unsubscribeTransaction() {
|
|
406
534
|
this.doUnsubscribe(push_message_1.SubjectType.Transaction);
|
|
407
535
|
this.accountSubs.delete(push_message_1.SubjectType.Transaction);
|
|
408
536
|
}
|
|
409
|
-
// =====
|
|
410
|
-
/**
|
|
537
|
+
// ===== Query subscription state =====
|
|
538
|
+
/** Get current market data subscriptions */
|
|
411
539
|
getSubscriptions() {
|
|
412
540
|
const result = new Map();
|
|
413
541
|
for (const [subject, symbols] of this.subscriptions) {
|
|
@@ -415,7 +543,7 @@ class PushClient {
|
|
|
415
543
|
}
|
|
416
544
|
return result;
|
|
417
545
|
}
|
|
418
|
-
/**
|
|
546
|
+
/** Get account-level subscriptions */
|
|
419
547
|
getAccountSubscriptions() {
|
|
420
548
|
return Array.from(this.accountSubs);
|
|
421
549
|
}
|