Skip to content

Latest commit

 

History

442 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multivenue Trading Engine

License Rust Python

Pure-Rust, zero-allocation, zero-copy, single-writer, lock-free HFT engine that executes systematic strategies across a multivenue universe — Binance spot/USDM, OKX, Deribit, Hyperliquid, Bybit, MEXC (data-only), Polymarket's CLOB and Polygon RPC, plus a boot-selected options ladder.

Strategies are composed at boot from a slot set (AI-executed intents, the ruleset VM, the intrabar candle member) and are free to trade any subset of that universe. Polymarket is one venue among several, not the target: a strategy may use it, ignore it, or trade purely between the crypto venues. The original Polymarket latency-arbitrage strategy still exists in-tree but is disabled at boot.

v1 runs locally on a MacBook Pro M4 on free-tier external APIs only. Phase 7 migrates to a plain Linux EC2 box — no cloud services, no observability stack, no IaC, at any phase.

Claude (via the claude-worker Python process) is an offline strategy researcher — it proposes rulesets, backtests them and stages them through an HMAC'd UDS command plane. It is never in the hot path.

Status (2026-09-19)

Lane State
Engine + capture (Stage 1–2, M1–M6, VM2, venue-time v3) CLOSED — MVP complete 2026-09-02
Regime + dashboard, S3 cold archive, ICDP, XSD, VRP, BIN15 lanes CLOSED / live in paper
Real execution E1–E6 (per-slot routing, HL signer + arm, risk gate, kill switches) LANDED, reviewed + re-tested in E7 (2026-09-19)
E7 — the ramp TESTNET first (operator-gated R0); mainnet is a later ruling
Stage 3 — AI-promoted members live GATED on the Stage-3 entry gate (waived for BIN15 only)
MEXC — the seventh market-data venue (MX0–MX9, docs/mexc-ingress-plan.md) LANDED 2026-09-23, data-only — captured once [mexc] is in the boot universe

Gates at HEAD: 2585 nextest · 62/62 alloc assertions at 0 B/op · clippy clean · make copy-audit new=0 · 1153 worker pytest. CLAUDE.md carries the authoritative CURRENT STATE and the standing laws.

Start here

Quick start

# 1. Secrets  (.env only — chmod 600, git-ignored, never printed)
cp .env.example .env && chmod 600 .env
$EDITOR .env

# 2. Universe  (M1: the boot universe is a file, not flags)
cp universe.toml.example ~/multivenue/universe.toml
$EDITOR ~/multivenue/universe.toml

# 3. Build  (G0 law: test gates never relink the release binary —
#    always build -p cli before a live boot)
cargo build --release -p cli

# 4. Tests
cargo nextest run --workspace
cargo test -p bench --test alloc_assertions --release -- --test-threads=1   # MUST show 0 B/op
cd claude-worker && uv run pytest

# 5. Paper-mode run — zero flags, universe comes from the file
cargo run --release -p cli -- run --paper --strategy ai

Polymarket crypto up/down dailies expire 16:00Z — refresh universe.toml via the Gamma lane before a manual boot (the M3 launchd fleet automates this). After a restart, run claude-worker fetch once; unresolved=0 is the done-tell.

Legacy fallback (no universe.toml): per-venue flags are required — --polymarket-asset-id <token id> --okx-symbols … --deribit-symbols … --hl-coins …. Boot refuses to start venue-blind.

Engine subcommands

multivenue-engine run --paper --strategy ai         # spawn ingress + engine, drain until SIGINT
multivenue-engine run --strategy ai+vrp+xsd+bin15 --exec ~/multivenue/exec.toml --arm-live 3   # E7: arm ONE slot (testnet first)
multivenue-engine print-config --env-file ./.env    # resolved non-secret config; smoke-tests the loader
multivenue-engine audit-replay  --dir <run dir>     # per-symbol rates, cadence bands, integrity, venue×channel matrix
multivenue-engine capture-catalog --dir <log root>  # per-run spans, UTC-day continuity, gap map, backtest/monitor views
multivenue-engine backtest --ruleset R --replay-dir D --split 70/30   # deterministic VM replay; schema-1 JSON on stdout
multivenue-engine audit-pnl --dir <log root>        # shadow P&L: logged intents through the strict-cross fill model
multivenue-engine exec-smoke [--lifecycle]          # the TESTNET-only signing gate (never mainnet, by construction)

Every ingress thread writes PMLR replay capture (per-venue tick / event / signal logs, the engine-orders.pmlr intent log, plus an optional --raw-tap payload tap) into a per-run directory under MULTIVENUE_LOG_DIR. Each run also drops instrument-manifest.tsv (and options-manifest.tsv when an options ladder is live) — options ordinals reshuffle per boot by design, so every offline consumer resolves symbols through the manifest, never a bare SymbolId across runs.

