A normalized exchange-agnostic market identifier.
An Instrument is a display/traceability record adapters and
downstream consumers use to describe a market. The adapter is
responsible for turning exchange-specific identifiers (Polymarket
token IDs, Kalshi ticker strings, exchange-symbol pairs, etc.) into
this struct via the PaperEx.Adapter.normalize_instrument/1
callback.
The engine itself never consumes an Instrument: PaperEx.Engine
works with opaque market_id / instrument_id terms carried on the
Order, Position, and MarketSnapshot, and never reaches into an
Instrument's fields. The fields here are reserved for adapters,
valuation, and execution models — :symbol, :exchange,
:description, and :metadata are for display and traceability, and
:tick_size is available to an adapter or execution model that needs
to round prices.
Fields
:id(required) — opaque adapter-specific identifier (any term). Consumers use this for equality / grouping; nothing inpaper_exparses it.:symbol— short display symbol (e.g."WELSH-YES"). Optional.:exchange— adapter / exchange tag (e.g."polymarket"). Optional.:description— long human-readable name. Optional.:tick_size— minimum price increment, if the exchange enforces one. Optional. The engine does not enforce tick-size compliance; that is the adapter's or caller's responsibility.:metadata— free-form map: condition IDs, outcome indices, raw adapter payload, anything the adapter or caller wants traceable.
Why :id is opaque
Different exchanges identify markets very differently. Polymarket
uses token IDs (256-bit integers); Kalshi uses ticker strings;
Binance uses symbol pairs. Paper_ex never parses :id; consumers
just use it for equality. Adapters round-trip whatever they want
through it.
Summary
Functions
Builds an Instrument from a map or keyword list.
Types
Functions
Builds an Instrument from a map or keyword list.
Required: :id. Raises ArgumentError on shape violations.