Packages
dp_exchange_core
0.1.21
0.3.120
0.3.119
0.3.118
0.3.117
0.3.116
0.3.115
0.3.114
0.3.113
0.3.112
0.3.111
0.3.110
0.3.109
0.3.108
0.3.107
0.3.106
0.3.105
0.3.104
0.3.103
0.3.102
0.3.101
0.3.100
0.3.99
0.3.98
0.3.97
0.3.96
0.3.95
0.3.94
0.3.93
0.3.92
0.3.91
0.3.90
0.3.89
0.3.88
0.3.87
0.3.86
0.3.85
0.3.84
0.3.83
0.3.82
0.3.81
0.3.80
0.3.79
0.3.78
0.3.77
0.3.76
0.3.75
0.3.74
0.3.73
0.3.72
0.3.71
0.3.70
0.3.69
0.3.68
0.3.67
0.3.66
0.3.65
0.3.64
0.3.63
0.3.62
0.3.61
0.3.60
0.3.59
0.3.58
0.3.57
0.3.56
0.3.55
0.3.54
0.3.53
0.3.52
0.3.51
0.3.50
0.3.49
0.3.48
0.3.47
0.3.46
0.3.45
0.3.44
0.3.43
0.3.42
0.3.41
0.3.40
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.1.79
0.1.78
0.1.77
0.1.76
0.1.75
0.1.74
0.1.73
0.1.72
0.1.71
0.1.70
0.1.69
0.1.68
0.1.67
0.1.66
0.1.65
0.1.64
0.1.63
0.1.62
0.1.61
0.1.60
0.1.59
0.1.58
0.1.57
0.1.56
0.1.55
0.1.54
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.48
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.42
0.1.41
0.1.40
0.1.39
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
EXPERIMENTAL — Shared contract for the DpExchange family of exchange adapters: behaviours, value types, canonical-pair normalisation and a conformance suite.
Current section
Files
Jump to
Current section
Files
usage-rules/symbols.md
# Symbols and the round-trip invariant
Canonical form is `BASE-QUOTE`, uppercase, dash-separated: `BTC-USD`.
## Your `SymbolFormat` declares the contract
```elixir
defmodule DpExchange.YourVenue.SymbolFormat do
@behaviour DpExchange.Core.SymbolNormalizer
@mapping %{sep: "", quotes: ~w(BUSD USDC USDT USD EUR BTC ETH)}
@impl true
def to_canonical_symbol(native),
do: DpExchange.Core.CanonicalPair.to_canonical(@mapping, native)
@impl true
def to_exchange_symbol(canonical),
do: DpExchange.Core.CanonicalPair.to_exchange(@mapping, canonical)
end
```
Both directions are required. A package shipping one fails the compiler's missing-callback
check, which is deliberate: one-directional normalisation round-trips wrong silently.
## Quotes must be ordered longest-first — and here is what that actually means
The rule is usually stated as "longest first", which is right but under-explains itself.
**The collision is a quote that *contains* a shorter quote.** `BUSD` ends with `USD`. So
`BTCBUSD` matches `USD` before it matches `BUSD`, and a shortest-first list splits the base
as `BTCB` — a pair that does not exist, carrying values that all look plausible.
Worth knowing what does **not** collide: `USD`, `USDT` and `USDC` round-trip correctly in
either order, because none is a suffix of another. A fixture built only on those looks like
it is testing the ordering rule while testing nothing.
## The invariant
```
to_canonical_symbol(to_exchange_symbol(pair)) == pair
```
For every pair, not just the ones you thought of. The conformance suite generates pairs
over your own declared `supported_quotes` for exactly that reason.
## Both directions are total
Malformed input must never raise. Unparseable input is uppercased and passed through, never
dropped — **a dropped symbol is invisible, a strange one is reviewable.**
## Asset aliases
Where your venue publishes legacy codes, map them:
```elixir
@mapping %{sep: "", quotes: ~w(USD EUR), asset_aliases: %{"XBT" => "BTC"}}
```
The alias is reversed on the way out, so the round trip still holds.