@@ -6,12 +6,12 @@ const Level3Update = require("../level3-update");
6
6
const Level3Snapshot = require ( "../level3-snapshot" ) ;
7
7
8
8
/**
9
- * LedgerX is defined in https://docs.ledgerx.com/reference#market-data-feed
9
+ * LedgerX is defined in https://docs.ledgerx.com/reference#connecting
10
10
* This socket uses a unified stream for ALL market data. So we will leverage
11
11
* subscription filtering to only reply with values that of are of interest.
12
12
*/
13
13
class LedgerXClient extends BasicClient {
14
- constructor ( { wssPath = "wss://trade .ledgerx.com/api /ws?token=" , apiKey, watcherMs } = { } ) {
14
+ constructor ( { wssPath = "wss://api .ledgerx.com/ws?token=" , apiKey, watcherMs } = { } ) {
15
15
super ( wssPath + apiKey , "LedgerX" , undefined , watcherMs ) ;
16
16
17
17
this . hasTrades = true ;
@@ -31,6 +31,8 @@ class LedgerXClient extends BasicClient {
31
31
_sendUnSubLevel3Updates ( ) { }
32
32
33
33
_onMessage ( msg ) {
34
+ this . emit ( "raw" , msg ) ;
35
+
34
36
const json = JSON . parse ( msg ) ;
35
37
36
38
if ( json . type === "auth_success" ) {
@@ -41,15 +43,15 @@ class LedgerXClient extends BasicClient {
41
43
return ;
42
44
}
43
45
44
- if ( json . type === "exposure_reports" ) {
46
+ if ( json . positions !== undefined ) {
45
47
return ;
46
48
}
47
49
48
- if ( json . type === "open_positions_update" ) {
50
+ if ( json . collateral !== undefined ) {
49
51
return ;
50
52
}
51
53
52
- if ( json . type === "collateral_balance_update " ) {
54
+ if ( json . type === "exposure_reports " ) {
53
55
return ;
54
56
}
55
57
@@ -76,7 +78,7 @@ class LedgerXClient extends BasicClient {
76
78
return ;
77
79
}
78
80
79
- // trade event
81
+ // trade event, filled either partial or fully
80
82
if ( json . status_type === 201 ) {
81
83
// check for trade subscription
82
84
let market =
@@ -110,6 +112,18 @@ class LedgerXClient extends BasicClient {
110
112
this . emit ( "l3update" , update , market , json ) ;
111
113
return ;
112
114
}
115
+
116
+ // cancelled and replaced event
117
+ if ( json . status_type === 204 ) {
118
+ const market =
119
+ this . _level3UpdateSubs . get ( json . contract_id ) ||
120
+ this . _level3UpdateSubs . get ( json . contract_id . toString ( ) ) ;
121
+ if ( ! market ) return ;
122
+
123
+ const update = this . _constructL3Replace ( json , market ) ;
124
+ this . emit ( "l3update" , update , market , json ) ;
125
+ return ;
126
+ }
113
127
}
114
128
}
115
129
@@ -125,7 +139,7 @@ class LedgerXClient extends BasicClient {
125
139
let bids = [ ] ;
126
140
for ( let row of data . book_states ) {
127
141
let orderId = row . mid ;
128
- let price = ( row . price / 100 ) . toFixed ( 2 ) ;
142
+ let price = row . price . toFixed ( 2 ) ;
129
143
let size = row . size . toFixed ( ) ;
130
144
let point = new Level3Point ( orderId , price , size ) ;
131
145
if ( row . is_ask ) asks . push ( point ) ;
@@ -212,10 +226,13 @@ class LedgerXClient extends BasicClient {
212
226
amount : msg . filled_size . toFixed ( 8 ) ,
213
227
buyOrderId,
214
228
sellOrderId,
229
+ open_interest : msg . open_interest ,
215
230
} ) ;
216
231
}
217
232
218
233
/**
234
+ * 200 - A resting limit order of size inserted_size @ price
235
+ * inserted_price was inserted into book depth.
219
236
{
220
237
inserted_time: 1597176131501325800,
221
238
timestamp: 1597176131501343700,
@@ -242,7 +259,7 @@ class LedgerXClient extends BasicClient {
242
259
}
243
260
*/
244
261
_constructL3Insert ( msg , market ) {
245
- let price = ( msg . price / 100 ) . toFixed ( 8 ) ;
262
+ let price = msg . price . toFixed ( 8 ) ;
246
263
let size = msg . inserted_size . toFixed ( 8 ) ;
247
264
let point = new Level3Point ( msg . mid , price , size , {
248
265
order_type : msg . order_type ,
@@ -283,6 +300,8 @@ class LedgerXClient extends BasicClient {
283
300
}
284
301
285
302
/**
303
+ * 201 - A cross of size filled_size @ price filled_price occurred.
304
+ * Subtract filled_size from the resting size for this order.
286
305
{
287
306
mid: '885be81549974faf88e4430f6046513d',
288
307
filled_size: 5,
@@ -309,7 +328,7 @@ class LedgerXClient extends BasicClient {
309
328
}
310
329
*/
311
330
_constructL3Trade ( msg , market ) {
312
- let price = ( msg . original_price / 100 ) . toFixed ( 8 ) ;
331
+ let price = msg . original_price . toFixed ( 8 ) ;
313
332
let size = ( msg . original_size - msg . filled_size ) . toFixed ( 8 ) ;
314
333
let point = new Level3Point ( msg . mid , price , size , {
315
334
order_type : msg . order_type ,
@@ -329,6 +348,7 @@ class LedgerXClient extends BasicClient {
329
348
price : msg . price ,
330
349
size : msg . size ,
331
350
vwap : msg . vwap ,
351
+ open_interest : msg . open_interest ,
332
352
} ) ;
333
353
334
354
let asks = [ ] ;
@@ -350,6 +370,7 @@ class LedgerXClient extends BasicClient {
350
370
}
351
371
352
372
/**
373
+ * 203 - An order was cancelled. Remove this order from book depth.
353
374
{
354
375
inserted_time: 1597176853952381700,
355
376
timestamp: 1597176857137740800,
@@ -376,7 +397,7 @@ class LedgerXClient extends BasicClient {
376
397
}
377
398
*/
378
399
_constructL3Cancel ( msg , market ) {
379
- let price = ( msg . original_price / 100 ) . toFixed ( 8 ) ;
400
+ let price = msg . original_price . toFixed ( 8 ) ;
380
401
let size = ( 0 ) . toFixed ( 8 ) ;
381
402
let point = new Level3Point ( msg . mid , price , size , {
382
403
order_type : msg . order_type ,
@@ -396,6 +417,80 @@ class LedgerXClient extends BasicClient {
396
417
price : msg . price ,
397
418
size : msg . size ,
398
419
vwap : msg . vwap ,
420
+ open_interest : msg . open_interest ,
421
+ } ) ;
422
+
423
+ let asks = [ ] ;
424
+ let bids = [ ] ;
425
+
426
+ if ( msg . is_ask ) asks . push ( point ) ;
427
+ else bids . push ( point ) ;
428
+
429
+ return new Level3Update ( {
430
+ exchange : this . _name ,
431
+ base : market . base ,
432
+ quote : market . quote ,
433
+ sequenceId : msg . clock ,
434
+ timestampMs : Math . floor ( msg . inserted_time / 1e6 ) ,
435
+ runId : this . runId ,
436
+ asks,
437
+ bids,
438
+ } ) ;
439
+ }
440
+
441
+ /**
442
+ * 204 - An order was cancelled and replaced. The new order retains the
443
+ * existing mid, and can only reflect an update in size and not price.
444
+ * Overwrite the resting order size with inserted_size.
445
+ *
446
+ {
447
+ "status_type": 204,
448
+ "inserted_size": 12,
449
+ "original_price": 59000,
450
+ "open_interest": 121,
451
+ "filled_size": 0,
452
+ "updated_time": 1623074768372895949,
453
+ "clock": 40011,
454
+ "size": 12,
455
+ "timestamp": 1623074768372897897,
456
+ "status_reason": 0,
457
+ "vwap": 0,
458
+ "inserted_time": 1623074764668677182,
459
+ "price": 59000,
460
+ "type": "action_report",
461
+ "is_ask": true,
462
+ "original_size": 12,
463
+ "order_type": "customer_limit_order",
464
+ "is_volatile": true,
465
+ "ticks": 25980094140252686,
466
+ "filled_price": 0,
467
+ "mid": "c071baaa458a411db184cb6874e86d69",
468
+ "inserted_price": 59000,
469
+ "contract_id": 22216779
470
+ }
471
+ */
472
+ _constructL3Replace ( msg , market ) {
473
+ let price = msg . original_price . toFixed ( 8 ) ;
474
+ let size = msg . inserted_size . toFixed ( 8 ) ;
475
+ let point = new Level3Point ( msg . mid , price , size , {
476
+ order_type : msg . order_type ,
477
+ status_type : msg . status_type ,
478
+ status_reason : msg . status_reason ,
479
+ is_volatile : msg . is_volatile ,
480
+ timestamp : msg . timestamp ,
481
+ ticks : msg . ticks ,
482
+ inserted_time : msg . inserted_time ,
483
+ updated_time : msg . updated_time ,
484
+ original_price : msg . original_price ,
485
+ original_size : msg . original_size ,
486
+ inserted_price : msg . inserted_price ,
487
+ inserted_size : msg . inserted_size ,
488
+ filled_price : msg . filled_price ,
489
+ filled_size : msg . filled_size ,
490
+ price : msg . price ,
491
+ size : msg . size ,
492
+ vwap : msg . vwap ,
493
+ open_interest : msg . open_interest ,
399
494
} ) ;
400
495
401
496
let asks = [ ] ;
0 commit comments