@icgio/icg-exchanges-wrapper 1.22.1 → 1.22.3
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/middleware/orders.js +43 -18
- package/package.json +1 -1
package/middleware/orders.js
CHANGED
|
@@ -505,20 +505,29 @@ module.exports = class Orders {
|
|
|
505
505
|
}
|
|
506
506
|
this.Exchanges[exchange].cancel_order_by_order(order, (res) => {
|
|
507
507
|
if (res.success || (!res.success && res.error === 'order-not-open' && original_status === 'CANCELING')) {
|
|
508
|
+
// The ack only means the request was processed — fills may have landed first (the
|
|
509
|
+
// trades push books them before the REST ack returns). A row already at or above
|
|
510
|
+
// f_filled_threshold is a filled order, not a canceled one.
|
|
511
|
+
const acked = _.get(this.order_info, [exchange, pair, order.type, order.order_id])
|
|
512
|
+
const acked_f_amount = round_amount(exchange, pair, (acked && acked.f_amount) || 0)
|
|
513
|
+
const acked_t_amount = round_amount(exchange, pair, (acked && acked.t_amount) || 0)
|
|
514
|
+
const acked_filled = acked_t_amount > 0 && acked_f_amount / acked_t_amount > this.f_filled_threshold
|
|
515
|
+
const ack_note = order.order_type + (acked_filled ? ' canceled-but-filled' : ' canceled')
|
|
508
516
|
this.update_order_info(
|
|
509
517
|
exchange,
|
|
510
518
|
pair,
|
|
511
519
|
order.type,
|
|
512
520
|
order.order_id,
|
|
513
521
|
{
|
|
514
|
-
status: 'CANCELED',
|
|
522
|
+
status: acked_filled ? 'F-FILLED' : 'CANCELED',
|
|
523
|
+
...(acked_filled ? { amount: 0, f_amount: acked_f_amount, f_percentage: acked_f_amount / acked_t_amount } : {}),
|
|
515
524
|
close_time: Date.now(),
|
|
516
525
|
decision_context: cancel_decision_context,
|
|
517
526
|
du_ns_cancel_latency: hrtime_diff(_.get(res, ['meta', 't_cancel_sent']), _.get(res, ['meta', 't_cancel_ack'])),
|
|
518
527
|
du_ns_rate_to_cancel_ack: hrtime_diff(decision_context?.hr_rate_root, _.get(res, ['meta', 't_cancel_ack'])),
|
|
519
528
|
event_hrtime: _.get(res, ['meta', 't_cancel_ack']),
|
|
520
529
|
},
|
|
521
|
-
|
|
530
|
+
ack_note,
|
|
522
531
|
)
|
|
523
532
|
setTimeout(() => {
|
|
524
533
|
this.delete_order_info(exchange, pair, order.type, order.order_id, order.order_type + ' cancel-order-success')
|
|
@@ -664,14 +673,20 @@ module.exports = class Orders {
|
|
|
664
673
|
const order_info_f_amount = round_amount(exchange, pair, order_info.f_amount)
|
|
665
674
|
if (_.includes(['CANCELED', 'CANCELING'], order_info.status) && trade_amount > order_info_f_amount) {
|
|
666
675
|
// console.log('TRADES: %s ORDER FILLED', order_info.status, trade, order_info)
|
|
667
|
-
|
|
676
|
+
// At or above f_filled_threshold the order is filled — book the terminal truth
|
|
677
|
+
// instead of leaving CANCELED for the query poll to flip (never P-FILLED here:
|
|
678
|
+
// resurrecting a live status on a canceled row is the failure the old comment feared)
|
|
679
|
+
const trade_filled = trade_amount / order_info.t_amount > this.f_filled_threshold
|
|
680
|
+
if (!trade_filled) {
|
|
681
|
+
this.log_terminal_divergence('trades', exchange, pair, order_id, order_info.status, 'P-FILLED')
|
|
682
|
+
}
|
|
668
683
|
this.update_order_info(
|
|
669
684
|
exchange,
|
|
670
685
|
pair,
|
|
671
686
|
type,
|
|
672
687
|
order_id,
|
|
673
688
|
{
|
|
674
|
-
|
|
689
|
+
...(trade_filled ? { status: 'F-FILLED' } : {}),
|
|
675
690
|
price: trade.price,
|
|
676
691
|
amount: 0,
|
|
677
692
|
f_amount: trade_amount,
|
|
@@ -954,24 +969,34 @@ module.exports = class Orders {
|
|
|
954
969
|
}
|
|
955
970
|
})
|
|
956
971
|
|
|
957
|
-
// If CANCELING orders are no longer in open_orders, infer they are canceled
|
|
972
|
+
// If CANCELING orders are no longer in open_orders, infer they are canceled — unless
|
|
973
|
+
// trades already show the order effectively filled: absence from the book is no
|
|
974
|
+
// evidence of cancellation for a filled order (push-tier races made that booking
|
|
975
|
+
// ping-pong CANCELED -> F-FILLED through the query reconciler ~1/min on busy venues).
|
|
958
976
|
const open_orders_ids_set = new Set(open_orders[exchange][pair].open_orders.map((o) => o.order_id))
|
|
959
977
|
this.get_order_info_status_all(exchange, pair, 'both', 'CANCELING').map((order_info) => {
|
|
960
978
|
if (order_info.order_id && !open_orders_ids_set.has(order_info.order_id)) {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
{
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
979
|
+
const swept_f_amount = round_amount(exchange, pair, order_info.f_amount || 0)
|
|
980
|
+
const swept_t_amount = round_amount(exchange, pair, order_info.t_amount || 0)
|
|
981
|
+
const effectively_filled = swept_t_amount > 0 && swept_f_amount / swept_t_amount > this.f_filled_threshold
|
|
982
|
+
const note = (order_info.order_type || '') + (effectively_filled ? ' canceling-filled-from-open-orders' : ' canceling-canceled-from-open-orders')
|
|
983
|
+
const update_dict = effectively_filled
|
|
984
|
+
? {
|
|
985
|
+
status: 'F-FILLED',
|
|
986
|
+
amount: 0,
|
|
987
|
+
f_amount: swept_f_amount,
|
|
988
|
+
f_percentage: swept_f_amount / swept_t_amount,
|
|
989
|
+
close_time: Date.now(),
|
|
990
|
+
event_hrtime: process.hrtime(),
|
|
991
|
+
}
|
|
992
|
+
: {
|
|
993
|
+
status: 'CANCELED',
|
|
994
|
+
close_time: Date.now(),
|
|
995
|
+
event_hrtime: process.hrtime(),
|
|
996
|
+
}
|
|
997
|
+
this.update_order_info(exchange, pair, order_info.type, order_info.order_id, update_dict, note)
|
|
973
998
|
setTimeout(() => {
|
|
974
|
-
this.delete_order_info(exchange, pair, order_info.type, order_info.order_id,
|
|
999
|
+
this.delete_order_info(exchange, pair, order_info.type, order_info.order_id, note)
|
|
975
1000
|
}, this.delete_finished_orders_timeout)
|
|
976
1001
|
}
|
|
977
1002
|
})
|