Polymarket-flavored fill simulator.
This module simulates how a PaperEx.Order would execute against
a PaperEx.MarketSnapshot produced by
PaperExPolymarket.OrderBook.from_clob_book/2. It is the
simulate_fill/3 implementation behind PaperExPolymarket.Adapter.
Polymarket order-type defaults
Polymarket's CLOB v2 supports several order types (FOK, FAK, GTC,
GTD). The adapter maps PaperEx.Order types as follows:
:market— modeled as FAK (fill-and-kill against current book). Walks levels; whatever fills, fills. Unfilled remainder is dropped (a future phase may emit a:pendingexecution for the remainder).:limit— modeled as GTC for simulation purposes. The order fills against any level that crosses the limit price. Unfilled remainder is reported as a partial fill; the engine can decide to leave the rest as:pending.
This is intentionally simpler than the live CLOB's full lifecycle.
Research-mode simulation does not need GTC resting-order
reconciliation. Live-mirror callers wanting that detail should
combine simulate_fill/3 with their own pending-order tracking
using PaperEx.Execution.status :pending → :filled /
:cancelled transitions.
:size vs :amount for :market orders
A :market order can specify quantity in two ways:
:size— explicit share quantity. The walker takesmin(level_size, remaining_shares)at each level until shares are exhausted.:amount— currency budget ("spend at most $N"for buys,"receive at most $N"for sells). The walker takesmin(level_size, remaining_budget / price)at each level until the budget is exhausted. This is the right reading for prediction markets where$5at price0.05should buy100shares, not5.
When both :size and :amount are set, :size wins — the
caller has stated explicit share quantity. For :limit orders,
:amount is informational only; the walker always uses :size
(per PaperEx.Order moduledoc).
Return shape
Matches PaperEx.Adapter.simulate_fill/3:
{:ok, :filled, [Fill.t()]}— the order's target was reached: the full requested:sizefor a share order, or the full:amountbudget exhausted for a budget (:amount) order.{:ok, :partial, [Fill.t()]}— some quantity filled; remainder unmodeled (book exhausted before the size/budget target).{:ok, :missed, :limit_not_crossed}— limit price did not cross the book.{:ok, :missed, :no_liquidity}— relevant side of book empty.
Summary
Functions
Simulate order against snapshot. opts is reserved for
future tuning (slippage cap, post-only flag, etc.) and currently
ignored.
Functions
@spec simulate_fill(PaperEx.Order.t(), PaperEx.MarketSnapshot.t(), keyword()) :: {:ok, :filled | :partial, [PaperEx.Fill.t()]} | {:ok, :missed, atom() | String.t()}
Simulate order against snapshot. opts is reserved for
future tuning (slippage cap, post-only flag, etc.) and currently
ignored.