Skip to content

Latest commit

 

History

History
146 lines (121 loc) · 7.79 KB

File metadata and controls

146 lines (121 loc) · 7.79 KB

Architecture

Polyterm is a multi-version bot platform. A single app runs one kernel (src/engine.js) that owns all the shared machinery, and drives whichever strategy plugin is currently selected in the Version Manager. Strategies decide what to bet; the kernel decides how to execute and book it.

                    ┌──────────────────────────────────────────────┐
                    │                 KERNEL  (engine.js)           │
 Spot feeds  ─────► │  feeds · market discovery · order execution   │
 (Binance WS)       │  risk gates · per-version ledgers · wallet    │ ◄── Version
 Target watcher ──► │  settlement · dashboard stream                │     Manager
 (/activity API)    │                      ▲     │                  │     (selects
 On-chain watcher ► │                ctx   │     │ events           │      the bot)
 (CTF transfers)    └──────────────────────┼─────┼──────────────────┘
                                           │     ▼
                              ┌────────────┴───────────────┐
                              │   Strategy plugin (active)  │
                              │  v1 Copy · v2 Strategy · …  │
                              └─────────────────────────────┘

The Version Manager

The dashboard lands on the Version Manager — a control panel, independent of any bot. It lists every registered version with its own P&L (separate per version) and an Enter button. Entering a bot:

  1. switches the kernel's active strategy (live, no restart), and
  2. opens that bot's dedicated UI.

A ← MANAGER button returns to the launcher; the bot keeps running in the background. Implemented bots are enterable; planned ones show "coming soon".

Decisions baked in: dashboard launcher (not a startup screen) · separate P&L per version · live-switchable any time.

The kernel (engine.js)

Owns everything shared, so every bot inherits it for free:

  • Spot feeds — one Binance WS price feed per asset (spotFeed.js); provides live price, the window-open price, and a momentum reading.
  • Market discovery (markets.js) — finds the currently-active window per asset. Two schemes:
    • epoch (5m/15m): the slug is ‹ticker›-updown-‹N›m-‹openTs›, with openTs = floor(now / windowSeconds) * windowSeconds.
    • series (1h/1d): the slugs are date-based (e.g. bitcoin-up-or-down-june-23-2026-9pm-et) so they can't be constructed; the live event is resolved from the Gamma series (‹ticker›-up-or-down-‹hourly|daily›) — the open, accepting event whose end is soonest in the future.
  • Unified window model — per-asset timing is driven by each market's own endTs, so it's correct for both epoch-aligned (5m/15m, 1h) and non-aligned (1d = ET midnight) windows. Rollover fires when the active window changes.
  • Order execution & risk gates — a single serialized-per-window path with all the gates (paused, asset-off, not-accepting, no-trade tail, max clips, throttle, max entry price, risk halt) and the dust-bump (size up to the 5-share minimum instead of skipping). Every skip is categorized for the copy-health breakdown.
  • Per-(version + mode) ledgersvdata, keyed ‹version›:‹paper|live›. Each holds its own broker, P&L series, blotter, settlements, reject counts, and slippage accumulators. Switching versions never mixes results.
  • BrokerspaperBroker.js (simulated fills vs the live book) and liveBroker.js (real CLOB FAK orders); identical interface so the kernel is broker-agnostic. Both support buyClip, sellSide (copy-exit one side), sellMarket (recycle), and settleWindow (resolution).
  • Wallet — live pUSD balance + funding/allowance preflight (clobClient.js), or the paper bankroll.
  • Dashboard stream (server.js) — WebSocket + HTTP; broadcasts full state each tick plus discrete fill/settle/window/target events.

Detection (how we see the target)

Used by target-following bots (Copy Bot). Two paths, deduped by txHash | conditionId | side:

Path Source Latency Role
On-chain CTF ERC-1155 transfers (WebSocket eth_subscribe) ~2–4 s primary
API Polymarket /activity (cache-busted) ~16–22 s fallback / enrichment

On-chain detects both directions: a transfer to the target = a BUY, a transfer from the target = a SELL (two subscriptions / log filters). RPC endpoints fail over (Alchemy → Infura → public).

The /trades API is not used — it lags 10–15 minutes, fatal for a copy bot. /activity is the real-time profile feed.

The strategy-plugin framework (src/strategies/)

  • base.js — the Strategy interface. Static metadata (version, title, description, implemented, needs) and optional lifecycle hooks: onStart, onStop, onTick, onWindow(assetKey), onTargetTrade(trade), onOnchainFill(fill), and status(assetKey).
  • registry.js — the catalog of versions (listVersions, createStrategy, defaultVersion, …). Adding a bot = a Strategy subclass + one row.
  • copy.js (v1), momentum.js (v2), and stubs for v3–v5.

The ctx interface

The kernel hands each strategy a ctx object — its only window into the platform. Highlights:

ctx.assets / windowFor() / market(k) / marketByConditionId / marketByTokenId
ctx.price(k) / priceFresh(k) / momentum(k) / openPrice(k) / feed(k)
ctx.watcher() / settings() / cash()
ctx.sizeUsd(targetTrade)                      → $ per the active betting mode
ctx.placeClip(assetKey, side, {usd, reason, refPrice})   → a gated, booked BUY
ctx.sellSide(assetKey, side, {reason})        → mirror an exit
ctx.getBook / bestAsk / bestBid / getMidpoint / log

A strategy never touches feeds, brokers, or the network directly — it reads state and places bets through ctx. That's what makes versions independent and the platform safe to extend.

Data flow (one tick, ~1 s)

  1. Kernel refreshes each asset's active market (cached; forced at window expiry).
  2. Detection events (on-chain / API) route to the active strategy's onOnchainFill / onTargetTrade.
  3. The strategy decides and calls ctx.placeClip / ctx.sellSide.
  4. The kernel runs gates, places the order via the active broker, books it to the active ledger, records slippage/rejects, and emits a fill.
  5. Near close, positions are exited (sell-to-recycle) or held to resolution.
  6. The kernel broadcasts the full state to the dashboard.

Source map

Module Responsibility
src/engine.js The kernel (everything above).
src/strategies/ Version plugins + registry (base, copy, momentum, registry).
src/markets.js Active-market discovery (epoch + series), order books, resolution.
src/spotFeed.js Binance price feed + window-open price + momentum, per asset.
src/targetWatcher.js Target fills via /activity; stance tracking.
src/onchainWatcher.js On-chain CTF transfer detection (BUY in / SELL out).
src/paperBroker.js / liveBroker.js Simulated / real order execution + settlement.
src/clobClient.js CLOB auth + funding/allowance preflight + market orders.
src/scout.js Target Scout + Market Scout (copyability scoring).
src/settings.js Runtime settings store (runtime-config.json).
src/server.js Dashboard WebSocket + HTTP API.
web/ React/Vite dashboard (Version Manager + per-bot views).