PaperExPolymarket.Execution (PaperExPolymarket v0.3.2)

Copy Markdown View Source

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 :pending execution 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 takes min(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 takes min(level_size, remaining_budget / price) at each level until the budget is exhausted. This is the right reading for prediction markets where $5 at price 0.05 should buy 100 shares, not 5.

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 :size for a share order, or the full :amount budget 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

simulate_fill(order, snap, opts \\ [])

@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.