Skip to content

SymbolRegistry

SymbolRegistry assigns and resolves stable SymbolId and ExchangeId values for instruments and exchanges. Exposes full metadata (SymbolInfo, ExchangeInfo) for fast, type-safe access across the engine.

struct SymbolInfo
{
  SymbolId id{0};
  std::string exchange;
  std::string symbol;
  InstrumentType type = InstrumentType::Spot;
  Price tickSize{Price::fromDouble(0.01)};
  ExchangeId exchangeId{InvalidExchangeId};

  std::optional<Price> strike;
  std::optional<TimePoint> expiry;
  std::optional<OptionType> optionType;
};

class SymbolRegistry : public ISubsystem
{
public:
  static constexpr size_t kMaxExchanges = 32;
  static constexpr size_t kMaxSymbols = 4096;
  static constexpr size_t kMaxEquivalentsPerSymbol = 8;

  // Exchange management
  ExchangeId registerExchange(std::string_view name,
                              VenueType type = VenueType::CentralizedExchange);
  const ExchangeInfo* getExchange(ExchangeId id) const;
  ExchangeId getExchangeId(std::string_view name) const;
  size_t exchangeCount() const;

  // Symbol registration (legacy string-based API)
  SymbolId registerSymbol(const std::string& exchange, const std::string& symbol);
  SymbolId registerSymbol(const SymbolInfo& info);
  std::optional<SymbolId> getSymbolId(const std::string& exchange,
                                      const std::string& symbol) const;
  std::optional<SymbolInfo> getSymbolInfo(SymbolId id) const;
  std::pair<std::string, std::string> getSymbolName(SymbolId id) const;

  // Symbol registration (ExchangeId-based API)
  SymbolId registerSymbol(ExchangeId exchange, std::string_view symbol);
  ExchangeId getExchangeForSymbol(SymbolId symbol) const;

  // Symbol equivalence (cross-exchange mapping)
  void mapEquivalentSymbols(std::span<const SymbolId> equivalentSymbols);
  std::span<const SymbolId> getEquivalentSymbols(SymbolId symbol) const;
  SymbolId getEquivalentOnExchange(SymbolId symbol, ExchangeId exchange) const;

  // Persistence
  bool saveToFile(const std::filesystem::path& path) const;
  bool loadFromFile(const std::filesystem::path& path);
  std::vector<std::byte> serialize() const;
  bool deserialize(std::span<const std::byte> data);

  // Utilities
  void clear();
  std::vector<SymbolInfo> getAllSymbols() const;
  size_t size() const;
};

Purpose

  • Provide a thread-safe, bidirectional mapping between human-readable instrument keys and compact numeric SymbolIds.
  • Manage exchange registrations with ExchangeId for multi-exchange scenarios.
  • Support cross-exchange symbol equivalence for arbitrage and routing.
  • Expose complete instrument metadata (SymbolInfo) for latency-critical components without repeated parsing.
  • Support persistence and serialization for replay and data recording scenarios.

Exchange Management

Method Description
registerExchange Registers an exchange, returns ExchangeId.
getExchange Returns ExchangeInfo* for the given ID.
getExchangeId Lookup ExchangeId by name.
exchangeCount Returns number of registered exchanges.

Symbol Registration

Method Description
registerSymbol(str) Registers a spot instrument, returns existing id if present.
registerSymbol(info) Registers any instrument type with full metadata.
registerSymbol(ExchangeId, symbol) Registers using ExchangeId instead of string.
getSymbolId Forward lookup from (exchange, symbol) to SymbolId.
getSymbolName Reverse lookup from SymbolId to (exchange, symbol) string pair.
getSymbolInfo Returns std::optional<SymbolInfo> for the given ID.
getExchangeForSymbol Returns ExchangeId for a given symbol.

Symbol Equivalence

For cross-exchange trading, symbols on different exchanges can be mapped as equivalent:

// Register symbols on different exchanges
auto btcBinance = registry.registerSymbol("binance", "BTCUSDT");
auto btcBybit = registry.registerSymbol("bybit", "BTCUSDT");
auto btcOkx = registry.registerSymbol("okx", "BTC-USDT");

// Map them as equivalent
registry.mapEquivalentSymbols({btcBinance, btcBybit, btcOkx});

// Query equivalents
auto equivalents = registry.getEquivalentSymbols(btcBinance);  // Returns all 3
auto bybitEquiv = registry.getEquivalentOnExchange(btcBinance, bybitExchangeId);
Method Description
mapEquivalentSymbols Links symbols as equivalent across exchanges.
getEquivalentSymbols Returns span of all equivalent symbols.
getEquivalentOnExchange Returns equivalent symbol on a specific exchange.

Persistence

Method Description
saveToFile Persists registry to a binary file.
loadFromFile Loads registry from a binary file.
serialize Returns binary representation as std::vector<std::byte>.
deserialize Restores state from binary data.

Capacity Limits

Constant Value Description
kMaxExchanges 32 Maximum number of exchanges.
kMaxSymbols 4096 Maximum number of symbols.
kMaxEquivalentsPerSymbol 8 Maximum equivalents per symbol.

Internal Design

  • Composite key "exchange:symbol" ensures O(1) forward lookups via _map.
  • _symbols is an unordered_map for direct id lookups.
  • _symbolToExchange provides O(1) symbol-to-exchange mapping.
  • Equivalence uses flat storage: [sym * kMaxEquivalentsPerSymbol ... (sym+1) * kMaxEquivalentsPerSymbol) for O(1) lookup.
  • A single mutex protects all structures; registration is rare, lookups are frequent.

Notes

  • Inherits from ISubsystem for lifecycle management integration.
  • InstrumentType allows immediate filtering (Spot, Future, Option) without extra registry calls in hot paths.
  • SymbolId remains a compact, contiguous 32-bit value suitable for array indices in event buses and order books.
  • Option-specific fields (strike, expiry, optionType) are populated only when type == InstrumentType::Option.
  • tickSize stores the minimum price increment for the instrument (default 0.01).
  • exchangeId links symbol directly to its exchange for O(1) access.
  • Persistence methods are useful for storing symbol mappings alongside recorded market data.