backtest's argv and schema-1 JSON are a frozen contract with claude-worker. The harness conforms to the worker, never vice versa.

Venue time + staleness (VT, 2026-09-03 — docs/arch/venue-time-capture-plan.md). Tick v3 carries venue_time_ms + flags; every ingress judges each tick against the venue's own fastest message (core_time::FeedClock) and flags it STALE past the per-venue stale_after_ms (pm 1000 / bn 1000 / okx 400 / deribit 600 / hl 700 / bybit 500 / mexc 400; run --stale-after-ms <venue>:<ms> overrides, :0 = measure only). A stale tick is captured but never a signal (Mid/Bid/Ask ABSENT in the VM), never a fill and never a mark. backtest and audit-pnl RE-JUDGE v3 captures from the stamp (--stale-after-ms on both — a threshold change is a replay), print stale: bn=59149/2639478 (12bps) … per run and stale-blind(v2) on a v2 root; --emit-detail is detail_version 2 with a stale block; capture-catalog reports stale_captured per lane. Any number from a v2 root is an upper bound. Metrics: engine_ingress_<venue>_stale_ticks_total, _feed_delay_ema_ms. Engine-side delay per venue: docs/venue-latency.md §5. Capture windows for research are ≤ 2 h by law (VT plan §6.1).

Slot 6 — strategy-xmm (XMM XH1–XH3, 2026-09-26; paper only). The Binance-led post-only market maker on Hyperliquid perps (plan xmm-hl-maker-plan-2026-09-26.md, rulings O-XH1…O-XH15). Parameters come from ~/multivenue/xmm.toml (--xmm <path>; xmm.toml.example is the probe); a requested xmm bit with no artifact refuses the boot. Since XH2 the member runs the LEAD θ policy (post-only at the touch, the LEAD cancel, the 500 ms gate, hard caps, stale-feed pulls), judged on paper by the queue law (core_fill::queue: queue ahead, prints, post-only rejects) in both the engine's paper matcher and backtest --member xmm; multivenue-engine xmm-parity replays one window on the XMM simulator's clock for the parity gate. Since XH3 it reports on /state (the xmm block: counters and one row per perp) and /metrics (engine_xmm_*_total, engine_xmm_perps, engine_xmm_p{k}_pos_1e6), audit-pnl fills its orders from the prints, and [labels.xmm] carries a regime label it never consults. A live slot 6 refuses the boot until XH4.

