Skip to main content
Navigation
HomeTechnical ReferenceJournalGitHubGitHub
Sidebar — toggle document categories via the logo
Raderbot — Rust Trading Bot

Raderbot — Rust Trading Bot

March 5, 2024

Overview​

Raderbot is a single-binary Rust app on Actix Web. It maintains WebSocket streams to an exchange, stores incoming market data, runs algorithmic trading strategies, and exposes everything through a REST API. The architecture is trait-based: exchange adapters and storage backends can be swapped at runtime via the .env file or an API call.

  • Dry-run by default — DRY_RUN=True routes all trading through a MockExchangeApi.
  • Decoupled account & market layers — Account uses its own exchange API instance; market data can come from a different source.
  • Pluggable storage — file system (default), MongoDB time-series, or InfluxDB.
  • Dynamic exchange switching — an endpoint swaps the account adapter between Binance, BingX, and Mock without restart.

Module map​

src/
├── main.rs # Entry point; Actix HttpServer, service registration
├── app.rs # AppState — shared Arc<Mutex<...>> for bot, account, market, exchange
├── bot.rs # RaderBot core + StrategyManager + async init loop
│
├── account/ # Position / TradeTx models, position lifecycle, adapter swap
├── algo/ # 12+ trading algorithms
├── analytics/ # Volume analysis (PriceVolume, TimeVolume, TradeVolume)
├── api/ # 5 route scopes: account, exchange, market, strategy, utils
├── exchange/ # Trait-based adapters: BinanceApi, BingXApi, MockExchangeApi + streams
├── market/ # Kline, Ticker, Trade structs + in-memory Market store
├── storage/ # FsStorage, MongoDbStorage, InfluxStorage behind StorageManager trait
├── strategy/ # Strategy loop, algorithm binding, SignalHandler, BackTest
└── utils/ # Channels, json helpers, time helpers

Root files​

Cargo.toml # tokio, actix-web, reqwest, tokio-tungstenite, serde, ta, mongodb...
Makefile # make build / dev / test / fix / clean / docs
docker-compose.yaml # InfluxDB 2.7 (MongoDB commented out)
.env.example # Exchange keys, DRY_RUN, storage backend, RUST_LOG
raderbot # Prebuilt release binary
static/ # Frontend assets
docs/ # strategies.md
LICENSE.md # MIT

Exchange layer​

Everything flows through a single async trait, ExchangeApi (src/exchange/api.rs):

#[async_trait]
pub trait ExchangeApi: Send + Sync {
async fn get_account(&self) -> ApiResult<Value>;
async fn open_position(&self, symbol, margin, leverage, side, price) -> ApiResult<Position>;
async fn close_position(&self, position, close_price) -> ApiResult<TradeTx>;
async fn get_kline(&self, symbol, interval) -> ApiResult<Kline>;
async fn get_ticker(&self, symbol) -> ApiResult<Ticker>;
fn get_stream_manager(&self) -> ArcMutex<Box<dyn StreamManager>>;
// ...
}

Three implementations:

AdapterFileRole
BinanceApiexchange/binance.rsDefault — real Binance API over REST + WebSocket streams
BingXApiexchange/bingx.rsAlternative BingX adapter
MockExchangeApiexchange/mock.rsSimulated exchange; used automatically when DRY_RUN=True

Streams are managed through a StreamManager trait (exchange/stream.rs). Each stream has metadata: id, URL, symbol, interval, start/last-update timestamps. Stream IDs follow <symbol>@kline_<interval> / <symbol>@ticker / <symbol>@trade.

Key detail from bot.rs: on startup the bot creates two exchange API instances — one for market data (hardcoded to BinanceApi), one for the account that can differ. When dry-run is on, the account gets a MockExchangeApi; otherwise it shares the market's BinanceApi or creates its own.


Market data​

Models live in src/market/:

StructFileFields
Klinekline.rssymbol, interval, open/high/low/close, volume, open_time, close_time
Tickerticker.rslast price, 24h change, high, low, volume
Tradetrade.rstimestamped public market trades
Intervalinterval.rs1m, 3m, 5m, 15m, 30m, 1h, 4h, 1d, 1w (string-serializable enum)

The Market (market/market.rs) is the in-memory store — it receives data from active WebSocket streams via an async channel (MarketMessage in messages.rs) and supports range queries against both live and bootstrapped historical data.


Storage backends​

All implement the StorageManager trait. Selected at boot from .env:

BackendFileWhen to use
FsStorage (default)storage/fs.rsSTORAGE_TYPE=FS — writes to ~/.raderbot/
MongoDbStoragestorage/mongo.rsSTORAGE_TYPE=MONGO — time-series collections
InfluxStoragestorage/influx.rsSTORAGE_TYPE=INFLUX — InfluxDB 2.7 point writes

Fallback behavior (from bot.rs): if Mongo or Influx fail to connect, the bot logs the error and falls back to FsStorage — no crash.

InfluxDB setup (docker-compose.yaml):

influxdb:
image: influxdb:2.7
ports: ["8086:8086"]
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_ORG: raderbot
DOCKER_INFLUXDB_INIT_BUCKET: trade_data
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: myadmintoken

Strategies & algorithms​

Lifecycle​

POST /new-strategy → bot.start_strategy(...) → picks an algorithm from src/algo/ → spawns a Strategy via tokio::spawn → tracks handle + settings in StrategyManager. A signal handler loop consumes SignalMessages and fires orders through the Account.

Available algorithms (src/algo/)​

FileStrategy
bollinger_bands.rsPrice bands around moving average; volatility envelope
ma_crossover.rsShort-term MA crosses long-term MA → buy/sell
ma_simple.rsSimple moving average signal
ma_three_crossover.rsThree-MA crossover (fast/med/slow)
macd.rsMACD (diff of EMAs) vs signal line
macd_bollinger.rsMACD + Bollinger Bands combined
rsi.rsRSI momentum oscillator (overbought more than 70, oversold less than 30)
rsi_ema_sma.rsRSI + EMA + SMA mix
volume_continuation.rsVolume-confirmed trend continuation
volume_continuation_reversal.rsVolume reversal detection
volume_profile.rsVolume-weighted price profiling
builder.rsFactory — maps algorithm name string → concrete impl
template.rsScaffold for writing new algorithms

Backtesting​

BackTest (strategy/backer.rs) replays KlineData over a strategy and produces a StrategySummary (PnL, trade count, win rate, etc.). Triggered via POST /run-back-test with symbol, interval, date range, and algorithm params. Uses the KlineData from the market's historical store.

Trade models​

  • Position — symbol, order side (Buy/Sell), open price & time, quantity (margin × leverage / price), margin_usd, leverage, optional stop-loss and strategy ID. Uses uuid::v4 for IDs.
  • TradeTx — close price, close time, computed profit (positive for winning trades on Buy, inverse for Sell), and linked source position with optional associated SignalMessage metadata.

REST API​

All endpoints under http://localhost:3000/api. Full request/response docs at the Postman collection — or download the collection JSON to import directly into Postman / Insomnia.

/api/market​

GET /info Market summary
GET /active-streams Live stream metadata
POST /open-stream {stream_type, symbol, interval?}
POST /close-stream {stream_id}
POST /last-price {symbol}
POST /kline-data {symbol, interval}
POST /kline-data-range {symbol, interval, from_ts?, to_ts?, limit?}
POST /ticker-data {symbol}
POST /trade-data {symbol, from_ts?, to_ts?, limit?}
POST /trade-volume-data {symbol, ..., bucket_size? | time_interval?}

/api/account​

GET /account-info
POST /set-exchange-api {exchange, dry_run} → swap Binance/BingX/Mock
GET /active-positions
GET /trades
POST /open-position {symbol, margin, leverage, order_side, stop_loss?, strategy_id?}
POST /close-position {position_id}
GET /close-all-positions

/api/strategy​

POST /new-strategy {symbol, strategy_name, algorithm_params, interval, margin?, leverage?}
POST /stop-strategy {strategy_id, close_positions?}
POST /stop-all-strategies {close_positions?}
POST /set-params {strategy_id, params}
POST /change-settings {strategy_id, settings}
GET /active-strategies
GET /historical-strategies
POST /historical-summary {strategy_id}
POST /list-positions {strategy_id}
POST /summary {strategy_id}
POST /info {strategy_id}
POST /run-back-test {symbol, strategy_name, algorithm_params, interval, from_ts, to_ts, ...}

/api (root + static)​

GET /api → serves static/index.html
GET /static/* → frontend assets (actix-files)

Getting started​

# Prereqs: Rust, cargo, make (Docker optional)
git clone https://github.com/subaquatic-pierre/raderbot.git
cd raderbot

# Configure
cp .env.example .env
# .env:
# BINANCE_API_KEY=...
# BINANCE_SECRET_KEY=...
# DRY_RUN=True
# STORAGE_TYPE=FS
# RUST_LOG=info

# Build release binary
make build

# Run
./raderbot
# → Actix on 127.0.0.1:3000

# Dev mode (auto-reload on file changes)
make dev

Key .env values​

DRY_RUN=True # True → MockExchangeApi (no real trades)
EXCHANGE_API=BINANCE # BINANCE or BINGX
STORAGE_TYPE=FS # FS | MONGO | INFLUX
MONGO_URI=mongodb://user:pass@localhost:27017/?authSource=admin
INFLUX_DB_HOST=http://localhost:8086
INFLUX_TOKEN=myadmintoken

Optional: InfluxDB for time-series metrics​

docker-compose up -d influxdb
# Update .env: STORAGE_TYPE=INFLUX, restart bot

Historical data​

For backtests and BootstrapKlineData/BootstrapTradeData requests, place CSV data from Binance public market data at:

~/Projects/BinanceData/
├── Kline/
│ ├── BTCUSDT-5m-2023-12.csv
│ └── ...
└── MarketTrade/
├── BTCUSDT-aggTrades-2020-01.csv
└── ...

Source: data.binance.vision — download ZIP files from data/spot/monthly/klines/<SYMBOL>/<INTERVAL>/ (and aggTrades/ for trades). Extraction scripts in github.com/binance/binance-public-data.


Notes​

  • Experimental — the bot is still in active development. Many features are undocumented or rough.
  • Unix only — build targets Unix systems.
  • Dry-run only by default — live trading requires DRY_RUN=False and a funded exchange API key.
  • Market data required for orders — opening/closing positions requires a live last price from a stream or ticker call. Make sure the symbol has an active stream.
  • Storage fallback — if Mongo or InfluxDB can't connect, the bot silently falls back to file-system storage.