@icgio/icg-exchanges-wrapper 1.21.28 → 1.21.29

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.
@@ -72,6 +72,7 @@ const PROCESS_OPEN_ORDERS_TRADERS_INTERVAL_MS = 500
72
72
  const MARKET_HISTORY_DEFAULT_MS = 10 * 60 * 1000
73
73
  const TRADES_DEFAULT_MS = 7 * 24 * 60 * 60 * 1000
74
74
  const NO_CALLBACK_TIMEOUT_MS = 2 * 60 * 1000
75
+ const STALE_QUERY_ORDER_THRESHOLD_MS = 12 * 60 * 60 * 1000
75
76
  const PROCESS_RATES_THROTTLE_MS = 75
76
77
  const MAX_ORDER_TRACE_ENTRIES = 20
77
78
  const ORDER_TYPE_PRIORITY = {
@@ -248,6 +249,7 @@ module.exports = class Orders {
248
249
  open_orders_check: true,
249
250
  trades_check: true,
250
251
  query_order_check_maker_1_self: false,
252
+ query_order_check_stale_maker_2_3: false,
251
253
  query_order_check_exchange: {},
252
254
  rates_check: true,
253
255
  market_history_check: true,
@@ -267,10 +269,10 @@ module.exports = class Orders {
267
269
  this.trades_amount_past_hour = {}
268
270
  this.check_trades()
269
271
  }
270
- if (this.function_enabled.query_order_check_maker_1_self) {
272
+ if (this.function_enabled.query_order_check_maker_1_self || this.function_enabled.query_order_check_stale_maker_2_3) {
271
273
  for (let exchange in this.Exchanges) {
272
274
  if (this.function_enabled.query_order_check_exchange[exchange]) {
273
- this.check_query_order(exchange, ['maker_1', 'self'])
275
+ this.check_query_order(exchange)
274
276
  }
275
277
  }
276
278
  }
@@ -292,7 +294,7 @@ module.exports = class Orders {
292
294
  this.process_open_orders(this.open_orders)
293
295
  }, PROCESS_OPEN_ORDERS_TRADERS_INTERVAL_MS)
294
296
  }
295
- if (this.function_enabled.query_order_check_maker_1_self) {
297
+ if (this.function_enabled.query_order_check_maker_1_self || this.function_enabled.query_order_check_stale_maker_2_3) {
296
298
  setInterval(() => {
297
299
  this.process_query_order(this.query_order)
298
300
  }, PROCESS_OPEN_ORDERS_TRADERS_INTERVAL_MS)
@@ -770,9 +772,8 @@ module.exports = class Orders {
770
772
  const local_filled_amount = round_amount(exchange, pair, local_order.f_amount || 0)
771
773
  const polled_filled_amount = round_amount(exchange, pair, polled_order.f_amount || 0)
772
774
  const compare_total = round_amount(exchange, pair, local_order.t_amount || polled_order.t_amount || 0)
773
- const both_effectively_filled = compare_total > 0 &&
774
- local_filled_amount / compare_total > this.f_filled_threshold &&
775
- polled_filled_amount / compare_total > this.f_filled_threshold
775
+ const both_effectively_filled =
776
+ compare_total > 0 && local_filled_amount / compare_total > this.f_filled_threshold && polled_filled_amount / compare_total > this.f_filled_threshold
776
777
  if (local_order.status === exchange_status && (local_filled_amount === polled_filled_amount || both_effectively_filled)) continue
777
778
  this.log_terminal_divergence('query_order', exchange, pair, polled_order.order_id, local_order.status, exchange_status)
778
779
  if (local_order.status === 'F-FILLED' && exchange_status === 'P-FILLED') continue
@@ -1492,10 +1493,62 @@ module.exports = class Orders {
1492
1493
  }
1493
1494
  get_trades_all(this.Exchanges, this.exchange_pairs, this.interval_dict)
1494
1495
  }
1495
- check_query_order(exchange, order_types) {
1496
+ check_query_order(exchange) {
1497
+ // Per pair, periodically collect the set of orders to query and dispatch them.
1498
+ // Targets come from two sources, each gated by its own flag:
1499
+ // 1. maker_1_self: every maker_1/self order older than QUERY_ORDER_TIME_IN_MS
1500
+ // 2. stale_maker_2_3: oldest maker_2/maker_3 per axis that's missing from the
1501
+ // latest open_orders snapshot and older than STALE_QUERY_ORDER_THRESHOLD_MS
1502
+ // Both sources share the same dispatch loop, per-order in_flight dedup, aggregate
1503
+ // settlement, and downstream reconciliation via process_query_order.
1504
+ if (!this.function_enabled.query_order_check_exchange[exchange]) return
1505
+ if (!this.Exchanges[exchange] || !this.Exchanges[exchange].query_order) return
1496
1506
  const QUERY_ORDER_TIME_IN_MS = 5 * 1000
1497
- const types = order_types && order_types.length > 0 ? order_types : ['maker_1']
1498
- let query_order_handler = (exchange, pair, res) => {
1507
+ const collect_targets = (pair) => {
1508
+ const targets = []
1509
+ if (this.function_enabled.query_order_check_maker_1_self) {
1510
+ const order_info_by_type = _.get(this.get_order_info_by_order_type(['maker_1', 'self']), [exchange, pair], {})
1511
+ const cutoff = Date.now() - QUERY_ORDER_TIME_IN_MS
1512
+ for (const type of ['buy', 'sell']) {
1513
+ let oldest = null
1514
+ let oldest_open_time_ms = Infinity
1515
+ for (const order_id in order_info_by_type[type] || {}) {
1516
+ const o = order_info_by_type[type][order_id]
1517
+ if (!o || !o.order_id) continue
1518
+ const open_time_ms = typeof o.open_time === 'number' ? o.open_time : new Date(o.open_time).getTime()
1519
+ if (!open_time_ms || open_time_ms > cutoff) continue
1520
+ if (open_time_ms < oldest_open_time_ms) {
1521
+ oldest = o
1522
+ oldest_open_time_ms = open_time_ms
1523
+ }
1524
+ }
1525
+ if (oldest) targets.push({ type, order_id: oldest.order_id })
1526
+ }
1527
+ }
1528
+ if (this.function_enabled.query_order_check_stale_maker_2_3) {
1529
+ const live_ids = new Set(_.get(this.open_orders, [exchange, pair, 'open_orders'], []).map((o) => o.order_id))
1530
+ const cutoff = Date.now() - STALE_QUERY_ORDER_THRESHOLD_MS
1531
+ for (const type of ['buy', 'sell']) {
1532
+ let oldest = null
1533
+ let oldest_open_time_ms = Infinity
1534
+ for (const order_id in _.get(this.order_info, [exchange, pair, type], {})) {
1535
+ const o = this.order_info[exchange][pair][type][order_id]
1536
+ if (!o || !o.order_id || live_ids.has(o.order_id)) continue
1537
+ if (!['maker_2', 'maker_3'].includes(o.order_type)) continue
1538
+ if (!['N-FILLED', 'P-FILLED'].includes(o.status)) continue
1539
+ const open_time_ms = typeof o.open_time === 'number' ? o.open_time : new Date(o.open_time).getTime()
1540
+ if (!open_time_ms || open_time_ms > cutoff) continue
1541
+ if (open_time_ms < oldest_open_time_ms) {
1542
+ oldest = o
1543
+ oldest_open_time_ms = open_time_ms
1544
+ }
1545
+ }
1546
+ if (oldest) targets.push({ type, order_id: oldest.order_id })
1547
+ }
1548
+ }
1549
+ return targets
1550
+ }
1551
+ const query_order_handler = (exchange, pair, res) => {
1499
1552
  if (res.success) {
1500
1553
  _.set(this.query_order, [exchange, pair], { query_order: res.body, update_time: new Date() })
1501
1554
  } else if (_.get(this.query_order, [exchange, pair, 'update_time']) < Date.now() - this.interval_dict[exchange].query_order) {
@@ -1506,58 +1559,37 @@ module.exports = class Orders {
1506
1559
  }
1507
1560
  }
1508
1561
  const in_flight = new Set()
1509
- let get_query_order_all = (Exchanges, exchange_pairs, interval_dict) => {
1510
- let query_order = (exchange, pair) => {
1511
- let order_info = _.get(this.get_order_info_by_order_type(types), [exchange, pair], {})
1512
- let timeout = setTimeout(() => {
1513
- query_order(exchange, pair)
1514
- }, interval_dict[exchange].query_order)
1515
- let order_number = _.keys(order_info['sell']).length + _.keys(order_info['buy']).length,
1516
- count = 0,
1517
- result = []
1518
- const settle = () => {
1519
- query_order_handler(exchange, pair, { success: true, body: result })
1520
- clearTimeout(timeout)
1521
- setTimeout(() => {
1522
- query_order(exchange, pair)
1523
- }, interval_dict[exchange].query_order)
1524
- }
1525
- if (order_number === 0) {
1526
- return
1527
- }
1528
- for (let type in order_info) {
1529
- for (let order_id in order_info[type]) {
1530
- let { open_time } = order_info[type][order_id]
1531
- const key = `${exchange}:${pair}:${type}:${order_id}`
1532
- if (in_flight.has(key)) {
1533
- count++
1534
- if (count === order_number) settle()
1535
- continue
1536
- }
1537
- if (open_time < Date.now() - QUERY_ORDER_TIME_IN_MS) {
1538
- in_flight.add(key)
1539
- Exchanges[exchange].query_order(pair, order_id, (res) => {
1540
- in_flight.delete(key)
1541
- count++
1542
- if (res.success) {
1543
- result.push(res.body)
1544
- }
1545
- if (count === order_number) settle()
1546
- })
1547
- } else {
1548
- count++
1549
- if (count === order_number) settle()
1550
- }
1551
- }
1552
- }
1562
+ const query_order_loop = (pair) => {
1563
+ const targets = collect_targets(pair)
1564
+ let timeout = setTimeout(() => query_order_loop(pair), this.interval_dict[exchange].query_order)
1565
+ const order_number = targets.length
1566
+ if (order_number === 0) return
1567
+ let count = 0
1568
+ const result = []
1569
+ const settle = () => {
1570
+ query_order_handler(exchange, pair, { success: true, body: result })
1571
+ clearTimeout(timeout)
1572
+ setTimeout(() => query_order_loop(pair), this.interval_dict[exchange].query_order)
1553
1573
  }
1554
- if (Exchanges[exchange].query_order) {
1555
- for (let pair of exchange_pairs[exchange]) {
1556
- query_order(exchange, pair)
1574
+ for (const { type, order_id } of targets) {
1575
+ const key = `${exchange}:${pair}:${type}:${order_id}`
1576
+ if (in_flight.has(key)) {
1577
+ count++
1578
+ if (count === order_number) settle()
1579
+ continue
1557
1580
  }
1581
+ in_flight.add(key)
1582
+ this.Exchanges[exchange].query_order(pair, order_id, (res) => {
1583
+ in_flight.delete(key)
1584
+ count++
1585
+ if (res.success) result.push(res.body)
1586
+ if (count === order_number) settle()
1587
+ })
1558
1588
  }
1559
1589
  }
1560
- get_query_order_all(this.Exchanges, this.exchange_pairs, this.interval_dict)
1590
+ for (const pair of this.exchange_pairs[exchange]) {
1591
+ query_order_loop(pair)
1592
+ }
1561
1593
  }
1562
1594
  check_rates() {
1563
1595
  const pending_rate_updates = new Map()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icgio/icg-exchanges-wrapper",
3
- "version": "1.21.28",
3
+ "version": "1.21.29",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {