hedgequantx 2.6.163 → 2.7.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 +15 -88
- package/bin/cli.js +0 -11
- package/dist/lib/api.jsc +0 -0
- package/dist/lib/api2.jsc +0 -0
- package/dist/lib/core.jsc +0 -0
- package/dist/lib/core2.jsc +0 -0
- package/dist/lib/data.js +1 -1
- package/dist/lib/data.jsc +0 -0
- package/dist/lib/data2.jsc +0 -0
- package/dist/lib/decoder.jsc +0 -0
- package/dist/lib/m/mod1.jsc +0 -0
- package/dist/lib/m/mod2.jsc +0 -0
- package/dist/lib/n/r1.jsc +0 -0
- package/dist/lib/n/r2.jsc +0 -0
- package/dist/lib/n/r3.jsc +0 -0
- package/dist/lib/n/r4.jsc +0 -0
- package/dist/lib/n/r5.jsc +0 -0
- package/dist/lib/n/r6.jsc +0 -0
- package/dist/lib/n/r7.jsc +0 -0
- package/dist/lib/o/util1.jsc +0 -0
- package/dist/lib/o/util2.jsc +0 -0
- package/package.json +6 -3
- package/src/app.js +40 -162
- package/src/config/constants.js +31 -33
- package/src/config/propfirms.js +13 -217
- package/src/config/settings.js +0 -43
- package/src/lib/api.js +198 -0
- package/src/lib/api2.js +353 -0
- package/src/lib/core.js +539 -0
- package/src/lib/core2.js +341 -0
- package/src/lib/data.js +555 -0
- package/src/lib/data2.js +492 -0
- package/src/lib/decoder.js +599 -0
- package/src/lib/m/s1.js +804 -0
- package/src/lib/m/s2.js +34 -0
- package/src/lib/n/r1.js +454 -0
- package/src/lib/n/r2.js +514 -0
- package/src/lib/n/r3.js +631 -0
- package/src/lib/n/r4.js +401 -0
- package/src/lib/n/r5.js +335 -0
- package/src/lib/n/r6.js +425 -0
- package/src/lib/n/r7.js +530 -0
- package/src/lib/o/l1.js +44 -0
- package/src/lib/o/l2.js +427 -0
- package/src/lib/python-bridge.js +206 -0
- package/src/menus/connect.js +14 -176
- package/src/menus/dashboard.js +65 -110
- package/src/pages/accounts.js +18 -18
- package/src/pages/algo/copy-trading.js +210 -240
- package/src/pages/algo/index.js +41 -104
- package/src/pages/algo/one-account.js +386 -33
- package/src/pages/algo/ui.js +312 -151
- package/src/pages/orders.js +3 -3
- package/src/pages/positions.js +3 -3
- package/src/pages/stats/chart.js +74 -0
- package/src/pages/stats/display.js +228 -0
- package/src/pages/stats/index.js +236 -0
- package/src/pages/stats/metrics.js +213 -0
- package/src/pages/user.js +6 -6
- package/src/services/hqx-server/constants.js +55 -0
- package/src/services/hqx-server/index.js +401 -0
- package/src/services/hqx-server/latency.js +81 -0
- package/src/services/index.js +12 -3
- package/src/services/rithmic/accounts.js +7 -32
- package/src/services/rithmic/connection.js +1 -204
- package/src/services/rithmic/contracts.js +116 -99
- package/src/services/rithmic/handlers.js +21 -196
- package/src/services/rithmic/index.js +63 -120
- package/src/services/rithmic/market.js +31 -0
- package/src/services/rithmic/orders.js +5 -111
- package/src/services/rithmic/protobuf.js +384 -138
- package/src/services/session.js +22 -173
- package/src/ui/box.js +10 -18
- package/src/ui/index.js +1 -3
- package/src/ui/menu.js +1 -1
- package/src/utils/prompts.js +2 -2
- package/dist/lib/m/s1.js +0 -1
- package/src/menus/ai-agent-connect.js +0 -181
- package/src/menus/ai-agent-models.js +0 -219
- package/src/menus/ai-agent-oauth.js +0 -292
- package/src/menus/ai-agent-ui.js +0 -141
- package/src/menus/ai-agent.js +0 -484
- package/src/pages/algo/algo-config.js +0 -195
- package/src/pages/algo/algo-multi.js +0 -801
- package/src/pages/algo/algo-utils.js +0 -58
- package/src/pages/algo/copy-engine.js +0 -449
- package/src/pages/algo/custom-strategy.js +0 -459
- package/src/pages/algo/logger.js +0 -245
- package/src/pages/algo/smart-logs-data.js +0 -218
- package/src/pages/algo/smart-logs.js +0 -387
- package/src/pages/algo/ui-constants.js +0 -144
- package/src/pages/algo/ui-summary.js +0 -184
- package/src/pages/stats-calculations.js +0 -191
- package/src/pages/stats-ui.js +0 -381
- package/src/pages/stats.js +0 -339
- package/src/services/ai/client-analysis.js +0 -194
- package/src/services/ai/client-models.js +0 -333
- package/src/services/ai/client.js +0 -343
- package/src/services/ai/index.js +0 -384
- package/src/services/ai/oauth-anthropic.js +0 -265
- package/src/services/ai/oauth-gemini.js +0 -223
- package/src/services/ai/oauth-iflow.js +0 -269
- package/src/services/ai/oauth-openai.js +0 -233
- package/src/services/ai/oauth-qwen.js +0 -279
- package/src/services/ai/providers/direct-providers.js +0 -323
- package/src/services/ai/providers/index.js +0 -62
- package/src/services/ai/providers/other-providers.js +0 -104
- package/src/services/ai/proxy-install.js +0 -249
- package/src/services/ai/proxy-manager.js +0 -494
- package/src/services/ai/proxy-remote.js +0 -161
- package/src/services/ai/strategy-supervisor.js +0 -1312
- package/src/services/ai/supervisor-data.js +0 -195
- package/src/services/ai/supervisor-optimize.js +0 -215
- package/src/services/ai/supervisor-sync.js +0 -178
- package/src/services/ai/supervisor-utils.js +0 -158
- package/src/services/ai/supervisor.js +0 -484
- package/src/services/ai/validation.js +0 -250
- package/src/services/hqx-server-events.js +0 -110
- package/src/services/hqx-server-handlers.js +0 -217
- package/src/services/hqx-server-latency.js +0 -136
- package/src/services/hqx-server.js +0 -403
- package/src/services/position-constants.js +0 -28
- package/src/services/position-exit-logic.js +0 -174
- package/src/services/position-manager.js +0 -438
- package/src/services/position-momentum.js +0 -206
- package/src/services/projectx/accounts.js +0 -142
- package/src/services/projectx/index.js +0 -443
- package/src/services/projectx/market.js +0 -172
- package/src/services/projectx/stats.js +0 -110
- package/src/services/projectx/trading.js +0 -180
- package/src/services/rithmic/latency-tracker.js +0 -182
- package/src/services/rithmic/market-data-decoders.js +0 -229
- package/src/services/rithmic/market-data.js +0 -272
- package/src/services/rithmic/orders-fast.js +0 -246
- package/src/services/rithmic/proto-decoders.js +0 -403
- package/src/services/rithmic/specs.js +0 -146
- package/src/services/rithmic/trade-history.js +0 -254
- package/src/services/session-history.js +0 -475
- package/src/services/strategy/hft-signal-calc.js +0 -147
- package/src/services/strategy/hft-tick.js +0 -407
- package/src/services/strategy/recovery-math.js +0 -402
- package/src/services/tradovate/constants.js +0 -109
- package/src/services/tradovate/index.js +0 -392
- package/src/services/tradovate/market.js +0 -47
- package/src/services/tradovate/orders.js +0 -145
- package/src/services/tradovate/websocket.js +0 -97
package/src/lib/api2.js
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rithmic Trading API - REAL ORDER EXECUTION
|
|
3
|
+
* Connects to Rithmic via WebSocket/Protobuf for order execution
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const WebSocket = require('ws');
|
|
7
|
+
const protobuf = require('protobufjs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const RITHMIC_GATEWAYS = {
|
|
11
|
+
CHICAGO: 'wss://rprotocol.rithmic.com:443',
|
|
12
|
+
EUROPE: 'wss://rprotocol-ie.rithmic.com:443',
|
|
13
|
+
TEST: 'wss://rituz00100.rithmic.com:443'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const PROTO_PATH = path.join(__dirname, '../../protos/rithmic');
|
|
17
|
+
|
|
18
|
+
class RithmicTradingAPI {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.ws = null;
|
|
22
|
+
this.isConnected = false;
|
|
23
|
+
this.protoRoot = null;
|
|
24
|
+
this.pendingOrders = new Map();
|
|
25
|
+
this.orderIdCounter = 1;
|
|
26
|
+
|
|
27
|
+
// Proto message types
|
|
28
|
+
this.RequestLogin = null;
|
|
29
|
+
this.ResponseLogin = null;
|
|
30
|
+
this.RequestNewOrder = null;
|
|
31
|
+
this.ResponseNewOrder = null;
|
|
32
|
+
this.ExchangeOrderNotification = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load protobuf definitions
|
|
37
|
+
*/
|
|
38
|
+
async _loadProtos() {
|
|
39
|
+
if (this.protoRoot) return;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
this.protoRoot = await protobuf.load([
|
|
43
|
+
path.join(PROTO_PATH, 'request_login.proto'),
|
|
44
|
+
path.join(PROTO_PATH, 'response_login.proto'),
|
|
45
|
+
path.join(PROTO_PATH, 'request_new_order.proto'),
|
|
46
|
+
path.join(PROTO_PATH, 'response_new_order.proto'),
|
|
47
|
+
path.join(PROTO_PATH, 'exchange_order_notification.proto'),
|
|
48
|
+
path.join(PROTO_PATH, 'request_cancel_all_orders.proto'),
|
|
49
|
+
path.join(PROTO_PATH, 'request_heartbeat.proto'),
|
|
50
|
+
path.join(PROTO_PATH, 'response_heartbeat.proto')
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
this.RequestLogin = this.protoRoot.lookupType('rti.RequestLogin');
|
|
54
|
+
this.ResponseLogin = this.protoRoot.lookupType('rti.ResponseLogin');
|
|
55
|
+
this.RequestNewOrder = this.protoRoot.lookupType('rti.RequestNewOrder');
|
|
56
|
+
this.ResponseNewOrder = this.protoRoot.lookupType('rti.ResponseNewOrder');
|
|
57
|
+
this.ExchangeOrderNotification = this.protoRoot.lookupType('rti.ExchangeOrderNotification');
|
|
58
|
+
this.RequestCancelAllOrders = this.protoRoot.lookupType('rti.RequestCancelAllOrders');
|
|
59
|
+
this.RequestHeartbeat = this.protoRoot.lookupType('rti.RequestHeartbeat');
|
|
60
|
+
|
|
61
|
+
console.log('[RITHMIC-TRADE] Protos loaded');
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('[RITHMIC-TRADE] Failed to load protos:', error.message);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Connect to Rithmic ORDER_PLANT for trading
|
|
70
|
+
*/
|
|
71
|
+
async connect() {
|
|
72
|
+
if (this.isConnected) return true;
|
|
73
|
+
|
|
74
|
+
await this._loadProtos();
|
|
75
|
+
|
|
76
|
+
const { userId, password, systemName, gateway } = this.config;
|
|
77
|
+
const gatewayUrl = gateway || RITHMIC_GATEWAYS.CHICAGO;
|
|
78
|
+
|
|
79
|
+
console.log(`[RITHMIC-TRADE] Connecting to ${gatewayUrl} for order execution`);
|
|
80
|
+
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
this.ws = new WebSocket(gatewayUrl, { rejectUnauthorized: false });
|
|
83
|
+
|
|
84
|
+
const timeout = setTimeout(() => {
|
|
85
|
+
this.ws.close();
|
|
86
|
+
reject(new Error('Connection timeout'));
|
|
87
|
+
}, 15000);
|
|
88
|
+
|
|
89
|
+
this.ws.on('open', async () => {
|
|
90
|
+
console.log('[RITHMIC-TRADE] WebSocket connected, sending login...');
|
|
91
|
+
|
|
92
|
+
const loginRequest = this.RequestLogin.create({
|
|
93
|
+
templateId: 10,
|
|
94
|
+
templateVersion: '3.9',
|
|
95
|
+
user: userId,
|
|
96
|
+
password: password,
|
|
97
|
+
appName: 'App',
|
|
98
|
+
appVersion: '1.0.0',
|
|
99
|
+
systemName: systemName,
|
|
100
|
+
infraType: 2 // ORDER_PLANT for trading
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const buffer = this.RequestLogin.encode(loginRequest).finish();
|
|
104
|
+
this.ws.send(buffer);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.ws.on('message', (data) => {
|
|
108
|
+
this._handleMessage(data, (success, error) => {
|
|
109
|
+
if (success !== undefined) {
|
|
110
|
+
clearTimeout(timeout);
|
|
111
|
+
if (success) {
|
|
112
|
+
this.isConnected = true;
|
|
113
|
+
this._startHeartbeat();
|
|
114
|
+
resolve(true);
|
|
115
|
+
} else {
|
|
116
|
+
reject(new Error(error || 'Login failed'));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this.ws.on('error', (error) => {
|
|
123
|
+
console.error('[RITHMIC-TRADE] Error:', error.message);
|
|
124
|
+
clearTimeout(timeout);
|
|
125
|
+
reject(error);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
this.ws.on('close', () => {
|
|
129
|
+
this.isConnected = false;
|
|
130
|
+
this._stopHeartbeat();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Handle incoming message
|
|
137
|
+
*/
|
|
138
|
+
_handleMessage(data, loginCallback) {
|
|
139
|
+
try {
|
|
140
|
+
const buffer = new Uint8Array(data);
|
|
141
|
+
|
|
142
|
+
// Try ResponseLogin
|
|
143
|
+
try {
|
|
144
|
+
const response = this.ResponseLogin.decode(buffer);
|
|
145
|
+
if (response.templateId === 11) {
|
|
146
|
+
const rpCode = Array.isArray(response.rpCode) ? response.rpCode[0] : response.rpCode;
|
|
147
|
+
if (rpCode === '0') {
|
|
148
|
+
console.log('[RITHMIC-TRADE] Login successful');
|
|
149
|
+
loginCallback(true);
|
|
150
|
+
} else {
|
|
151
|
+
console.log(`[RITHMIC-TRADE] Login failed: ${response.textMsg || rpCode}`);
|
|
152
|
+
loginCallback(false, response.textMsg);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {}
|
|
157
|
+
|
|
158
|
+
// Try ResponseNewOrder
|
|
159
|
+
try {
|
|
160
|
+
const response = this.ResponseNewOrder.decode(buffer);
|
|
161
|
+
if (response.templateId === 313) {
|
|
162
|
+
this._handleOrderResponse(response);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
} catch (e) {}
|
|
166
|
+
|
|
167
|
+
// Try ExchangeOrderNotification (fill, reject, etc.)
|
|
168
|
+
try {
|
|
169
|
+
const notification = this.ExchangeOrderNotification.decode(buffer);
|
|
170
|
+
if (notification.templateId === 351) {
|
|
171
|
+
this._handleOrderNotification(notification);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
} catch (e) {}
|
|
175
|
+
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('[RITHMIC-TRADE] Message decode error:', error.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Handle order response
|
|
183
|
+
*/
|
|
184
|
+
_handleOrderResponse(response) {
|
|
185
|
+
const basketId = response.basketId;
|
|
186
|
+
const pending = this.pendingOrders.get(basketId);
|
|
187
|
+
|
|
188
|
+
if (pending) {
|
|
189
|
+
const rpCode = Array.isArray(response.rpCode) ? response.rpCode[0] : response.rpCode;
|
|
190
|
+
if (rpCode === '0') {
|
|
191
|
+
console.log(`[RITHMIC-TRADE] Order acknowledged: ${basketId}`);
|
|
192
|
+
pending.resolve({ success: true, basketId });
|
|
193
|
+
} else {
|
|
194
|
+
console.log(`[RITHMIC-TRADE] Order rejected: ${response.textMsg || rpCode}`);
|
|
195
|
+
pending.reject(new Error(response.textMsg || 'Order rejected'));
|
|
196
|
+
}
|
|
197
|
+
this.pendingOrders.delete(basketId);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Handle order notification (fill, cancel, etc.)
|
|
203
|
+
*/
|
|
204
|
+
_handleOrderNotification(notification) {
|
|
205
|
+
const status = notification.notifyType;
|
|
206
|
+
const symbol = notification.symbol;
|
|
207
|
+
const fillPrice = notification.avgFillPrice;
|
|
208
|
+
const filledQty = notification.filledQty;
|
|
209
|
+
|
|
210
|
+
console.log(`[RITHMIC-TRADE] Order notification: ${symbol} - Status: ${status}, Filled: ${filledQty} @ ${fillPrice}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Place a market order - REAL EXECUTION
|
|
215
|
+
*/
|
|
216
|
+
async placeMarketOrder(accountId, contractId, side, quantity) {
|
|
217
|
+
if (!this.isConnected) {
|
|
218
|
+
await this.connect();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const basketId = `X_${Date.now()}_${this.orderIdCounter++}`;
|
|
222
|
+
|
|
223
|
+
// Extract symbol from contractId (e.g., "MNQH5" or just use as-is)
|
|
224
|
+
const symbol = this._extractSymbol(contractId);
|
|
225
|
+
|
|
226
|
+
const orderRequest = this.RequestNewOrder.create({
|
|
227
|
+
templateId: 312,
|
|
228
|
+
userMsg: [basketId],
|
|
229
|
+
symbol: symbol,
|
|
230
|
+
exchange: 'CME',
|
|
231
|
+
quantity: quantity,
|
|
232
|
+
price: 0,
|
|
233
|
+
triggerPrice: 0,
|
|
234
|
+
transactionType: side === 'buy' ? 1 : 2, // 1=Buy, 2=Sell
|
|
235
|
+
duration: 1, // DAY
|
|
236
|
+
priceType: 1, // Market
|
|
237
|
+
tradeRoute: 'DEFAULT',
|
|
238
|
+
accountId: accountId.toString(),
|
|
239
|
+
basketId: basketId
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
console.log(`[RITHMIC-TRADE] MARKET ${side.toUpperCase()} ${quantity}x ${symbol}`);
|
|
243
|
+
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
this.pendingOrders.set(basketId, { resolve, reject });
|
|
246
|
+
|
|
247
|
+
const buffer = this.RequestNewOrder.encode(orderRequest).finish();
|
|
248
|
+
this.ws.send(buffer);
|
|
249
|
+
|
|
250
|
+
// Timeout after 10 seconds
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
if (this.pendingOrders.has(basketId)) {
|
|
253
|
+
this.pendingOrders.delete(basketId);
|
|
254
|
+
reject(new Error('Order timeout'));
|
|
255
|
+
}
|
|
256
|
+
}, 10000);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Close position - REAL EXECUTION
|
|
262
|
+
*/
|
|
263
|
+
async closePosition(accountId, contractId) {
|
|
264
|
+
// For Rithmic, closing a position means placing an opposite order
|
|
265
|
+
// We need to get the current position first, but for simplicity,
|
|
266
|
+
// we'll use cancel all and let the caller handle the close order
|
|
267
|
+
console.log(`[RITHMIC-TRADE] Close position requested: ${contractId}`);
|
|
268
|
+
|
|
269
|
+
// Cancel all pending orders first
|
|
270
|
+
try {
|
|
271
|
+
await this.cancelAllOrders(accountId);
|
|
272
|
+
} catch (e) {
|
|
273
|
+
console.log('[RITHMIC-TRADE] Cancel all orders failed:', e.message);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return { success: true };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Cancel all orders
|
|
281
|
+
*/
|
|
282
|
+
async cancelAllOrders(accountId) {
|
|
283
|
+
if (!this.isConnected) return { success: false };
|
|
284
|
+
|
|
285
|
+
const request = this.RequestCancelAllOrders.create({
|
|
286
|
+
templateId: 316,
|
|
287
|
+
accountId: accountId.toString()
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const buffer = this.RequestCancelAllOrders.encode(request).finish();
|
|
291
|
+
this.ws.send(buffer);
|
|
292
|
+
|
|
293
|
+
console.log('[RITHMIC-TRADE] Cancel all orders sent');
|
|
294
|
+
return { success: true };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Extract symbol from various formats
|
|
299
|
+
*/
|
|
300
|
+
_extractSymbol(contractId) {
|
|
301
|
+
if (!contractId) return 'MNQH5';
|
|
302
|
+
|
|
303
|
+
// If already looks like Rithmic symbol, return as-is
|
|
304
|
+
if (/^[A-Z]{2,4}[FGHJKMNQUVXZ]\d{1,2}$/.test(contractId)) {
|
|
305
|
+
return contractId;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Try to extract from longer format
|
|
309
|
+
const match = contractId.match(/([A-Z]{2,4})([FGHJKMNQUVXZ])(\d{1,2})/);
|
|
310
|
+
if (match) {
|
|
311
|
+
return `${match[1]}${match[2]}${match[3]}`;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return contractId;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Start heartbeat
|
|
319
|
+
*/
|
|
320
|
+
_startHeartbeat() {
|
|
321
|
+
this.heartbeatInterval = setInterval(() => {
|
|
322
|
+
if (this.isConnected && this.ws) {
|
|
323
|
+
const heartbeat = this.RequestHeartbeat.create({ templateId: 18 });
|
|
324
|
+
const buffer = this.RequestHeartbeat.encode(heartbeat).finish();
|
|
325
|
+
this.ws.send(buffer);
|
|
326
|
+
}
|
|
327
|
+
}, 30000);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Stop heartbeat
|
|
332
|
+
*/
|
|
333
|
+
_stopHeartbeat() {
|
|
334
|
+
if (this.heartbeatInterval) {
|
|
335
|
+
clearInterval(this.heartbeatInterval);
|
|
336
|
+
this.heartbeatInterval = null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Disconnect
|
|
342
|
+
*/
|
|
343
|
+
disconnect() {
|
|
344
|
+
this._stopHeartbeat();
|
|
345
|
+
if (this.ws) {
|
|
346
|
+
this.ws.close();
|
|
347
|
+
this.ws = null;
|
|
348
|
+
}
|
|
349
|
+
this.isConnected = false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
module.exports = { RithmicTradingAPI, RITHMIC_GATEWAYS };
|