Symbol ↔ counter_id conversion utilities.
Longbridge's HTTP endpoints address instruments by an internal
counter_id (e.g. ST/US/AAPL, ST/HK/700, ETF/US/SPY, IX/HK/HSI),
not by the user-facing symbol (AAPL.US, 700.HK, ...). The WebSocket
layer accepts user symbols and normalises them on the server, but the
HTTP MarketContext endpoints (broker-holding, ahpremium, ...) require
the converted form.
Local conversion (offline)
to_counter_id/1 and friends mirror symbol_to_counter_id/1 from
longbridge/openapi/rust/src/utils/counter.rs exactly:
- Leading-dot symbols (e.g.
.DJI.US) are US-style indexes and always map to theIX/prefix. - HK numeric codes have leading zeros stripped
(
00700.HK→ST/HK/700). - SZ/CN codes keep leading zeros (
000001.SZ→ST/SZ/000001). - ETFs / warrants / non-stock indexes are matched against the embedded directory first.
- Everything else falls back to
ST/{MARKET}/{CODE}.
Embedded directory entries live in priv/counter_ids/. New listings
resolved at runtime can be added to Longbridge.Symbol.Cache (loaded
from $LONGBRIDGE_CACHE_DIR/counter-ids.csv when present).
Remote batch lookup (online)
For symbols missing from the embedded directory (e.g. newly listed
ETFs), resolve_counter_ids/2 calls POST /v1/quote/symbol-to-counter-ids
with the unresolved symbols and merges the server's resolution back
into the result. Resolved entries are added to the local cache so
subsequent lookups don't need a network round-trip.
Mirrors QuoteContext::symbol_to_counter_ids and
QuoteContext::resolve_counter_ids in longbridge/openapi Rust SDK
(added in 4.3.0).
Summary
Functions
Convert a counter_id (e.g. "ST/US/AAPL", "IX/HK/HSI") back to
its user-facing display symbol.
Convert a user-supplied index symbol ("HSI.HK", "/DJI.US",
"SPX.US") to its counter_id, always using the IX/ prefix.
Resolves a list of symbols to their counter_ids.
Convert a user-supplied symbol ("AAPL.US", "00700.HK") to its
internal counter_id ("ST/US/AAPL", "ST/HK/700").
Functions
Convert a counter_id (e.g. "ST/US/AAPL", "IX/HK/HSI") back to
its user-facing display symbol.
This is best-effort and intended for log messages / debugging.
Some internal counter_ids (e.g. ST/HK/<4-digit-code> for HK
warrants) have no public equivalent — the input is returned
unchanged in that case.
iex> Longbridge.Symbol.from_counter_id("ST/US/AAPL")
"AAPL.US"
iex> Longbridge.Symbol.from_counter_id("IX/HK/HSI")
"HSI.HK"
Convert a user-supplied index symbol ("HSI.HK", "/DJI.US",
"SPX.US") to its counter_id, always using the IX/ prefix.
Leading zeros are stripped from the index code where they appear
(mirroring Symbol::to_counter_id for IX/...). Examples:
iex> Longbridge.Symbol.index_to_counter_id("HSI.HK")
"IX/HK/HSI"
iex> Longbridge.Symbol.index_to_counter_id(".DJI.US")
"IX/US/DJI"
@spec resolve_counter_ids(Longbridge.Config.t(), [String.t()]) :: {:ok, [%{required(String.t()) => String.t()}]}
Resolves a list of symbols to their counter_ids.
Uses the embedded directory first, then the remote API at
POST /v1/quote/symbol-to-counter-ids for any unknown symbols.
Resolved entries are added to the local cache so subsequent
lookups don't repeat the network call.
Returns {:ok, [%{symbol: String.t(), counter_id: String.t()}]}
with one entry per input symbol, in the same order. Symbols the
backend does not recognize fall back to the local default
ST/{MARKET}/{CODE} conversion.
Convert a user-supplied symbol ("AAPL.US", "00700.HK") to its
internal counter_id ("ST/US/AAPL", "ST/HK/700").
Mirrors the upstream Symbol::to_counter_id helper from
longbridge/openapi/rust (the SDK vendored US-ETF / US-IX /
US-WT directory lives in priv/counter_ids/ and is loaded by
Longbridge.Symbol.Directory).
Rules:
AAPL.US,TSLA.US— looked up in the embedded directory for a specific counter_id (mostly relevant for ETFs and warrants that have non-ST/US/<CODE>ids). If unknown, returnsST/US/<CODE>.00700.HK— leading zeros stripped →ST/HK/700.600000.SH/000001.SZ— leading zeros kept →ST/SH/600000/ST/SZ/000001./DJI.US— leading-dot index symbol →IX/US/DJI.- Anything without a
.— returned unchanged (caller bug).
The result is purely local (no network). For an authoritative
resolution when the symbol is unknown locally, use
resolve_counter_ids/2, which falls back to the server.