Skip to content

SymbolRegistry

Global singleton Durable Object (id: "global") managing dynamic symbol metadata, categories, leverage overrides, and automated crawler recommendations.

Purpose

SymbolRegistry is the central authority for which symbols are tradable and how they're configured. It augments the static 26 core symbols with dynamic metadata from external APIs, enabling runtime addition/removal of symbols without code deploys.

  • Single global instance (id: "global")
  • Alarm-driven crawler on configurable interval (default: 1 hour)
  • Suggest-don't-act recommendation model — crawler never auto-enables symbols
  • Eventual consistency via push + periodic reconciliation to 77 downstream DOs

High-Level Design

Core Responsibilities

  1. Symbol Lifecycle — Maintain the canonical list of symbols with their metadata (category, leverage, decimals, price scale, rankings)
  2. Automated Discovery — Crawl external APIs to discover new Hyperliquid-listed symbols and recommend promotions/demotions
  3. Config Distribution — Fan out enabled symbol config to all downstream PriceCollector and PriceAlert DOs
  4. Admin Controls — Expose promote/demote/batch operations for manual symbol management

Data Flow

External APIs    SymbolRegistry DO         Downstream DOs
─────────────    ──────────────────        ──────────────
CoinMarketCap ─┐
CoinGecko     ─┼─→ CrawlingManager     ─→  RankingsManager
Hyperliquid   ─┘   .crawlAndSync()               │
                         │                       ▼
                         │               symbols table (SQLite)
                         │                       │
                         ▼                       ▼
              PushNotificationManager  ─→  PriceCollector (7) — full metadata
                         │                 PriceAlert (70)    — symbol list

                     Admin API ←── SymbolAdminManager (promote/demote)

                     Frontend  ←── GET /symbols/enabled

Managers

ManagerRole
SymbolStorageManagerCRUD on symbols table; seeds 26 core symbols on first access
CrawlingManagerFetches from CMC, CoinGecko, Hyperliquid in parallel
CrawlerConfigManagerPersists crawler settings (topN, interval, enabled)
RankingsManagerUpdates CMC/CoinGecko ranks, inserts newly discovered symbols
PushNotificationManagerFans out config changes to downstream DOs with retry
SymbolAdminManagerPromote/demote, batch ops, recommendation management

Recommendation System (Suggest, Don't Act)

The crawler never auto-enables or auto-disables symbols. It sets recommendations (PROMOTE / DEMOTE) that require admin action:

  • PROMOTE: Symbol appears in both CMC and CoinGecko top-N and is listed on Hyperliquid, but currently disabled
  • DEMOTE: Symbol is enabled but has fallen out of the top-N intersection

This two-step design prevents accidental exposure of illiquid symbols to users.

Top-N Intersection Filter

Only symbols appearing in both CoinMarketCap and CoinGecko top-N rankings are considered for promotion. This cross-reference reduces noise from single-source anomalies.

Auto-Categorization

Newly discovered symbols are automatically categorized:

  • Known meme tickers (DOGE, SHIB, PEPE, etc.) → MEME
  • BTC, ETH → MAJOR
  • CMC rank ≤ 10 → LARGE_CAP
  • CMC rank ≤ 50 → ALTCOIN
  • Otherwise → EMERGING

Fail-Open Downstream Design

PriceCollector and PriceAlert store pushed config in memory. If they haven't received a push yet (fresh start, eviction):

  • PriceCollector: Falls back to static HyperliquidSymbolInfo definitions
  • PriceAlert: Allows all symbols (null set = no filtering)

This ensures the system degrades gracefully rather than refusing to operate.

Eventual Consistency via Push + Reconciliation

Config changes trigger an immediate push to all 77 downstream DOs (7 PriceCollectors + 70 PriceAlerts). On top of this:

  • Retry with backoff: Failed pushes retry via alarm (30s → 1m → 2m → 5m → 15m cap)
  • Periodic reconciliation: Every 15 minutes, a full push runs as a safety net to correct any drift

Lazy Initialization

On first access, if the symbols table is empty, SymbolRegistry seeds all 26 core symbols from static constants (categories, display orders, CMC/CoinGecko IDs, Hyperliquid metadata). No manual bootstrapping required.

Crawler Lifecycle

The alarm handler runs on a configurable interval (default: 1 hour):

  1. Crawl: Fetch CMC top-N, CoinGecko top-N, and all Hyperliquid perpetuals in parallel
  2. Sync: Insert new symbols as disabled, update rankings, set recommendations
  3. Reconcile: Push current config to all downstream DOs
  4. Reschedule: Set next alarm

Edge Cases & Error Handling

  • Partial crawl failure: Each external API (CMC, CoinGecko, Hyperliquid) is fetched via Promise.allSettled. If one source fails, available data is still processed — the intersection filter naturally excludes symbols missing from a failed source
  • Downstream push failure: Individual DO push failures don't block others (Promise.allSettled). Failed targets are retried with exponential backoff up to 5 attempts, and periodic reconciliation acts as a final safety net
  • Empty intersection: If both CMC and CoinGecko fail, the intersection is empty — no recommendations are generated, existing config is unchanged

See Also

  • PriceCollector — Receives enabled symbol metadata for price collection
  • PriceAlert — Receives enabled symbol list for alert validation