0.3.2 - 2026-07-25
Fixed
- Live CLOB book timestamps in milliseconds.
OrderBook.from_clob_book/2treated a string"timestamp"as Unix seconds, but the live/bookendpoint sends milliseconds as a string (e.g."1781577793787") —DateTime.from_unix!/1then raisedinvalid Unix timeand crashed the consuming snapshotter (and, in the reference bot, the whole app on boot). The string path now applies the same ms-vs-seconds heuristic as the integer path, and a malformed timestamp falls back toDateTime.utc_now/0instead of raising. Surfaced by a real paper-trading run; 2 regression tests.
0.3.1 (unreleased)
Added
- Integration test for
PaperEx.Engine.advance_pending/3flowing throughPaperExPolymarket.Adapter: a limit pending created by the adapter is resolved by a fresh snapshot end-to-end, and a non-crossing fresh snapshot leaves the pending in place with no ledger churn. - No adapter code change —
advance_pending/3is generic in the engine and consumes the adapter's existingsimulate_fill/3.
0.3.0 (unreleased)
Added
PaperExPolymarket.Snapshot— convenience module closing the loop from a Polymarket CLOB/bookresponse to aPaperEx.MarketSnapshot:from_clob_book/3— normalize an already-fetched body for a token id,{:token_id, …}tuple, or pre-resolvedPaperEx.Instrument.fetch_order_book_snapshot/3— same, with an injected fetcher (1-arity function or{module, function, args}tuple). The package never owns network IO; fetchers are caller-supplied.
- 18 new tests covering: fixture-backed conversion, token-id /
tuple / instrument refs, malformed inputs returning bounded
reason codes (
:polymarket_invalid_market_payload,:polymarket_invalid_book), function and MFA fetcher success paths, error pass-through, instrument_opts forwarding.
Notes
- This module exists in
paper_ex_polymarketrather thanpolymarketto preserve the dependency direction:polymarketstays upstream of paper packages. Any helper returningPaperEx.MarketSnapshotbelongs here or inpolymarket_bot.
0.2.0 (unreleased)
Added
- Hand-authored CLOB/Data-API fixture set under
test/fixtures/(clob_market.json,clob_book.json,data_api_trade.json) modeling realistic Polymarket payload shapes from the v1 bot's observed responses. Seetest/fixtures/README.mdfor the shape rationale. PaperExPolymarket.Fixtures— test-support helper for loading the fixture set (not compiled into the library).- 28 new fixture-backed integration tests exercising
Market.from_clob_market/2,OrderBook.from_clob_book/2,Adapter.normalize_instrument/1,Adapter.normalize_snapshot/2,Adapter.normalize_fill/2, andExecution.simulate_fill/3against the realistic payload shapes. Covers happy paths, malformed payloads (non-map instrument, missing book keys, partial-parse prices, partial-parse timestamps, zero-size levels) and the bounded-reason-code contract. - 6 new pending-integration tests verifying that the
:pending_remainderpolicy added toPaperEx.Engineflows cleanly through the Polymarket adapter, that market FAK partials never record:pending, and thatEngine.cancel_pending/3andLiveMirror.record_pending/3coexist without colliding.
Notes
- No code change to
PaperExPolymarket.Adapterwas required: the pending-remainder policy is implemented generically inPaperEx.Engineand the adapter'ssimulate_fill/3already returns the{:ok, :partial, fills}shape the engine consumes.
0.1.0 (unreleased)
Initial scaffold of the Polymarket adapter for paper_ex.
Added
PaperExPolymarkettop-level module withversion/0and moduledoc explaining the adapter package role and non-goals.PaperExPolymarket.Market— token id ↔PaperEx.Instrumentconversion, including outcome label/index lookup against CLOB"tokens"lists and tick-size parsing.PaperExPolymarket.OrderBook— CLOB/bookbody ↔PaperEx.MarketSnapshot. Parses string-encoded prices/sizes, filters zero-size levels, surfaces malformed payloads as:invalid_book.PaperExPolymarket.ActivityMapper— Data-API and RTDS trade event ↔PaperEx.Fill. Enforces instrument id match, parses second-/ms- precision timestamps, surfaces maker/taker liquidity hints.PaperExPolymarket.Execution— Polymarket-flavored fill simulator (:marketorders modeled as FAK,:limitmodeled as GTC). Walks the book, produces:filled/:partial/:missedoutcomes with bounded reason codes (:no_liquidity,:limit_not_crossed).PaperExPolymarket.Fees— bps-based fee helper for take-fee modeling viaadapter_opts: [fee_bps: <bps>]. Defaults to zero.PaperExPolymarket.Adapter— implements everyPaperEx.Adaptercallback. Returns bounded Polymarket-tagged reason atoms (:polymarket_invalid_market_payload,:polymarket_invalid_book,:polymarket_invalid_trade_payload,:polymarket_instrument_mismatch) on top of the generic engine codes fromPaperEx.ReasonCodes.engine_codes/0.PaperExPolymarket.LiveMirror— live-mirror lifecycle helpers:simulate_intent/4— engine apply with:mode = :live_mirror.mirror_actual_fill/4— record an observed exchange trade as a:filledexecution.record_pending/3— record a resting:pendingexecution.resolve_pending/4— move a pending into:filledor:cancelled, preserving both ledger entries.
- 71 tests covering: CLOB market normalization, CLOB book parsing
(happy + malformed + zero-size), activity-event mapping (BUY /
SELL / liquidity / ms timestamps / instrument mismatch / zero
size / non-numeric), fill simulation across
:market/:limit/:buy/:sell/ partial / missed / limit-not-crossed paths, adapter behaviour conformance, end-to-endPaperEx.Engine.apply_order/4through the adapter, fee application viaadapter_opts, full live-mirror pending → filled / cancelled lifecycle, and live-mirror ledger preservation for misses and skips that never produced a position.
Deferred
- Auto-fetching CLOB market metadata via
polymarket_clob. Callers pass metadata in. - Polymarket FAK partial-remainder lifecycle (
:pendingexecution for the unfilled remainder of a market order). - A built-in price-history loader.