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

Normalised order fill — a partial or complete execution of the caller's own order.

One fill is a single match against the book; **a single order may produce many fills**,
so a caller reconstructing an order's economics sums its fills rather than reading any
one of them.

Distinct from `DpExchange.Core.Types.Trade`, which is the public tape.

`:timestamp` is the venue's own, used as-is.

# `liquidity`

```elixir
@type liquidity() :: :maker | :taker | nil
```

# `t`

```elixir
@type t() :: %DpExchange.Core.Types.Fill{
  fee: Decimal.t() | nil,
  fee_currency: String.t() | nil,
  liquidity: liquidity(),
  order_id: String.t(),
  price: Decimal.t(),
  provider: atom() | String.t(),
  quantity: Decimal.t(),
  side: :buy | :sell,
  symbol: String.t(),
  timestamp: DateTime.t(),
  trade_id: String.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 `:side` that is not `:buy` or `:sell`, and on a `:liquidity` that is not
`:maker`, `:taker` or `nil`: `side: :long` on a fill reads as no side to a consumer
matching the two the type states, and a `"maker"` string matches neither.

A `:price` of zero or less raises, as a public trade's does (`Types.Trade`): a match
happened at a price above zero, and a `0` is a decode bug (an absent price read as a number)
that would zero the order's average price in whoever sums the fills. A negative `:fee` stays
legal, since a maker rebate is a fee the venue paid.

---

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