Skip to content
www.idarti.com edited this page Feb 26, 2026 · 2 revisions

Welcome to the NeutronTrader wiki!

Current state:

NeutronTrader v0.3 Architecture

Problem

Everything runs on Electron's single main thread: 5 exchange adapters, arbitrage detection, sniper execution, listing detection, price aggregation, DeFi wallet ops, AND the window lifecycle. A slow Kraken API response blocks the UI and every other engine.

Solution: Worker Thread Architecture

Renderer (React UI)
    |
    | IPC (contextBridge)
    v
Main Process (thin router)
    |
    +-- WorkerCoordinator
    |       |
    |       +-- marketDataWorker     (owns all WS/REST connections)
    |       |       writes to SharedArrayBuffer ──> zero-copy price reads
    |       |
    |       +-- strategyWorker       (arbitrage, sniper, listing detector, bots)
    |       |       reads SharedArrayBuffer for prices
    |       |       executes orders via adapter instances in-thread
    |       |
    |       +-- defiWorker           (lazy-spawned on first DeFi tab open)
    |               ethers.js providers, DEX adapters
    |
    +-- SystemMonitor
    |       monitors heap, RSS, load avg, event loop lag
    |       emits tier-change events -> coordinator sheds load
    |
    +-- RiskManager (stays on main -- lightweight, shared state)
    +-- StorageService (stays on main -- SQLite is single-writer)
    +-- KeyVault (stays on main -- security boundary)

New Files

electron/
  core/
    ringBuffer.js          O(1) circular buffer replacing array.shift()
    rateLimitBudget.js     Token-bucket rate limiter shared across engines
    sharedPriceCache.js    SharedArrayBuffer for cross-worker price data
    marketDataService.js   Unified WS+REST service (replaces 2 old services)
    systemMonitor.js       Resource monitor with 4 degradation tiers
    workerCoordinator.js   Spawns/manages workers, routes messages
  workers/
    marketDataWorker.js    Price feeds + arbitrage detection
    strategyWorker.js      Sniper, listing detector, trading bots

Deleted Files

src/services/professionalDataService.js   (replaced by marketDataService)
src/services/realtimeWebSocketService.js  (replaced by marketDataService)

Key Design Decisions

SharedArrayBuffer for Prices

All workers need current prices. Instead of message-passing (which serializes data and adds latency), workers share a fixed-layout Float64Array:

5 exchanges * 20 symbols * 40 bytes = 4 KB total

Market data worker writes; strategy worker reads. Zero copies, zero IPC.

Staggered + Failover Data Feeds

Each exchange gets its own connection lifecycle:

  1. Try WebSocket (real-time, lowest latency)
  2. If WS fails: fall back to REST polling
  3. If REST fails: use cached data (mark as stale)

Exchanges initialize 8 seconds apart so startup doesn't spike CPU/network.

Rate Limit Budget

All engines share a single token-bucket per exchange. The arbitrage engine and sniper engine can't accidentally exceed rate limits even when both are firing simultaneously. The budget is based on published exchange limits:

binance: 8 req/s burst, 1000/min sustained kraken: 1 req/s burst, 60/min sustained (most restrictive)

Degradation Tiers

SystemMonitor checks heap, RSS, load average, and event loop lag every 5s:

Tier 1 (Normal): Everything runs at full capacity Tier 2 (Elevated): REST polling slowed 2x, DeFi monitoring paused Tier 3 (High): Sniper paused, DeFi worker terminated, polling 4x slower Tier 4 (Critical): ALL trading stopped, open positions preserved, user alerted

Thresholds are configurable. Defaults: Heap: 400 MB -> 700 MB -> 1 GB RSS: 600 MB -> 1 GB -> 1.5 GB Load: 70% -> 85% -> 95% of CPU cores EL Lag: 50 ms -> 200 ms -> 500 ms

Lazy Everything

  • DeFi worker: spawned only on first wallet/DeFi operation
  • Exchange adapters: instantiated only when referenced
  • Strategy engines: require()'d only when user activates them
  • Adapter classes in workers: each worker loads only what it needs

RingBuffer vs Array.shift()

Old pattern (O(n) per push when full): this._history.push(record); if (this._history.length > 200) this._history.shift();

New pattern (O(1)): this._history = new RingBuffer(200); this._history.push(record);

Migration Path

  1. Drop in electron/core/* and electron/workers/*
  2. Replace IPC handlers in main.js (see main.refactored.js)
  3. Delete the two old data services
  4. Add system:status IPC channel to preload.js
  5. Add SystemMonitor widget to React dashboard
  6. Update arbitrageEngine.js and sniperEngine.js to use RingBuffer
  7. Test: start arbitrage + sniper + listing detector simultaneously -> verify UI stays responsive, memory stays under 400 MB