strategy-icdp (ICDP I1–I7, 2026-09-03) — unlinked at XMM XH1. Its crate, tests and backtest --member icdp --icdp <path> stay; no engine path composes it and --strategy ai+icdp refuses the boot. The intrabar candle-direction member: a UTC bar grid (core_time::BarClock), L1 features from every tick, an offline-fitted linear composite, IoC taker intents (Order.kind = 1, ttl_ns = the bar's remaining life) — entry at open + δ, exit at the roll, one position per instrument per bar. Parameters come from ~/multivenue/icdp.toml (--icdp <path>), a generated integer artifact (sha256 logged at boot); descriptors must resolve against the boot universe or the boot refuses. It was enabled with --strategy ai+icdp until XH1 (that name now refuses the boot). The offline fill model scores its intents under the I1 IoC law and prints the fee ladder. Its engine_icdp_*_total metrics and /state block were retired at XMM XH3.

Venue latency calibration — REQUIRED per deployment and per location

The backtest / audit-pnl fill model activates an order Δ_venue after emit and matches it against ticks in local receive time, so Δ_venue = feed one-way + order one-way as seen from the host and network the engine runs on. Those are location facts, not constants: moving the engine (a new box, a new region, a new ISP, a VPN) changes every number in the table and silently mis-prices every P&L the harness reports. The defaults in crates/cli/src/backtest.rs (ModelParams) are the values measured for the current deployment and carry their measurement date + location in the doc comment.

cd claude-worker && uv run python -m claude_worker.latency_probe --out ~/multivenue/research/latency-<date> --minutes 25

Run it on the deployment host before the first backtest there and after every move, then update ModelParams::default() and the table in docs/venue-latency.md (procedure, derivation, and the current measurement). The probe is stdlib-only, touches no engine path, and leaves per-message NDJSON so lead-lag can be re-derived in venue time.

claude-worker (offline researcher)

Python 3.14 package under claude-worker/. One serve daemon plus the frozen operator verb surface:

serve  fetch  backtest  push  positions  stage-ruleset  commit-ruleset  pnl

Frame-sending verbs (push, stage-ruleset, commit-ruleset) open the HMAC'd UDS; read-only verbs never touch the socket — a data pull must not signal AI liveness to the engine. The Anthropic SDK is constructed inside serve only; the strategist model is claude-fable-5. Verbs are globally serialized (one SQLite sequence namespace) — pgrep -f claude-worker before invoking one.

Continuous operation (M3)

./scripts/install-launchd.sh    # idempotent: renders launchd/*.plist, seeds state, bootstraps the agents

Installs the standing engine (com.multivenue.engine), the 00:00Z SIGTERM restart + universe refresh (com.multivenue.daily-restart), the hourly candles agent (com.multivenue.candles) and caffeinate. One engine ever — port 9191 and ai.sock are singletons; any smoke boot must stop the standing instance first and restart it after.

Layout

crates/
  core-*/            OS-agnostic primitives (alloc, config, crypto, io, latency,
                     metrics, net, parse, ring, simd, time, types)
  ingress-*/         External sources: polymarket, binance, okx, deribit,
                     hyperliquid, rpc + ingress-ai (UDS/HMAC command plane)
  options-select/    Boot-only options-chain selection law (shared by venues)
  book-builder/      Order-book construction
  strategy-*/        core, latency-arb, vrp, rule-tree, vm (ruleset VM), icdp,
                     set (the composed set), ai-exec; cross-arb + ev stay in
                     the workspace but are unlinked from the set
  research-artifacts/ Ruleset artifacts + validation
  signer-eip712/     EIP-712 signer (secp256k1 + tiny-keccak, no ethers/alloy)
  clob-dispatcher/   Persistent HTTP/2 client, preallocated buffers
  engine/            Engine<S: Strategy>
  cli/               Main binary (multivenue-engine)
  tui/               ratatui dashboard (read-only)
  bench/             criterion + dhat + allocation assertions
fuzz/                cargo-fuzz targets (integration tests are per-crate under tests/)
claude-worker/       Python 3.14 offline Claude researcher (never in the hot path)
launchd/  scripts/   M3 launchd plists + install / restart / candles / retention
docs/                Live docs (arch/ = closed historical plans and logs)
.claude/             Subagents, slash commands, settings

make help lists the full developer target set. config.example.toml is operator reference only — the binary is driven by env vars + CLI flags + universe.toml.

Hard rules

  1. Zero runtime allocations in hot paths. Enforced by alloc_assertions (0 B/op).
  2. No tokio, serde_json, ethers, alloy, reqwest, async-std on hot paths. Handwritten byte scanners over &[u8]; mio + state machines.
  3. No dyn Trait in hot paths. Monomorphization only (Engine<S: Strategy>).
  4. No panics in release hot paths. debug_assert! + panic = "abort"; fail fast.
  5. Every POD hot-path struct is #[repr(C)] + Copy; every ring is #[repr(align(64))].
  6. Every ingress parser has a property test + a fuzz target.
  7. No from x import y in Python. Full import x only.
  8. Secrets = a single .env file (chmod 600, git-ignored). No Keychain, no KMS, no Vault.
  9. No cloud services at any phase. Plain VMs only.
  10. No observability stack. TUI + log files + loopback /metrics only.
  11. No git operations without the operator's explicit ask. No push, rebase, history rewrite or new branches.
  12. Venue latency is measured, never assumed. Every deployment and every location re-runs claude_worker.latency_probe and re-derives the harness Δ table (docs/venue-latency.md).

See CLAUDE.md for the complete list plus the "stop if you're about to do this" pitfalls.

License

Licensed under the Apache License, Version 2.0 — see LICENSE and NOTICE.

Copyright 2026 Anton (darkcite)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Every source file carries SPDX-License-Identifier: Apache-2.0; make license-check fails the build if one does not. The license covers documentation source and diagrams (docs/, PLAN.md, *.svg) on the same terms — Apache-2.0's definition of "Source" is explicit that it includes documentation source.

Contributions are accepted under Apache-2.0 §5 — a submitted contribution is licensed under the same terms, without additional conditions. See CONTRIBUTING.md.

Third-party dependencies

No third-party source is vendored in this tree; dependencies are resolved at build time from crates.io and PyPI and carry their own licenses. A compiled binary does link them, so attribution for the binary is generated by make license-deps (cargo-about) into THIRD-PARTY-NOTICES.md. No distributed binary may ship without LICENSE, NOTICE and THIRD-PARTY-NOTICES.md alongside it. make license-deps also runs cargo deny check licenses against the allowlist in deny.toml.

Trademarks

Polymarket, Binance, OKX, Deribit and Hyperliquid are trademarks of their respective owners. This project is not affiliated with, endorsed by, or sponsored by any of them, and names them only to describe interoperability. Per Apache-2.0 §6, this license grants no trademark rights.

Disclaimer

This software trades real money on live venues. It is provided as is, without warranty of any kind, and nothing here is financial advice. Running it in non-paper mode is entirely at your own risk. See docs/risk-policy.md for the kill-switch and cap rules.

About

AI-powered Quant Research, backtest and trading engine for Binance, Hyperliquid, OKX, Polymarket, MEXC, Bybit, Deribit

Topics

Resources

Contributing

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages