Security Exchange Identification#
Sure uniquely identifies a security using the compound key ticker + exchange_operating_mic, where exchange_operating_mic is a four-letter ISO 10383 MIC (Market Identifier Code) — the internationally standardized identifier for stock exchanges and trading venues. This prevents collisions when the same ticker symbol exists on multiple exchanges (e.g., AAPL on XNAS vs. a grey-market listing on OTCM).
Data Model#
The securities table stores the exchange as exchange_operating_mic (string, nullable) alongside ticker (string, non-null) . Database uniqueness is enforced by a case-insensitive compound index on the two columns, with NULL exchange coerced to an empty string so there's at most one exchange-less security per ticker :
index upper(ticker), COALESCE(upper(exchange_operating_mic), '')
UNIQUE
The application-level validation mirrors this: validates :ticker, uniqueness: { scope: :exchange_operating_mic, case_sensitive: false } . Before save, exchange_operating_mic is always up-cased .
The table also stores exchange_mic (the segment/participant MIC) and exchange_acronym as supplementary metadata, but exchange_operating_mic is the authoritative key used for lookups and deduplication .
Exchange Registry (config/exchanges.yml)#
The canonical MIC-to-display-name mapping lives in config/exchanges.yml, loaded at boot into Security::EXCHANGES . Each entry maps a four-letter MIC to a name (display label) and an optional country (ISO 3166-1 alpha-2). The registry covers ~80 venues across the Americas, Europe, Asia-Pacific, the Middle East, and Africa.
A few structural patterns in the registry:
- Exchange families: Multiple segment MICs share the same display name. For example,
XNAS,XNGS,XNMS, andXNCMall resolve to"NASDAQ", andXNYS,ARCX,XASE,XCHI, andXCISall resolve to NYSE family names . - Crypto: A single crypto venue is included —
BNCX(Binance, AE), added when Binance received its official ISO 10383 MIC in January 2026 .
Security.exchange_name_for(mic) resolves a MIC to its display name, falling back to the raw uppercased MIC if the code isn't in the registry . The exchange_name instance method delegates to this class method .
Combobox ID Format#
When a user selects a security from search results, the resolved security is represented as a pipe-delimited string: SYMBOL|EXCHANGE_OPERATING_MIC|PROVIDER . For example: AAPL|XNAS|twelve_data. This format is parsed by Security.parse_combobox_id and carries the full identity context needed to find or create the right Security record without ambiguity.
Crypto Detection#
A security is considered crypto when its exchange_operating_mic equals Provider::BinancePublic::BINANCE_MIC ("BNCX") . This drives behavior differences: logo URLs use Brandfetch's crypto endpoint, the crypto_base_asset method strips quote currency suffixes from tickers (e.g., BTCUSD → BTC), and no country code is propagated so any family's country filter can still resolve Binance picks .
Provider Normalization#
All securities data providers normalize their native exchange codes to ISO MIC before persisting. TwelveData returns MICs directly; Yahoo Finance maps its proprietary exchange codes via map_exchange_mic. The cross-provider dedup key is "#{symbol}|#{exchange_operating_mic}|#{provider_key}", ensuring the same ticker on the same exchange appears at most once per provider in search results .