Webull's symbol mapping.
Native form is concatenated, no separator: BTCUSD. Canonical is BASE-QUOTE. So
both directions do real work, and the same overlapping-quote hazard applies as on any
sep: "" venue — the quote list is consulted in order, and a shorter quote that is also
the tail of a longer one wins if checked first.
USDT and USDC therefore precede USD. Without that, BTCUSDT splits as BTCUS/DT
or BTCUSD/T depending on the list, and neither is an asset.
Why both directions run through CanonicalPair
So they cannot drift. The adapter this came from records why that matters: an audit
found build_order_body sending the canonical symbol to the venue un-converted, so
reads worked and writes silently did not. Running every path — read and write — through
one mapping is the fix, and it only works if there is exactly one mapping.
Summary
Functions
@spec mapping() :: DpExchange.Core.CanonicalPair.mapping()
The mapping, exposed so the conformance suite can drive CanonicalPair with it.
@spec quotes() :: [String.t()]
The quote currencies this venue settles in.