Direct Reaction And Dynamic Intelligence System — Low-latency Rust prediction-market trading bot for Kalshi & Polymarket. Nine autonomous Viper strategies, a Raptor recon layer (Price, Funding, Derivatives, Tide "Institutional Pulse", Horizon "TradFi Velocity", and a venue-neutral Sports line-movement scout), a Squadron deployment framework, a CAG async dispatch layer with concurrent multi-asset support, a real-time Next.js Control Tower, and an LLM Advisor (Ollama local/remote, OpenAI-compatible, or Anthropic) that delivers optimization recommendations via Telegram & OpenClaw — and can propose or autonomously apply live config changes under a tiered, guard-railed autonomy policy.
WARNING: This is ALPHA software. You will probably lose money. Start in GHOST mode and tune before going live. Make sure to regularly pull updates as our own LLM advises on config and Viper strategy impls daily.
Public Demo Site: https://demo.dradis.live/
DRADIS is a comprehensive trading automation platform for prediction markets. Built in Rust for maximum concurrency and memory safety, it evaluates selected markets every 50ms, coordinating multiple autonomous strategies to preserve capital and place orders where it sees inefficiencies.
The system is organized around four BSG-inspired tactical layers:
| Layer | Folder | Role |
|---|---|---|
| Raptors | src/raptors/ |
Signal scouts — fetch, normalise, broadcast external data |
| Vipers | src/vipers/ |
Trading strategies — evaluate signals and place orders |
| Squadron | src/squadron/ |
Deployment unit — bundles Raptors + Vipers onto a battle location |
| CAG | src/cag/ |
Commander Air Group — async dispatch, session state, multi-asset orchestration |
# 1. Clone and configure
git clone https://github.com/youruser/dradis.git && cd dradis
cp .env.example .env # fill in POLYMARKET_PRIVATE_KEY, POLYGON_RPC_URL, TELEGRAM tokens, etc.
# If deploying remotely:
cp deploy-multi.sh.example deploy-multi.sh # fill in HOST, USER, KEY
# choose one config profile and copy it into src/config.rs before building
cp src/config.balanced.rs.example src/config.rs # or conservative/aggressive# 2. Select the appropriate venue (builds Rust engine + Control Tower)
# Start Polymarket INTL clob default
./start-local.sh # Intl CLOB, BTC (default)
# Or start Polymarket US API
VENUE=us ./start-local.sh # US Retail venue (us_retail build)
# Or start Kalshi (demo-friendly — see Kalshi configuration below)
VENUE=kalshi ./start-local.sh # Kalshi venue (kalshi build)
# optionally start with verbose logging
RUST_LOG=debug ./start-local.sh # verbose logging
tail -f logs/dradis-local.log
./stop-local.shAfter ~5 minutes the stack is live:
| Service | URL |
|---|---|
| Control Tower | http://<host>:3002 |
| DRADIS REST API | http://<host>:9000/api/health |
| Ollama | http://<host>:11434/api/tags (internal) |
Prerequisites: Docker on the remote host, Rust 1.95+ only needed for local builds.
DRADIS compiles for exactly one execution venue, chosen at build time via a Cargo
feature. All venues share the same strategy/abstraction layers through the venue-neutral
Execution trait (src/venues/core.rs) and the shared OrderLifecycle reconciler
(src/venues/lifecycle.rs); only the venue module differs, so the unused venues'
dependencies are stripped from the binary.
| Feature | Venue | Auth | Gateway |
|---|---|---|---|
intl_clob (default) |
Polymarket International (self-custody) | EOA wallet + EIP-712 over Polygon | clob.polymarket.com |
us_retail |
Polymarket US (custodial, CFTC) | Ed25519 challenge-response → JWT | api.prod.polymarketexchange.com |
kalshi |
Kalshi (custodial, CFTC) | RSA-PSS request signing | external-api.kalshi.com (demo: external-api.demo.kalshi.co) |
# Polymarket Intl CLOB (default)
./start-local.sh # BTC
./start-local.sh eth # ETH
# Polymarket US Retail
VENUE=us ./start-local.sh
# Kalshi
VENUE=kalshi ./start-local.sh# International CLOB (default)
cargo build --release
cargo test
# US Retail
cargo build --release --no-default-features --features us_retail
cargo test --no-default-features --features us_retail
# Kalshi
cargo build --release --no-default-features --features kalshi
cargo test --no-default-features --features kalshiPOLYMARKET_US_KEY_ID=<key-id-uuid> # developer-portal Key ID (X-PM-Access-Key)
POLYMARKET_US_SECRET_KEY=<base64-secret> # portal Secret Key (Base64 Ed25519 keypair), shown once
# optional:
POLYMARKET_US_BASE_URL=https://api.prod.polymarketexchange.com # override (staging/mock)
POLYMARKET_US_TRADE_SIZE=10 # contracts per leg (default 10)
POLYMARKET_US_ARB_EDGE=0.02 # min risk-free edge per pair (default $0.02)
POLYMARKET_US_MARKET_FILTER=chiefs # optional slug/question substring to pick a market
ASSETS=us # keep the dashboard pool tidy (US data lives in logs/us-dradis.db)Polymarket US Retail status: the MVP loop (
src/venues/us/trader.rs) runs the venue-agnostic arbitrage strategy — discover a binary market → stream both legs over WebSocket → buyYES+NOfor < $1 via an engine-atomic batched order (/v1/orders/batched) → reconcile viaOrderLifecycle. Open positions and portfolio P&L appear in the Control Tower under theusasset selector. The Control Tower API stays live on:9000regardless. A second crypto wing (us-cryptoasset) hunts crypto-class markets with the full Raptor stack, so all nine Vipers fly on them.
Kalshi signs every request locally with RSA-PSS — create an API key in your account settings (Key ID + downloadable RSA private key PEM, shown once).
Try it risk-free on the demo exchange — demo.kalshi.co is a full paper-trading environment with play money and the same live crypto markets; demo credentials are separate from production.
KALSHI_API_KEY_ID=<key-id-uuid> # from account settings (REQUIRED)
KALSHI_PRIVATE_KEY_PATH=data/kalshi-key.pem # downloaded PEM (REQUIRED; or KALSHI_PRIVATE_KEY=<pem contents>)
KALSHI_DEMO=1 # 1 = demo.kalshi.co paper trading, unset = production
# optional:
KALSHI_SERIES=KXBTC15M,KXBTCD,KXETH15M,KXETHD # crypto series to hunt (default shown)
KALSHI_MARKET_FILTER=bitcoin # optional ticker/title substring to pick a market
ASSETS=kalshi # keep the dashboard pool tidy (data in logs/kalshi-dradis.db)Kalshi status: the loop (
src/venues/kalshi/trader.rs) is crypto-first — it discovers the hottest open market across the configured series (15-minute and hourly BTC/ETH by default), classifies it via the shared taxonomy, and flies all nine Vipers with the full Raptor intelligence stack. Order books stream over the authenticated WebSocket (orderbook_deltawith sequence-gap recovery) and fills confirm event-precisely via the privatefillchannel. Kalshi's quadratic taker fee (max 1.75¢/contract at P=0.50) is priced into Viper edge thresholds. Positions and P&L appear under thekalshiasset selector.
┌─────────────────────────────────────────────────────────────────────┐
│ src/ layout │
│ │
│ raptors/ ← Signal scouts (Binance WS + FAPI, The Odds API)│
│ vipers/ ← Trading strategies (8 Vipers) │
│ squadron/ ← Deployment layer (Raptor+Viper+Market bundle) │
│ cag/ ← Commander (async dispatch, multi-asset) │
│ orchestrator/ ← Strategy trait, registry, executor │
│ tasks/ ← Market monitor, cleanup, chain-sync │
│ helpers/ ← DB, orders, balance, metrics, notifications │
│ api/ ← axum REST server (:9000) │
└─────────────────────────────────────────────────────────────────────┘
┌──────────────────────┐ ┌──────────────────────┐
│ src/raptors/ │ │ Polymarket CLOB │
│ Price Raptor │ │ (WebSocket Feed) │
│ (Binance Spot WS) │ │ │
│ Funding Raptor │ │ │
│ (Binance FAPI REST) │ │ │
│ Derivatives Raptor │ │ │
│ (Binance FAPI: OI) │ │ │
│ Tide Raptor │ │ │
│ (Alpaca IEX + iNAV) │ │ │
│ Horizon Raptor │ │ │
│ (SPY/QQQ/UVXY) │ │ │
│ Sports Raptor │ │ │
│ (The Odds API) │ │ │
└──────────┬───────────┘ └───────────┬──────────┘
│ watch channels │ orderbook WS
└─────────────┬─────────────┘
▼
┌─────────────────────────┐
│ src/cag/ │ ← CAG (Commander Air Group)
│ run_market_loop() │ ← one tokio task per asset
│ SessionState │ ← per-asset P&L + collateral
└─────────────┬───────────┘
│ (BTC task) (ETH task) (SOL task) …
▼
┌─────────────────────────┐
│ src/squadron/ │
│ Squadron descriptor │ ← SquadronRaptors (signal bundle)
│ (battle location + │ ← SquadronConfig (which Vipers fly)
│ Raptor+Viper bundle) │ ← SquadronState (STAGED→PATROLLING→RTB)
└─────────────┬───────────┘
▼
┌─────────────────────────┐
│ Orchestrator (CIC) │◄──── axum REST API (:9000)
│ 50ms Heartbeat │
└─────────────┬───────────┘
│ parallel dispatch
┌─────────────┼───────────────┬───────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌───────────────┐ ┌────────────┐ ┌──────────────┐
│ Momentum/ │ │ Maker │ │ Arbitrage / │ │ GBoost │ │ TrendCapture │
│ FairValue │ │ Viper │ │ TimeDecay / │ │ Viper │ │ Viper │
│ Viper │ │ │ │ Basis Vipers │ │ (ML) │ │ (drift/trend)│
└──────┬─────┘ └────┬─────┘ └──────┬────────┘ └─────┬──────┘ └──────┬───────┘
└────────────┼──────────────┴────────────────┴───────────────┘
▼
┌───────────────────────┐
│ Execution Layer │
│ OBI Gate · Fee Gate │
│ Circuit Breaker │
└───────────────────────┘
┌───────────────────────┐
│ Control Tower UI │ Next.js dashboard (:3002)
│ Viper toggles │ ◄── PATCH /api/config
│ P&L chart │ ◄── GET /api/pnl/history
│ Open Positions │ ◄── GET /api/positions
│ Trade log │ ◄── GET /api/trades
└───────────────────────┘
┌───────────────────────┐ ┌────────────────┐
│ LLM Advisor │────►│ Ollama API │
│ (background task) │ │ (your model) │
└──────────┬────────────┘ └────────────────┘
▼
┌───────────────────────┐
│ Telegram Channel │
└───────────────────────┘
- Parallel Dispatch: Every 50ms heartbeat, the CIC evaluates all registered Vipers concurrently.
- Isolated budgets: Each Viper has its own independent capital budget and position book — a loss in one sector can't drain another's fuel.
- Multi-asset concurrency: Each asset runs in its own
tokio::spawned task with independent raptors and session state. The tokio runtime sizes its worker pool to the host's core count (floor 2) to avoid oversubscribing small instances; setTOKIO_WORKER_THREADSto raise it for multi-asset boxes (e.g. BTC + ETH + SOL on a 4+ vCPU host). Blocking work runs on the dedicatedspawn_blockingpool, so matching workers to cores is the correct configuration. - OS-thread watchdog: A native OS thread (outside the tokio runtime) checks an atomic heartbeat every 60 s. If the trading loop goes silent for 5 minutes, it calls
process::exit(1)to trigger Docker's restart policy — immune to tokio runtime deadlocks. - OBI Veto: A built-in Order Book Imbalance gate at −0.60 blocks entries into toxic flow / distribution walls.
- Strategy Timeout: Each Viper evaluation is hard-capped at 500ms. A hung Viper is skipped for that tick — the engine never freezes.
- REST API: axum server on
:9000exposes live config, P&L, positions, and trade history to the Control Tower.
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | Liveness check |
/api/assets |
GET | List initialized asset pools |
/api/config |
GET | Current DynamicConfig as JSON |
/api/config |
PATCH | JSON merge-patch — hot-reloads strategies |
/api/config/schema |
GET | Editable-config field schema |
/api/pnl/history |
GET | Recent P&L snapshots |
/api/trades |
GET | Recent completed trades |
/api/positions |
GET | Current open positions |
/api/squadrons |
GET | List all active squadrons |
/api/squadrons/{id} |
GET | Get one squadron by id |
/api/squadrons/{id}/config |
GET/PATCH | Squadron-specific config |
/api/squadrons/deploy |
POST | Queue a new squadron deployment |
/api/deployments |
GET | List deployment queue status |
/api/deployment/region |
GET | Region + available market types |
/api/markets/available |
GET | Fetch markets by type from Gamma API |
/api/taxonomy/raptors |
GET | Raptor kinds for market class |
/api/taxonomy/vipers |
GET | Viper kinds for market class |
/api/telemetry |
GET | Live Raptor signal snapshots |
/api/llm/recommendations |
GET | Recent LLM Advisor analyses |
/api/llm/actions |
GET | AI config-change audit trail (proposed/applied/rejected/…) |
/api/llm/actions/{id}/approve |
POST | Approve a proposed AI change (revalidated, then applied) |
/api/llm/actions/{id}/reject |
POST | Reject a proposed AI change |
/api/setup/autonomy |
GET/PUT | AI autonomy tier, kill switch, breaker reset (admin-gated) |
/api/setup/export |
GET | Download portable config bundle — secrets + global/squadron configs (admin-gated) |
/api/setup/import |
POST | Restore a config bundle on a new instance; restart applies (admin-gated) |
All data endpoints accept ?asset=btc query param to scope to a specific asset pool.
Raptors are DRADIS's recon layer — lightweight signal scouts that fly ahead of the Vipers and report external intelligence back to the CIC. Each Raptor polls a specific data source on its own schedule and publishes a normalized signal via watch channels.
Raptors are intentionally dumb: fetch, normalize, broadcast — no trading logic, no position awareness, no side effects.
| Raptor | Source | Signal | Module |
|---|---|---|---|
| Price Raptor | Binance Spot WS | spot price, 5s/1s velocity, acceleration, 10m/60m drift | src/raptors/price.rs |
| Funding Raptor | Binance Perpetuals FAPI | Perpetual funding rate (smart-money sentiment) | src/raptors/funding.rs |
| Derivatives Raptor | Binance Perpetuals FAPI | Open-interest delta + taker CVD ratio (positioning pressure, all-asset) | src/raptors/derivatives.rs |
| Tide Raptor | Alpaca IEX + synthetic iNAV | "Institutional Pulse" + coherence from spot-BTC-ETF (IBIT/FBTC/ARKB) premium vs iNAV — BTC-only, US-hours | src/raptors/tide.rs |
| Horizon Raptor | Alpaca IEX (shared) | TradFi velocity (SPY/QQQ), macro coherence (BTC↔QQQ), VIX proxy (UVXY) — BTC-only, US-hours | src/raptors/horizon.rs |
| Sports Raptor | The Odds API (h2h) | Vig-free consensus probability, line drift, book dispersion — venue-neutral (US + intl), observe-only | src/raptors/sports.rs |
| (future) Politics Raptor | Polling aggregators | Approval drift, event probability shifts | — |
When multiple Raptors are active, the GBoost Viper fuses every signal as model features (funding, OI/CVD, institutional pulse/coherence, TradFi velocity/VIX); Basis, Momentum and TrendCapture use them as confirmation gates; Maker and TrendCapture consume the Horizon macro signal as preventative gates (VIX-spike / coherent-TradFi-flow quote suppression, fade veto — observe-first, enforcement behind config flags); and the Convergence Viper opens directional positions only when the institutional + derivatives stack agrees. No single Raptor has veto power alone.
The Tide and Horizon Raptors share a single Alpaca IEX WebSocket connection (free tier allows only one per account). Tide tracks BTC-specific institutional flow (ETF premium); Horizon tracks TradFi macro regime (equity velocity, VIX). Together they enable divergence detection — e.g., equities selling off but BTC ETFs at premium suggests institutional flight into crypto.
The Sports Raptor is the first non-crypto scout: a single venue-neutral instance shared by both the US and intl pipelines. It polls The Odds API (keyed on ODDS_API_KEY), reduces the nearest-commencing event's cross-book moneyline to a vig-free consensus, and broadcasts line drift + book dispersion. It runs observe-only — it publishes telemetry but no Viper consumes it for sizing yet — and degrades silently to a neutral snapshot when no API key is set.
Nine specialized Viper strategy classes. Each Viper is an autonomous tactical unit with its own capital budget, position book, and entry/exit logic.
| Viper | Venue | Description |
|---|---|---|
| Momentum | Hourly | Detects high-velocity Binance moves and strikes Polymarket before it reprices |
| Maker | Window | Dual-sided passive bids on YES+NO, capturing the spread while managing net exposure |
| Arbitrage | Window/Daily | Buys both YES+NO when combined asks are < $1.00 (net of fees) |
| Time Decay | Hourly | Posts resting GTC maker bids during the theta window; settles at $1.00 at 0% fee |
| Basis | Window | Fades retail skew using Binance funding rates as smart-money confirmation |
| GBoost | Window/Daily | Online gradient-boosted ML model retraining continuously on live orderbook + Raptor features |
| TrendCapture | Window/Daily | Exploits sustained multi-minute oracle drift (10m + 60m) before Polymarket reprices; Kelly-fractional sizing, OBI veto, trend-reversal exit |
| FairValue | Window/Daily | Compare fair value of asset, compare market ask, enter when discount exceeds margin |
| Convergence | Hourly | Macro-conviction directional Viper — opens YES/NO only when the Tide institutional pulse, Derivatives CVD, and OI all agree on a direction. BTC-only, US-cash-hours-only, fixed tiny size |
Build your own: CUSTOM_STRATEGY.md.
A Squadron is the core deployable unit — it bundles Raptors with Vipers and sends them to a specific Polymarket market (the battle location).
Squadron
├── Battle Location → MarketConfig (yes/no tokens, expiry, fees)
├── SquadronRaptors → typed bundle of Raptor watch::Receiver handles
├── SquadronConfig → RaptorProfile + ViperProfile composition spec
└── SquadronState → STAGED → DEPLOYED → PATROLLING → RTB → STOOD_DOWN
Markets are classified into domains that determine which Raptors and Vipers are meaningful:
| Market Class | Raptors | Vipers |
|---|---|---|
crypto |
Price, Funding, Derivatives, Tide | All nine Vipers |
sports |
Sports (line movement) | Arbitrage, Maker (venue-agnostic) |
politics |
Politics (roadmap) | Arbitrage, Maker (venue-agnostic) |
Classification is data-driven via the market_class_rule table — add a new mapping (e.g., tennis → sports) with one INSERT, no code change.
| Preset | Raptors | Vipers |
|---|---|---|
full_wing |
Price + Funding + Derivatives + Tide | All nine Vipers (current default) |
momentum_only |
Price only | Momentum + GBoost |
arb_wing |
Price + Funding | Arbitrage + Basis |
| State | Meaning |
|---|---|
STAGED |
Assembled, waiting for a battle location (user-deployed via UI) |
DEPLOYED |
Market acquired, WS subscriptions live |
PATROLLING |
Active trading tick loop running |
RTB |
Returning to base — no new entries, winding down |
STOOD_DOWN |
Market expired or manually stood down |
Each market rotation logs: ️ Squadron [btc-hourly-2026-05-23T14:00:00Z] → state=PATROLLING
The Commander Air Group is the async orchestration layer that sits between main.rs and the Squadron/Orchestrator. It owns the market rotation loop for each asset and manages session-level state.
CAG
├── Cag → global registry (shared across all asset tasks)
├── SessionState → per-asset P&L, starting/live collateral, position tracking
├── RunArgs<P> → typed bundle passed into each concurrent market-loop task
└── run_market_loop → async fn — the full patrol loop for one asset
Set ASSETS=btc,eth,sol to run three independent patrol loops in parallel. Each asset gets its own:
- Price Raptor + Funding Raptor (watch channels)
SessionState(isolated P&L and collateral tracking)- LLM Advisor background task
tokio::spawnedrun_market_looptask
Shared across all assets: trading_client, nonce_manager, wallet_provider, CAG registry, DynamicConfig watch channel, axum API server.
# .env — multi-asset (BTC + ETH + SOL in parallel)
ASSETS=btc,eth,sol
# .env — single-asset fallback (backward-compatible)
CRYPTO_FILTER=btcEach asset owns its own SQLite DB file (
logs/btc-dradis.db,logs/eth-dradis.db, etc.). The primary asset (first inASSETS) also backs the default REST API view; pass?asset=ethquery params to scope API responses to a specific asset pool.
DRADIS ships with a real-time web dashboard called Control Tower built on Next.js 15 + Tailwind CSS.
| Panel | What it shows |
|---|---|
| Status Bar | Engine online/offline, GHOST mode badge, active market, current BTC price, session P&L |
| P&L Chart | Rolling equity curve across recent snapshots |
| Viper Cards | Live enabled/disabled toggle + all parameters editable inline without a restart |
| Open Positions | In-flight positions with entry time, side (YES/NO/UP/DOWN in correct color), entry price, shares |
| Telemetry | Live Raptor macro cards — Tide (ETF premium, institutional pulse), Horizon (TradFi velocity, VIX proxy), greyed outside US market hours |
| Trade Log | Last N completed trades with strategy, side, entry/exit prices, shares, P&L, exit reason |
| CAG Registry | Active squadrons with market, state, deployed time, and + Deploy button |
| AI Actions | Full audit trail of LLM-proposed config changes — status lifecycle, delta %, tier, outcome score — with inline apply/reject for pending proposals |
| Setup | Admin-gated credential management — venue keys, RPC, Alpaca, Telegram — with test-connection buttons, one-click engine restart, and the AI Autonomy panel (tier selector, kill switch, circuit-breaker reset) |
Every parameter in the Viper cards maps directly to the runtime DynamicConfig. Editing a value sends PATCH /api/config — no restart required. Changes take effect on the next 50ms tick.
Hot-Enable Design — All nine Vipers are always instantiated at startup. The
DynamicConfigenable flags are the sole runtime gate. Toggle any Viper on or off during a live session with immediate effect.
The Setup tab lets you configure DRADIS entirely from the browser — designed for prosumer deployments (e.g. a prebuilt AWS image) where editing .env on the server isn't practical.
- First boot: if no admin password exists, the tab shows a first-boot wizard — create the password, enter venue credentials, restart.
- Admin gate: setup routes require a login (argon2-hashed password, 24h HMAC session tokens); the rest of the dashboard is unaffected. Already protected by
CT_USERNAME/CT_PASSWORD+DRADIS_API_KEY? SetDRADIS_SETUP_AUTH=offto skip the second password. - Write-only fields: the API never returns stored secrets — only a "set / …last4" hint.
- Test buttons: validate credentials live before saving (intl wallet → full CLOB auth + Safe derivation; Polygon RPC →
eth_blockNumber; Alpaca → data probe; Telegram →getMe). - Storage: saved to
$DRADIS_DATA_DIR/secrets.envon the data volume; it overrides container env on boot, so values survive container recreation. Restart engine applies them (Docker respawns the process).
The + Deploy button in the CAG Registry panel opens the Squadron Builder modal — craft custom squadrons with market type selection, raptor/viper configuration, and regional deployment restrictions.
| Mode | Description |
|---|---|
| Quick Deploy | Select market type (crypto/sports/politics) → DRADIS auto-selects the highest-liquidity market and optimal raptors/vipers |
| Full Control | Browse available markets, manually select raptors and vipers, see implementation status badges |
Regional restrictions:
| Deployment | Squadron Builder Market Types | Notes |
|---|---|---|
US (us_retail) |
Politics, Sports | Crypto runs as an auto-managed wing (us-crypto squadron) — deployed by the trader loop, not the builder |
Kalshi (kalshi) |
Crypto | Kalshi lists sports/politics too, but DRADIS's Kalshi loop is crypto-first (15-min/hourly ladders) |
INTL (intl_clob) |
Politics, Sports, Crypto |
Deployment flow:
User → "+ Deploy" → Modal → POST /api/squadrons/deploy
↓
deployment_queue (pending)
↓
Admiral Adama processor (5s poll)
↓
CAG.register_staged_deployment() → STAGED in UI
Staged squadrons appear in the CAG Registry. The auto-discovery loops for crypto assets (BTC/ETH/SOL) adopt staged deployments on their next market rotation.
# .env (production)
CT_USERNAME=starbuck
CT_PASSWORD=your-strong-passwordOptional background task. Every LLM_ADVISOR_INTERVAL_SECS (default: 30 min) it fetches recent trades from SQLite, analyzes them with an LLM, and posts plain-English optimization recommendations to Telegram. Defaults to a local Ollama model; remote providers are supported via env vars.
// src/config.rs
pub const ENABLE_LLM_ADVISOR: bool = true;
pub const LLM_ADVISOR_INTERVAL_SECS: u64 = 1800;
pub const LLM_ADVISOR_TRADES_LOOKBACK: i64 = 20;
pub const LLM_PROVIDER: &str = "ollama";
pub const LLM_OLLAMA_URL: &str = "http://localhost:11434";
pub const LLM_OLLAMA_MODEL: &str = "llama3.2";# Ollama (default) — override at runtime without rebuilding
OLLAMA_URL=http://192.168.1.10:11434
OLLAMA_MODEL=mistral
# Any OpenAI-compatible provider (OpenAI, Groq, Together, OpenRouter, vLLM, LM Studio…)
LLM_PROVIDER=openai
LLM_API_BASE=https://api.openai.com/v1 # optional; default shown
LLM_API_KEY=sk-... # env only — never persisted or logged
LLM_MODEL=gpt-4o-mini
# Anthropic
LLM_PROVIDER=anthropic
LLM_API_KEY=sk-ant-...
LLM_MODEL=claude-haiku-4-5Beyond prose recommendations, the advisor appends a machine-readable block of
proposed DynamicConfig changes to each analysis. Every proposal is validated
against the config schema (exact keys, type coercion, min/max clamping, max 4
per cycle), recorded in the llm_actions audit table, and TTL-bound (30 min —
stale advice never applies). What happens next depends on the autonomy tier,
set live from Setup → AI Autonomy (no restart):
| Tier | Name | Behaviour |
|---|---|---|
| 1 | Recommend | Nothing auto-applies. Proposals queue in the dashboard; a human presses apply (revalidated against the current config first) or reject. |
| 2 | Limited | Safe changes apply immediately: schema-clamped, per-field delta capped (±20% default), rate-limited (1 batch/hour default), never money fields (*_usdc, budgets, collateral). Everything else queues for approval. |
| 3 | Autonomous | The AI applies its changes directly (still schema-clamped; ghost_mode flips always require a human). |
Guardrails at every tier:
- Kill switch — one click in Setup (or
LLM_AUTONOMY_KILL=1) forces recommend-only. - Circuit breaker — if session P&L draws down past
LLM_BREAKER_DRAWDOWN_USDC(default $25) within the watch window after an auto-apply, all recent AI changes are reverted via their stored inverse patches, autonomy is demoted to tier 1 until an operator resets it, and a Telegram alert fires. - Full audit trail — the AI Actions tab shows every proposal's lifecycle
(
proposed → applied / rejected / expired / reverted / failed), and each applied change is outcome-scored (session-P&L delta afterLLM_OUTCOME_HORIZON_SECS, default 2h). Rejections, reverts, and scores are injected back into future prompts as few-shot examples, so the model learns from its own track record.
All tiers run identically in LIVE and GHOST mode (each action is stamped with the mode), so you can audition tier 2/3 behaviour risk-free in ghost first.
# Autonomy knobs (.env — all optional, shown with defaults)
LLM_AUTONOMY_TIER=1 # 1 recommend / 2 limited / 3 autonomous
LLM_AUTONOMY_KILL=0 # 1 = hard stop for all auto-applies
LLM_MAX_PATCHES_PER_HOUR=1 # tier-2 rate limit (applied batches/hour)
LLM_MAX_DELTA_PCT=0.20 # tier-2 per-field relative delta cap
LLM_BREAKER_DRAWDOWN_USDC=25.0 # P&L drawdown that trips the breaker
LLM_BREAKER_WINDOW_SECS=14400 # how far back applied changes are watched
LLM_OUTCOME_HORIZON_SECS=7200 # when applied changes get outcome-scored- Circuit breaker: Pauses all trading after 3 consecutive execution failures.
- TOCTOU-safe entry: Atomic lock scope prevents duplicate orders.
- Orphaned pair detection: Arbiter waits 5s after first-leg confirm before acting on a missing second leg. TimeDecay GTC bids are given the full theta window (up to 30 min) before a resting order is declared orphaned.
- Rescue-profit gate: Arbitrage entries are blocked when a single-leg failure cannot be rescued into profit (
yes_rescue_costorno_rescue_cost ≥ $1.00including fees and rehedge buffer). - Fee Gates: Blocks Taker Vipers from entering high-fee (10%+) markets.
- AI autonomy guardrails: LLM-authored config changes are schema-clamped at every tier, money fields never auto-apply below full autonomy, and a P&L circuit breaker reverts recent AI changes and demotes to recommend-only on a drawdown (see LLM Advisor).
- Chain-sync: Startup and periodic reconciliation against on-chain wallet state — stale DB rows purged, missing positions re-adopted with correct side labels.
This is experimental software. You will probably lose money. Start in GHOST mode and tune.
- Risk: Momentum trades are directional and can get whiplashed. Arbitrage spreads are thin. None of this is guaranteed profit.
- US Citizens: Polymarket is rolling out US access under CFTC regulation via a waitlist.
- Competition: Polymarket is full of well-funded, low-latency bots. This project is a learning exercise, not an edge.
All builds:
- Rust 1.95+ (or Docker)
- Telegram bot token (optional)
- Alpaca API key/secret (optional — free tier; powers both Tide and Horizon Raptors from one connection. Without it both cards stay idle.)
- The Odds API key (optional — free tier; only needed for the Sports Raptor's line-movement feed. Without it the Sports Raptor pill stays idle.)
Polymarket International build (intl_clob) only:
- A Polygon wallet with USDC and MATIC
- A paid Polygon RPC endpoint (required for auto-settlement)
Polymarket US Retail build (us_retail) only:
- Polymarket US developer-portal API key (Key ID + Ed25519 Secret Key) — no wallet or RPC needed
Kalshi build (kalshi) only:
- Kalshi API key (Key ID + RSA private key PEM) — no wallet or RPC needed; start with demo.kalshi.co paper trading
The Tide and Horizon Raptors share a single Alpaca IEX WebSocket connection (free tier allows only one per account). Together they stream 6 symbols:
| Raptor | Symbols | Signal |
|---|---|---|
| Tide | IBIT, FBTC, ARKB | BTC ETF premium vs synthetic iNAV → "Institutional Pulse" |
| Horizon | SPY, QQQ, UVXY | TradFi velocity, macro coherence (BTC↔QQQ), VIX proxy |
Both are BTC-only and active during US market hours (09:30–16:00 ET). To enable them, add your Alpaca keys to .env:
ALPACA_API_KEY_ID=your-key-id
ALPACA_API_SECRET_KEY=your-secret-keyTide feeds the GBoost feature vector, the Basis tide veto, and the Convergence Viper. Horizon feeds the GBoost feature vector (TradFi velocity, macro coherence, VIX proxy/velocity) and drives preventative gates on Maker (VIX-spike / coherent-TradFi-flow quote suppression) and TrendCapture (fade veto when TradFi confirms the drift) — the gates run observe-first and enforce once calibrated (MAKER_HORIZON_GATE_ENFORCE, TRENDREVERSAL_HORIZON_VETO_ENFORCE). Omit the keys and both run idle (neutral snapshots, offline pills).
The Sports Raptor is a venue-neutral, observe-only scout shared by both the US
and intl pipelines. It polls The Odds API (free tier),
reduces the nearest-commencing event's cross-book moneyline to a vig-free consensus
probability, and broadcasts line drift (movement since the previous poll) and
book dispersion (soft-line disagreement). To enable it, add your key to .env:
ODDS_API_KEY=your-the-odds-api-keyThe free tier is a hard ~500 requests/month, so the raptor polls conservatively
every 2 hours (~360 requests/month, leaving headroom). It publishes telemetry only
— no Viper consumes it for sizing yet. The remaining monthly budget is logged each
poll (from the API's x-requests-remaining header), with a loud warning when it
runs low. Omit the key and it runs idle (neutral snapshot, offline pill).
Recommended: Alchemy, QuickNode, Infura
POLYGON_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/YOUR_API_KEYsrc/config.rs is gitignored. Copy one of the provided examples before building:
| Profile | File | Wallet | Risk | Vipers |
|---|---|---|---|---|
| Conservative | src/config.conservative.rs.example |
< $100 | Low | Maker, Time Decay |
| Balanced | src/config.balanced.rs.example |
$100–$300 | Medium | All nine |
| Aggressive | src/config.aggressive.rs.example |
$200+ | High | All nine |
cp src/config.balanced.rs.example src/config.rs
cargo build --releasecp .env.example .env
cp src/config.balanced.rs.example src/config.rs
# Intl CLOB (default) — BTC
./start-local.sh
# Intl CLOB — specific asset
./start-local.sh eth
# US Retail venue
VENUE=us ./start-local.sh
# Kalshi venue
VENUE=kalshi ./start-local.sh
tail -f logs/dradis-local.log
./stop-local.sh# .env — run BTC, ETH, and SOL loops concurrently
ASSETS=btc,eth,sol
# Each asset gets its own SQLite DB file:
# logs/btc-dradis.db (primary — default REST API / Control Tower view)
# logs/eth-dradis.db
# logs/sol-dradis.db
# Use ?asset=eth on API endpoints to scope responses to a specific asset.Log filtering:
tail -f logs/dradis-local.log | grep -i "trade\|entry\|exit" # trades
tail -f logs/dradis-local.log | grep "Squadron" # deployment lifecycle
tail -f logs/dradis-local.log | grep "btc\|eth\|sol" # per-asset activity
tail -f logs/dradis-local.log | grep -E "WARN|ERROR" # problems./deploy-multi.shDashboard: http://YOUR_SERVER_IP:3002
API health: http://YOUR_SERVER_IP:9000/api/health
openclaw skills install dradis-tactical-command| You say | Effect |
|---|---|
| "Pause GBoost" | Stops GBoost entries on next tick |
| "Enable ghost mode" | Switches to paper trading instantly |
| "What's my P&L today?" | Returns session profit/loss |
| "Show open positions" | Lists all in-flight positions |
| "Tighten GBoost stop loss to 8%" | Updates risk parameter live |
# .env — enables API key enforcement for OpenClaw
DRADIS_API_KEY=replace-with-a-strong-random-secretWhy Rust? Fearless concurrency — evaluating nine Vipers every 50ms needs a multi-threaded runtime with no GIL or GC pauses.
Can I trade multiple assets at once? Yes — set ASSETS=btc,eth,sol in .env. Each asset runs its own independent patrol loop (raptors, session state, LLM advisor, SQLite DB) inside a tokio::spawned task. The wallet, CLOB client, and API server are shared. Each asset writes to its own DB file (logs/btc-dradis.db, logs/eth-dradis.db, etc.); pass ?asset=eth to any API endpoint to scope results to that asset.
Why isn't the bot trading? Check: (1) GHOST_MODE true? (2) High-fee market? (3) Thresholds too tight in config.rs? (4) No Window/Daily market for Maker/Arb/Basis?
I see two Vipers on the same token — is that a bug? No. Each Viper has its own independent position book.
How do I adjust risk live? Use the Control Tower Viper cards or PATCH /api/config. No restart needed.
GBoost producing garbage after an update? The model file is incompatible across feature vector changes. Delete old files and let it cold-start:
rm -f logs/gboost_model_*.jsonThe safe pattern: bump the suffix in GBOOST_MODEL_PATH (e.g. v14f → v15f) when adding a new feature in src/vipers/gboost_impl.rs.
Can I enable a Viper mid-session? Yes — all nine are always instantiated. Toggle via Control Tower or PATCH /api/config. Takes effect on the next 50ms tick.
Does DRADIS support the US Polymarket API? Yes. Polymarket's US platform is a separate, custodial, CFTC-regulated exchange with web2 auth (API key / secret / session token) and string/UUID market IDs. We have venue abstraction so a build targets one venue via a Cargo feature flag (intl_clob default, us_retail, kalshi) — single-venue per binary, so the US deployment carries none of the Polygon crypto weight and stays inside its own regulatory/network footprint. Start a US build with VENUE=us ./start-local.sh.
What about Kalshi? Fully supported. Build with --features kalshi (or VENUE=kalshi ./start-local.sh) — RSA-PSS signed REST + WebSocket, crypto-first trading loop over Kalshi's 15-minute and hourly BTC/ETH series, all nine Vipers with the full Raptor stack, and event-precise fill confirmation. Paper-trade it risk-free against demo.kalshi.co with KALSHI_DEMO=1. See "Kalshi configuration" above.
Control Tower shows "Offline"? Check: (1) DRADIS running? (2) curl http://localhost:9000/api/health? (3) Docker — same dradis-net network?
How can I tune my instance for maximum performance? Please see our dedicated performance tuning guide: PERFORMANCE_TUNING.md.
How do I enable the LLM Advisor?
ollama pull llama3.2ENABLE_LLM_ADVISOR = trueinconfig.rscargo build --release- Set
TELEGRAM_BOT_TOKEN+TELEGRAM_CHAT_IDin.env
Why doesn't DRADIS include a backtesting framework?
| Concern | Backtester | Ghost Mode |
|---|---|---|
| Market data fidelity | Requires storing full L2 orderbook snapshots | Real-time Polymarket CLOB — 100% authentic |
| Strategy fidelity | Must mock async execution, cooldown maps, drawdown guards | Full production code path runs unchanged |
| Fill simulation | Assumes fills that may never occur in thin markets | No fills in ghost — no wishful thinking |
| Build/maintain cost | Significant | Zero — GHOST_MODE = true in config.rs |
Workflow: ghost overnight → tools/session_parser.py → tune config.rs → repeat until positive expectancy.
