trade-bot

A trading bot whose backtest is the live run.

An event-driven trading bot in Rust. A backtest and a live run execute the same strategy code through the same engine loop; only the data feed and broker are swapped. Binance spot today, built so equities, options and perpetuals can follow without a rewrite.

Status: v1. Backtesting and paper trading (Binance testnet or Demo Trading, and paper on MAX's live bars) are the supported paths. Real-money trading is behind three separate locks and has not been exercised against mainnet. No strategy here has a demonstrated edge: backtest results come from a stated fill model and are not a promise.

Safety model

These are invariants in the code, each pinned by tests, not conventions.

Money is exact

Prices, quantities, balances and fees are Decimal in unit types (Price, Qty, Notional), never floats. Config and data files take money as strings; a bare number is an error.

No lookahead

A strategy sees data only up to the current closed candle, and its orders fill no earlier than the next one. A test rewrites every candle after t and requires nothing up to t to change.

Secrets from the environment

API keys come only from BINANCE_API_KEY / BINANCE_API_SECRET. No config field can hold them: api_key in a file is an unknown-field error.

Three locks for real money

The default is paper on testnet. Live needs mode = "live", exchange.network = "live" and --i-understand typed on the command line.

How it works

One-way data flow. The strategy is a pure decision; the provider is the only thing that differs between a backtest and a live run.

Each event, in order

  • The broker settles pending orders against the new event, so a decision at t fills at t+1.
  • Fills update the strategy's position before the bar joins its history.
  • The strategy decides; risk rounds to lot and tick (never more aggressively) and checks venue filters.

Stated fill model

  • Market orders fill at the next candle's open, taker, with slippage you must specify.
  • Resting limits fill only when price trades through them; a touch is not a fill.
  • Stop and target in one candle: the model assumes the worse.

Built-in strategies

Each implements one trait and registers itself, so it runs in backtests and live unchanged. Each one says what it bets on and how it fails. Compare any of them against buy_and_hold on the same coin after costs.

NameBets onFails when
buy_and_holdNothing: the benchmark. Buys once, holds forever.The coin falls.
dcaSpreading entry over time (hour, day, week, month).Removes timing risk, not direction risk; buys all the way down.
sma_trendTrends: long above the SMA, cash below.Ranges cause whipsaws.
dual_ma_crossTrends: long while the fast average is above the slow one.Ranges and lag.
donchian_breakoutBreakouts beyond the prior channel continuing.False breakouts in ranges.
avwapPrice holding above its anchored VWAP.Chop around the anchor.
rsi_reversionRanges: buys oversold, sells overbought.Sustained downtrends (no stop, by design).
momentum_rotationRecent winners among several coins keep winning.Sharp reversals, choppy leadership.
ratio_hopRotating coins only when units ratchet up after fees, with a freefall guard.Maximizes units, not value.
gridOscillation inside a price range.Trends either way: holds every level falling, sells out rising.

Quick start

Prebuilt binaries for Linux, macOS and Windows are on the releases page. Building from source needs only rustup; the toolchain is pinned.

# Cache public history (no API key needed) and backtest on it
make fetch-data SYMBOL=BTCUSDT FROM=2024-01-01
make backtest STRATEGY=buy_and_hold SYMBOL=BTCUSDT \
     FROM=2024-01-01 TO=2024-06-01 SLIPPAGE_BPS=5 PARAMS=my-params.toml

# Paper trade against Binance testnet
export BINANCE_API_KEY=… BINANCE_API_SECRET=…
make run-paper

Venues

Binance spot: testnet, Demo Trading and live. MAX (MaiCoin): backtests and paper trading on live bars, never orders.

Books that survive restarts

Orders are journaled before submit and fills recorded by venue trade id. On start and on every exit the bot reconciles with the exchange.

Observable, read-only

Prometheus metrics, JSON logs, a Grafana stack in deploy/, and an HTTP API that can never place or cancel an order.