hedgequantx 2.7.15 → 2.7.16
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/package.json +1 -1
- package/src/lib/data.js +245 -471
- package/src/lib/m/s1-models.js +173 -0
- package/src/lib/m/s1.js +354 -735
- package/src/lib/api.js +0 -198
- package/src/lib/api2.js +0 -353
- package/src/lib/core.js +0 -539
- package/src/lib/core2.js +0 -341
- package/src/lib/data2.js +0 -492
- package/src/lib/decoder.js +0 -599
- package/src/lib/m/s2.js +0 -34
- package/src/lib/n/r1.js +0 -454
- package/src/lib/n/r2.js +0 -514
- package/src/lib/n/r3.js +0 -631
- package/src/lib/n/r4.js +0 -401
- package/src/lib/n/r5.js +0 -335
- package/src/lib/n/r6.js +0 -425
- package/src/lib/n/r7.js +0 -530
- package/src/lib/o/l1.js +0 -44
- package/src/lib/o/l2.js +0 -427
- package/src/lib/python-bridge.js +0 -206
package/src/lib/n/r5.js
DELETED
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rithmic P&L and Positions
|
|
3
|
-
* Handles real-time P&L updates from PNL_PLANT
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const EventEmitter = require('events');
|
|
7
|
-
const { RithmicConnection } = require('./r2');
|
|
8
|
-
const { TEMPLATE_IDS, INFRA_TYPES } = require('./r7');
|
|
9
|
-
|
|
10
|
-
class RithmicPnL extends EventEmitter {
|
|
11
|
-
constructor(options = {}) {
|
|
12
|
-
super();
|
|
13
|
-
|
|
14
|
-
this.connection = null;
|
|
15
|
-
this.config = null;
|
|
16
|
-
|
|
17
|
-
// Login info
|
|
18
|
-
this.fcmId = null;
|
|
19
|
-
this.ibId = null;
|
|
20
|
-
|
|
21
|
-
// Account P&L cache
|
|
22
|
-
this.accountPnL = new Map(); // accountId -> P&L data
|
|
23
|
-
|
|
24
|
-
// Instrument P&L cache
|
|
25
|
-
this.instrumentPnL = new Map(); // `${accountId}:${symbol}` -> P&L data
|
|
26
|
-
|
|
27
|
-
// Subscriptions
|
|
28
|
-
this.subscriptions = new Set(); // accountIds subscribed
|
|
29
|
-
|
|
30
|
-
// Options
|
|
31
|
-
this.debug = options.debug || false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Connect to Rithmic PNL_PLANT
|
|
36
|
-
* @param {Object} credentials - { userId, password, systemName, gateway }
|
|
37
|
-
*/
|
|
38
|
-
async connect(credentials) {
|
|
39
|
-
this.config = credentials;
|
|
40
|
-
|
|
41
|
-
this.connection = new RithmicConnection({
|
|
42
|
-
debug: this.debug,
|
|
43
|
-
maxReconnectAttempts: 5
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Forward connection events
|
|
47
|
-
this.connection.on('loggedIn', (data) => {
|
|
48
|
-
this.fcmId = data.fcmId;
|
|
49
|
-
this.ibId = data.ibId;
|
|
50
|
-
this.emit('connected', data);
|
|
51
|
-
|
|
52
|
-
// Resubscribe after reconnect
|
|
53
|
-
for (const accountId of this.subscriptions) {
|
|
54
|
-
this._sendSubscribe(accountId);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
this.connection.on('error', (error) => {
|
|
59
|
-
this.emit('error', error);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
this.connection.on('disconnected', (data) => {
|
|
63
|
-
this.emit('disconnected', data);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Handle P&L updates
|
|
67
|
-
this.connection.on('AccountPnLPositionUpdate', (update) => this._handleAccountPnL(update));
|
|
68
|
-
this.connection.on('InstrumentPnLPositionUpdate', (update) => this._handleInstrumentPnL(update));
|
|
69
|
-
|
|
70
|
-
// Connect
|
|
71
|
-
await this.connection.connect({
|
|
72
|
-
userId: credentials.userId,
|
|
73
|
-
password: credentials.password,
|
|
74
|
-
systemName: credentials.systemName,
|
|
75
|
-
gateway: credentials.gateway,
|
|
76
|
-
infraType: INFRA_TYPES.PNL_PLANT
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Subscribe to P&L updates for an account
|
|
84
|
-
*/
|
|
85
|
-
async subscribe(accountId) {
|
|
86
|
-
if (!this.connection || !this.connection.isReady) {
|
|
87
|
-
throw new Error('Not connected');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.subscriptions.add(accountId);
|
|
91
|
-
return this._sendSubscribe(accountId);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Internal subscribe
|
|
96
|
-
*/
|
|
97
|
-
_sendSubscribe(accountId) {
|
|
98
|
-
try {
|
|
99
|
-
this.connection.send('RequestPnLPositionUpdates', {
|
|
100
|
-
templateId: TEMPLATE_IDS.REQUEST_PNL_POSITION_UPDATES,
|
|
101
|
-
request: 1, // Subscribe
|
|
102
|
-
fcmId: this.fcmId,
|
|
103
|
-
ibId: this.ibId,
|
|
104
|
-
accountId: accountId.toString()
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error('[RITHMIC:PnL] Subscribe error:', error.message);
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Unsubscribe from P&L updates
|
|
117
|
-
*/
|
|
118
|
-
async unsubscribe(accountId) {
|
|
119
|
-
if (!this.connection || !this.connection.isReady) {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
this.subscriptions.delete(accountId);
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
this.connection.send('RequestPnLPositionUpdates', {
|
|
127
|
-
templateId: TEMPLATE_IDS.REQUEST_PNL_POSITION_UPDATES,
|
|
128
|
-
request: 2, // Unsubscribe
|
|
129
|
-
fcmId: this.fcmId,
|
|
130
|
-
ibId: this.ibId,
|
|
131
|
-
accountId: accountId.toString()
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
return true;
|
|
135
|
-
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.error('[RITHMIC:PnL] Unsubscribe error:', error.message);
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Handle account-level P&L update
|
|
144
|
-
*/
|
|
145
|
-
_handleAccountPnL(update) {
|
|
146
|
-
const accountId = update.accountId;
|
|
147
|
-
|
|
148
|
-
const pnlData = {
|
|
149
|
-
accountId: accountId,
|
|
150
|
-
|
|
151
|
-
// P&L
|
|
152
|
-
openPositionPnL: this._parseNumber(update.openPositionPnl),
|
|
153
|
-
closedPositionPnL: this._parseNumber(update.closedPositionPnl),
|
|
154
|
-
dayOpenPnL: this._parseNumber(update.dayOpenPnl),
|
|
155
|
-
dayClosedPnL: this._parseNumber(update.dayClosedPnl),
|
|
156
|
-
dayPnL: this._parseNumber(update.dayPnl),
|
|
157
|
-
|
|
158
|
-
// Positions
|
|
159
|
-
openPositionQuantity: update.openPositionQuantity || 0,
|
|
160
|
-
closedPositionQuantity: update.closedPositionQuantity || 0,
|
|
161
|
-
netQuantity: update.netQuantity || 0,
|
|
162
|
-
|
|
163
|
-
// Volume
|
|
164
|
-
fillBuyQty: update.fillBuyQty || 0,
|
|
165
|
-
fillSellQty: update.fillSellQty || 0,
|
|
166
|
-
buyQty: update.buyQty || 0,
|
|
167
|
-
sellQty: update.sellQty || 0,
|
|
168
|
-
|
|
169
|
-
// Balances
|
|
170
|
-
accountBalance: this._parseNumber(update.accountBalance),
|
|
171
|
-
cashOnHand: this._parseNumber(update.cashOnHand),
|
|
172
|
-
marginBalance: this._parseNumber(update.marginBalance),
|
|
173
|
-
minMarginBalance: this._parseNumber(update.minMarginBalance),
|
|
174
|
-
availableBuyingPower: this._parseNumber(update.availableBuyingPower),
|
|
175
|
-
usedBuyingPower: this._parseNumber(update.usedBuyingPower),
|
|
176
|
-
|
|
177
|
-
// Risk
|
|
178
|
-
percentMaximumAllowableLoss: this._parseNumber(update.percentMaximumAllowableLoss),
|
|
179
|
-
|
|
180
|
-
// Timestamps
|
|
181
|
-
isSnapshot: update.isSnapshot || false,
|
|
182
|
-
timestamp: Date.now()
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
// Calculate total P&L
|
|
186
|
-
pnlData.totalPnL = pnlData.openPositionPnL + pnlData.closedPositionPnL;
|
|
187
|
-
|
|
188
|
-
// Store
|
|
189
|
-
this.accountPnL.set(accountId, pnlData);
|
|
190
|
-
|
|
191
|
-
// Debug
|
|
192
|
-
if (this.debug) {
|
|
193
|
-
console.log(`[RITHMIC:PnL] Account ${accountId}: Open=$${pnlData.openPositionPnL.toFixed(2)}, Closed=$${pnlData.closedPositionPnL.toFixed(2)}, Net=${pnlData.netQuantity}`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Emit
|
|
197
|
-
this.emit('accountPnL', pnlData);
|
|
198
|
-
this.emit('pnl', pnlData);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Handle instrument-level P&L update
|
|
203
|
-
*/
|
|
204
|
-
_handleInstrumentPnL(update) {
|
|
205
|
-
const accountId = update.accountId;
|
|
206
|
-
const symbol = update.symbol;
|
|
207
|
-
const key = `${accountId}:${symbol}`;
|
|
208
|
-
|
|
209
|
-
const pnlData = {
|
|
210
|
-
accountId: accountId,
|
|
211
|
-
symbol: symbol,
|
|
212
|
-
exchange: update.exchange,
|
|
213
|
-
productCode: update.productCode,
|
|
214
|
-
instrumentType: update.instrumentType,
|
|
215
|
-
|
|
216
|
-
// P&L
|
|
217
|
-
openPositionPnL: this._parseNumber(update.openPositionPnl),
|
|
218
|
-
closedPositionPnL: this._parseNumber(update.closedPositionPnl),
|
|
219
|
-
dayOpenPnL: update.dayOpenPnl || 0,
|
|
220
|
-
dayClosedPnL: update.dayClosedPnl || 0,
|
|
221
|
-
dayPnL: update.dayPnl || 0,
|
|
222
|
-
|
|
223
|
-
// Position
|
|
224
|
-
openPositionQuantity: update.openPositionQuantity || 0,
|
|
225
|
-
closedPositionQuantity: update.closedPositionQuantity || 0,
|
|
226
|
-
netQuantity: update.netQuantity || 0,
|
|
227
|
-
avgOpenFillPrice: update.avgOpenFillPrice || 0,
|
|
228
|
-
|
|
229
|
-
// Volume
|
|
230
|
-
fillBuyQty: update.fillBuyQty || 0,
|
|
231
|
-
fillSellQty: update.fillSellQty || 0,
|
|
232
|
-
buyQty: update.buyQty || 0,
|
|
233
|
-
sellQty: update.sellQty || 0,
|
|
234
|
-
|
|
235
|
-
// Timestamps
|
|
236
|
-
isSnapshot: update.isSnapshot || false,
|
|
237
|
-
timestamp: Date.now()
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// Calculate total P&L
|
|
241
|
-
pnlData.totalPnL = pnlData.openPositionPnL + pnlData.closedPositionPnL;
|
|
242
|
-
|
|
243
|
-
// Store
|
|
244
|
-
this.instrumentPnL.set(key, pnlData);
|
|
245
|
-
|
|
246
|
-
// Emit
|
|
247
|
-
this.emit('instrumentPnL', pnlData);
|
|
248
|
-
this.emit('position', pnlData);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Parse number from string or return 0
|
|
253
|
-
*/
|
|
254
|
-
_parseNumber(value) {
|
|
255
|
-
if (typeof value === 'number') return value;
|
|
256
|
-
if (typeof value === 'string') {
|
|
257
|
-
const parsed = parseFloat(value);
|
|
258
|
-
return isNaN(parsed) ? 0 : parsed;
|
|
259
|
-
}
|
|
260
|
-
return 0;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Get account P&L
|
|
265
|
-
*/
|
|
266
|
-
getAccountPnL(accountId) {
|
|
267
|
-
return this.accountPnL.get(accountId) || null;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Get instrument P&L
|
|
272
|
-
*/
|
|
273
|
-
getInstrumentPnL(accountId, symbol) {
|
|
274
|
-
return this.instrumentPnL.get(`${accountId}:${symbol}`) || null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Get all positions for an account
|
|
279
|
-
*/
|
|
280
|
-
getPositions(accountId) {
|
|
281
|
-
const positions = [];
|
|
282
|
-
for (const [key, pnl] of this.instrumentPnL) {
|
|
283
|
-
if (key.startsWith(`${accountId}:`) && pnl.netQuantity !== 0) {
|
|
284
|
-
positions.push(pnl);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return positions;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Get all account P&L data
|
|
292
|
-
*/
|
|
293
|
-
getAllAccountPnL() {
|
|
294
|
-
return Array.from(this.accountPnL.values());
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Get summary for an account
|
|
299
|
-
*/
|
|
300
|
-
getSummary(accountId) {
|
|
301
|
-
const account = this.accountPnL.get(accountId);
|
|
302
|
-
const positions = this.getPositions(accountId);
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
accountId,
|
|
306
|
-
pnl: account,
|
|
307
|
-
positions,
|
|
308
|
-
openPositionCount: positions.length,
|
|
309
|
-
totalNetQuantity: positions.reduce((sum, p) => sum + p.netQuantity, 0)
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Check if connected
|
|
315
|
-
*/
|
|
316
|
-
get isConnected() {
|
|
317
|
-
return this.connection && this.connection.isReady;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Disconnect
|
|
322
|
-
*/
|
|
323
|
-
async disconnect() {
|
|
324
|
-
if (this.connection) {
|
|
325
|
-
await this.connection.disconnect();
|
|
326
|
-
this.connection = null;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
this.subscriptions.clear();
|
|
330
|
-
this.accountPnL.clear();
|
|
331
|
-
this.instrumentPnL.clear();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
module.exports = { RithmicPnL };
|