# `DpExchange.Core.Types.ContractStats`
[🔗](https://github.com/DistortionPoint/dp-exchange-core/blob/v0.3.120/lib/dp_exchange/core/types/contract_stats.ex#L1)

Risk statistics for a derivative contract.

## Mark and index are not the same price, and neither is the last trade

`:mark_price` is the venue's own valuation — what it marks positions and computes
liquidations against. `:index_price` is the external reference it is derived from. They
diverge, sometimes sharply, and the divergence is the point: a venue marking away from the
index is why a position can be liquidated at a price the market never printed.

Neither is a traded price. `Types.Quote` carries that. Three prices for one instrument,
each meaning something different, is exactly the situation in which a single "price" field
produces a confident wrong answer.

## Open interest in contracts and in notional

`:open_interest` counts contracts; `:open_interest_notional` values them. A venue publishes
both because neither substitutes for the other across instruments with different contract
sizes.

# `t`

```elixir
@type t() :: %DpExchange.Core.Types.ContractStats{
  index_price: Decimal.t() | nil,
  mark_price: Decimal.t() | nil,
  open_interest: Decimal.t() | nil,
  open_interest_notional: Decimal.t() | nil,
  product_type: String.t() | nil,
  provider: atom(),
  symbol: String.t(),
  venue_time: DateTime.t() | nil
}
```

# `new`

```elixir
@spec new(keyword() | map()) :: t()
```

Builds a `t:t/0`, failing closed if a required field is absent or `nil`.

`@enforce_keys` guards presence, not `nil` — see `DpExchange.Core.Types.Validate`.

Also raises on a `:mark_price` or `:index_price` of zero or less (a valuation is above zero)
and on a negative `:open_interest` or `:open_interest_notional` (zero is legal, an instrument
nobody holds).

---

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