DpExchange.Core.Types.OrderBook (DpExchangeCore v0.3.14)

Copy Markdown View Source

Normalised order book snapshot, returned by every venue package.

bids and asks are sorted by price, best price first:

  • bids descending — highest bid first
  • asks ascending — lowest ask first

Each level is a {price, quantity} tuple. The ordering is part of the contract, not a convenience: a caller reading hd(bids) as the best bid is reading it correctly, and a venue package that returns venue-order without re-sorting has broken the contract even though every value in it is true.

:venue_time is the venue's own, used as-is, and nil where the venue publishes none — a nil there says the venue did not date this book, which is information rather than an omission. :observed_at is when this package read it, and is always present.

These replaced a single :timestamp in 0.2.0. See DpExchange.Core.Types.Quote's own moduledoc for the full reasoning, and docs/design/2026-09-09_venue-time-and-observed-time.md for the decision: the short version is that a venue publishing no time for a frame — which Gemini's partial-depth snapshot genuinely does not — had to either lie in a field documented as the venue's or drop real data, and one field could not tell a consumer which had happened.

dp_exchange_schwab's Streamer book is the model for :venue_time: it reads the venue's snapshot_time and fails closed when absent, rather than substituting.

:sequence is the venue's book sequence number where it publishes one, for callers reconciling snapshots against a delta stream, and nil where it does not.

Summary

Functions

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

Types

level()

@type level() :: {Decimal.t(), Decimal.t()}

t()

@type t() :: %DpExchange.Core.Types.OrderBook{
  asks: [level()],
  bids: [level()],
  observed_at: DateTime.t(),
  provider: atom() | String.t(),
  sequence: integer() | nil,
  symbol: String.t(),
  venue_time: DateTime.t() | nil
}

Functions

new(attrs)

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

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

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