Skip to content

Local state ignores partial fills (Status::PartiallyFilled) #299

@simongu20070911

Description

@simongu20070911

Summary

Local processors apply fills only when order.status == Status::Filled. When using PartialFillExchange, partial fills are emitted as Status::PartiallyFilled, so local state (position/balance/fee/trade count) is not updated until the final fill.

Evidence

File: hftbacktest/src/backtest/proc/local.rs

if order.status == Status::Filled {
    self.state.apply_fill(&order);
}

Same logic in L3 local:
File: hftbacktest/src/backtest/proc/l3_local.rs

if order.status == Status::Filled {
    self.state.apply_fill(&order);
}

PartialFillExchange sets Status::PartiallyFilled for partial fills:
File: hftbacktest/src/backtest/proc/partialfillexchange.rs

if (order.leaves_qty / self.depth.lot_size()).round() > 0f64 {
    order.status = Status::PartiallyFilled;
} else {
    order.status = Status::Filled;
}

Impact

Incorrect state values when using PartialFillExchange (positions/fees/trade counts undercounted between partial fills). This can materially distort PnL and risk metrics.

Repro (minimal)

  1. Use PartialFillExchange
  2. Place a limit order that fills in multiple partials
  3. After the first partial fill, check state_values.position -> it remains unchanged until final fill

Expected

Apply fills for partial fills as well (or apply deltas based on incremental exec_qty).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions