Fill resolution
What happens when several resting orders trigger inside one bar — adverse-first ordering, the stop/take-profit bracket cap, and the both-hit count the result carries so the ambiguity is reported rather than hidden.
OHLC cannot reveal the sequence inside a bar. When several resting orders trigger on the same
bar, the engine has to choose an order to apply them in, and the choice changes the result: a
stop and a take-profit that both lie inside the bar's range cannot both have filled against one
position. crates/vike-fills/src/fill_resolution.rs is the one shared answer — an exact port of
the Python oracle's resolve_intrabar_fills — and its header states the two rules.
Adverse first
Apply adverse fills (stop and trailing) before favourable fills (limit). That is the
pessimistic ordering: when the data cannot say which side of the range the price reached first,
the engine assumes the side that hurts. resolve_intrabar_fills takes the (order, fill_price)
pairs that triggered this bar together with the position size before any of them, and
returns the pairs sorted adverse-first.
The bracket cap
When more than one order reduces the current position in the same bar — an SL + TP bracket — the total reduction is capped to the position size, adverse-first, so the profit target cannot also fill after the stop has already flattened the position. The returned sizes are the bracket-capped ones.
The ambiguous bar is not silently resolved. The function returns both_hit — 1 when the cap
applied this bar — and the header says why: it is surfaced on the result for honesty.
BacktestResult::intrabar_both_hit in crates/vike-analytics/src/result.rs is the counter,
described there as event-engine only; the vectorized kernel leaves it at 0. A run whose stops
and targets kept landing in the same bar is a run whose bar interval is too coarse for its
brackets, and the count is how you find that out from the result.
Where it runs
The step is part of every event-engine fill pass. fill_pending_tick_queued's doc gives the
shape of the tick lanes as trigger → resolve → dispatch → tagged lane, the resolve being this
function; the queue lane inherits it unchanged from the frozen
path it mirrors. The paper exchange is built from the same
vike-fills primitives, which is the point of the function living there: one definition of what
happens on an ambiguous bar, on both sides of the backtest-equals-paper law.
Frozen arithmetic
vike-fills was extracted verbatim from the backtester — a pure relocation with no behaviour
change — and the crate header's parity rules apply: f64 end to end, the same expression order
as the oracle, no fused multiply-add or fast-math. See the parity
gate for why none of that is relaxed to make a test pass.
Fill models
The tiered fill-price models — bar, L1 spread-crossing and the L2 book walk — selected by the data a tape carries, with the measurement that shows why the book tier exists.
The cost model
The three canonical cost scalars the backtest engines charge through — adverse fill price, fee and funding, the first two shared with the paper exchange — with the one deliberate deviation from the port, a floor that keeps an adverse move from inverting a price.