# `Bourse.Market`
[🔗](https://github.com/ZenHive/bourse/blob/main/lib/bourse/market.ex#L1)

Unified market/instrument metadata.

Describes a trading pair and its properties — spot, derivatives,
precision, limits, and fee structure.

## Fields

  * `id` - Exchange-native market ID (e.g., "BTCUSDT")
  * `symbol` - Unified symbol (e.g., "BTC/USDT")
  * `base`, `quote` - Base and quote currency codes
  * `base_id`, `quote_id` - Exchange-native currency IDs
  * `type` - Market type: "spot", "swap", "future", "option". Multi-leg
    books that do not satisfy a single-leg type keep the venue kind
    (`"option_combo"`, `"future_combo"`) instead of borrowing `option` /
    `future`.
  * `sub_type` - "linear" or "inverse" for derivatives
  * `spot`, `margin`, `swap`, `future`, `option`, `contract` - Type flags
  * `active` - Whether the market is currently trading
  * `settle`, `settle_id` - Settlement currency
  * `contract_size` - Base-asset units represented by one contract. Linear
    quantity is already base-denominated, so this is the venue's contract
    unit (1 for Binance USD-M BTCUSDT). Inverse venues publish a multiplier
    (100 USD for Binance COIN-M BTCUSD). Linear notional is
    `quantity * price * contract_size`; inverse notional is
    `contracts * contract_size`. Nil when the venue states no unit. On a
    multi-leg book (`combo?/1`) the mark is a spread or premium
    difference, not an underlying — do not form a notional against it.
  * `quantity_unit` - Denomination of order quantity. `"base"` for
    base-asset linear contracts and for the canonical option unit.
  * `native_quantity_unit` - Venue option quantity unit (`"base"` or `"contracts"`)
  * `native_quantity_field` - Venue option order field carrying the quantity
  * `native_amount_step` - Venue-native quantity increment before conversion
  * `linear`, `inverse` - Settlement direction flags
  * `expiry`, `expiry_datetime` - Futures/options expiration
  * `strike` - Options strike price
  * `option_type` - "call" or "put"
  * `taker`, `maker` - Fee rates as decimals
  * `percentage` - Whether fees are charged as a percentage
  * `tier_based` - Whether fees use a tiered schedule
  * `precision_mode` - Authored precision interpretation mode
  * `precision` - Price/amount/cost precision rules
  * `limits` - Min/max for price, amount, cost, leverage
  * `created` - Market listing timestamp in milliseconds
  * `asset_index` - Venue signing index for L1 actions (Hyperliquid: meta/spotMeta
    universe position with spot/HIP-3 offsets). Explicit — not overloaded onto
    `id`/`base_id` (carve C-T339).
  * `info` - Raw exchange response

# `t`

```elixir
@type t() :: %Bourse.Market{
  active: boolean() | nil,
  asset_index: integer() | nil,
  base: String.t() | nil,
  base_id: String.t() | nil,
  contract: boolean() | nil,
  contract_size: number() | nil,
  created: integer() | nil,
  expiry: integer() | nil,
  expiry_datetime: String.t() | nil,
  future: boolean() | nil,
  id: String.t() | nil,
  info: map() | nil,
  inverse: boolean() | nil,
  limits: map() | nil,
  linear: boolean() | nil,
  maker: number() | nil,
  margin: boolean() | nil,
  native_amount_step: number() | nil,
  native_quantity_field: String.t() | nil,
  native_quantity_unit: String.t() | nil,
  option: boolean() | nil,
  option_type: String.t() | nil,
  percentage: boolean() | nil,
  precision: map() | nil,
  precision_mode: String.t() | nil,
  quantity_unit: String.t() | nil,
  quote: String.t() | nil,
  quote_id: String.t() | nil,
  settle: String.t() | nil,
  settle_id: String.t() | nil,
  spot: boolean() | nil,
  strike: number() | nil,
  sub_type: String.t() | nil,
  swap: boolean() | nil,
  symbol: String.t() | nil,
  taker: number() | nil,
  tier_based: boolean() | nil,
  type: String.t() | nil
}
```

# `combo?`

```elixir
@spec combo?(t()) :: boolean()
```

True when this market is a multi-leg combo/strategy book.

Deribit `option_combo` / `future_combo` are the current cases. The mark
of a combo is a spread or premium difference between legs, not an
underlying price — `contracts * contract_size / mark` is not a notional.

# `quantity_resolvable?`

```elixir
@spec quantity_resolvable?(t()) :: boolean()
```

True when `contract_size` has a resolvable unit for exposure math.

False when this is a multi-leg combo (the mark is a spread or premium
difference, not an underlying), and false when both
`native_quantity_unit` and `quantity_unit` are unset on a market that is
not a single-leg inverse or linear contract with a published size.
Block exposure on `false` rather than multiplying by a unit-less
`contract_size`.

# `schema`

```elixir
@spec schema() :: map()
```

JSON Schema for the Market unified type.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
