fix(ml-backtesting): skip queue-decay fill for sentinel-priced market-like orders — ACTUAL root cause of vwap=0/huge sentinels
S1.20-S1.22 chased a wrong hypothesis (walk_* deep-level filter) for 3 rounds. The actual bug: resting_orders.cu:344 fills at cost = take * s.price in the queue-decay maturation arm. Market-like orders seed at line 644 with sentinel s.price = 1e9 (buy) / 0 (sell), counting on the marketability check at lines 372-... to fire first via walk_*. But queue_position initializes to 0 (no book level matches the sentinel), so on the first same-side trade volume the queue-decay arm fires and injects the sentinel into cost: buy cost = take * 1e9 -> avg_px = 1e9 -> huge_flat=216, sell cost = take * 0 -> avg_px = 0 -> zero_flat=194. Same pattern explains flip=9+6. Fix: detect s.price outside [min_reasonable_px, max_reasonable_px] in the queue-decay arm; absorb queue_position depletion without filling. Marketability check fires in the same iteration via walk_* with proper book prices. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -336,29 +336,41 @@ extern "C" __global__ void resting_orders_step(
|
|||||||
if (s.queue_position >= trade_abs) {
|
if (s.queue_position >= trade_abs) {
|
||||||
s.queue_position -= trade_abs;
|
s.queue_position -= trade_abs;
|
||||||
} else {
|
} else {
|
||||||
const float over = trade_abs - s.queue_position;
|
// Sentinel-priced (market-like) orders use s.price = 1e9 (buy)
|
||||||
s.queue_position = 0.0f;
|
// or 0 (sell) so the marketability check below always crosses.
|
||||||
const float take = (over < s.size_remaining) ? over : s.size_remaining;
|
// The queue-decay arm MUST NOT use s.price for cost because it
|
||||||
if (take > 0.0f) {
|
// would inject the sentinel into avg_px (S1.23 root cause:
|
||||||
// Filled `take` lots at our limit price (queue position reached us).
|
// zero_flat=194, huge_flat=216). Absorb the queue depletion
|
||||||
const float cost = take * s.price;
|
// only; the marketability check fires this same iteration via
|
||||||
apply_fill_to_pos(pos, take, cost, s.side,
|
// walk_* with book-derived prices.
|
||||||
b, cost_per_lot_per_side_per_b, total_fees_per_b,
|
const bool is_sentinel_price = (s.price < min_px) || (s.price > max_px);
|
||||||
nan_avg_px, nan_realised, nan_realized_pnl,
|
if (is_sentinel_price) {
|
||||||
vwap_zero_open_flat, vwap_huge_open_flat,
|
s.queue_position = 0.0f;
|
||||||
vwap_zero_scale_in, vwap_huge_scale_in,
|
} else {
|
||||||
vwap_zero_flip, vwap_huge_flip,
|
const float over = trade_abs - s.queue_position;
|
||||||
last_bad_vwap, last_bad_path);
|
s.queue_position = 0.0f;
|
||||||
s.size_remaining -= take;
|
const float take = (over < s.size_remaining) ? over : s.size_remaining;
|
||||||
emit_audit(audit_base, audit_head, b, (unsigned int)ring_cap_events,
|
if (take > 0.0f) {
|
||||||
current_ts_ns,
|
// Filled `take` lots at our limit price (queue position reached us).
|
||||||
pack_slot_tag(0 /*SlotKind::Limit*/, (unsigned char)i, s.gen_counter),
|
const float cost = take * s.price;
|
||||||
1 /*SubmitLimit*/, s.side, (unsigned short)take,
|
apply_fill_to_pos(pos, take, cost, s.side,
|
||||||
(int)(s.price / tick_size + 0.5f), 0);
|
b, cost_per_lot_per_side_per_b, total_fees_per_b,
|
||||||
if (s.size_remaining <= 0.0f) {
|
nan_avg_px, nan_realised, nan_realized_pnl,
|
||||||
cancel_oco_pair(orders, s.oco_pair);
|
vwap_zero_open_flat, vwap_huge_open_flat,
|
||||||
s.active = 0;
|
vwap_zero_scale_in, vwap_huge_scale_in,
|
||||||
continue;
|
vwap_zero_flip, vwap_huge_flip,
|
||||||
|
last_bad_vwap, last_bad_path);
|
||||||
|
s.size_remaining -= take;
|
||||||
|
emit_audit(audit_base, audit_head, b, (unsigned int)ring_cap_events,
|
||||||
|
current_ts_ns,
|
||||||
|
pack_slot_tag(0 /*SlotKind::Limit*/, (unsigned char)i, s.gen_counter),
|
||||||
|
1 /*SubmitLimit*/, s.side, (unsigned short)take,
|
||||||
|
(int)(s.price / tick_size + 0.5f), 0);
|
||||||
|
if (s.size_remaining <= 0.0f) {
|
||||||
|
cancel_oco_pair(orders, s.oco_pair);
|
||||||
|
s.active = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user