Free guide · 12 min read

The complete freqtrade Docker setup: install, backtest, dry-run, live

One page, ten steps, two files. The exact minimal setup we run ourselves — from a clean machine to dry-run, plus the four changes that take you live.

Watch the video · YouTubeWatch the full walkthrough — every step below, run for real on camera (8:52).

What you'll build

Ten steps and two small files take you from a clean machine to a real strategy trading live prices in simulation. This is the exact setup we run and verify ourselves — no conda, no Python version fights, no forty-page manual. Everything below is copy-paste complete.

Steps 1–2: install Docker, create the folder

Install Docker Desktop first (Windows, macOS, or Linux — the commands are identical). Then create a project folder:

docker version          # sanity check
mkdir freqtrade-demo && cd freqtrade-demo

Step 3: docker-compose.yml — the whole file

This is the entire file — twelve lines. The default command runs dry-run trading with a strategy called BBRSI2 (swap in your own later):

services:
  freqtrade:
    image: freqtradeorg/freqtrade:stable
    restart: unless-stopped
    container_name: freqtrade
    volumes:
      - "./user_data:/freqtrade/user_data"
    # Default command when running `docker compose up`
    command: >
      trade
      --config /freqtrade/user_data/config.json
      --strategy BBRSI2

Steps 4–5: pull the image, create user_data

docker compose pull
docker compose run --rm freqtrade create-userdir --userdir /freqtrade/user_data

Step 6: config.json — the whole file

Thirty-eight lines, and only five of them really matter. The file:

{
    "max_open_trades": 1,
    "stake_currency": "USDT",
    "stake_amount": 100,
    "tradable_balance_ratio": 0.99,
    "dry_run_wallet": 1000,
    "fiat_display_currency": "USD",
    "dry_run": true,
    "timeframe": "1m",
    "cancel_open_orders_on_exit": true,
    "exchange": {
        "name": "binance",
        "key": "",
        "secret": "",
        "ccxt_config": {},
        "pair_whitelist": ["BTC/USDT"],
        "pair_blacklist": []
    },
    "pairlists": [
        {"method": "StaticPairList"}
    ],
    "entry_pricing": {
        "price_side": "same",
        "use_order_book": true,
        "order_book_top": 1,
        "price_last_balance": 0.0,
        "check_depth_of_market": {"enabled": false, "bids_to_ask_delta": 1}
    },
    "exit_pricing": {
        "price_side": "same",
        "use_order_book": true,
        "order_book_top": 1
    },
    "bot_name": "freqtrade_docker_demo",
    "initial_state": "running",
    "internals": {"process_throttle_secs": 5},
    "fee": 0.001
}
  • dry_run: true — simulation mode. No real money anywhere; exchange key and secret stay empty.
  • stake_amount: 100 + max_open_trades: 1 — each trade uses 100 USDT, one position at a time.
  • pair_whitelist — the bot only ever trades BTC/USDT.
  • timeframe: 1m must match the strategy you run (BBRSI2 is a 1-minute strategy).
  • fee: 0.001 — realistic Binance spot fee (0.1%). Backtests without fees are fiction.

Step 7: add a strategy

Download BBRSI2.py from the Vetta catalog and drop it into user_data/strategies/. The class name inside the file is what you pass to --strategy. Any other strategy works the same way — just match its timeframe in the config.

Step 8: download real market data

This pulls 200 days of 1-minute BTC/USDT candles from Binance public market data — no exchange account needed:

docker compose run --rm freqtrade download-data \
  --config /freqtrade/user_data/config.json \
  --pairs BTC/USDT --timeframes 1m --days 200 \
  --data-format-ohlcv jsongz --erase

Step 9: backtest — and read it like a skeptic

docker compose run --rm freqtrade backtesting \
  --config /freqtrade/user_data/config.json \
  --strategy BBRSI2 --timerange 20260207- \
  --data-format-ohlcv jsongz
  • Sample size first: hundreds of trades mean something; a handful means nothing.
  • Always compare against the market: if the coin rose 11% and the strategy lost 17%, the strategy subtracted value.
  • Win rate is a trap: 60% winners can still lose money if the losses are huge.
  • Drawdown duration: could you sit through 186 days underwater without quitting?

Step 10: dry-run — live signals, fake money

The compose file's default command already runs dry-run trading. Start it in the background and watch the log:

docker compose up -d        # start
docker compose logs -f      # watch live signals
docker compose down         # stop
  • Dry-run trades a simulated 1,000 USDT wallet against live prices. Let it run for at least 2–4 weeks and compare the result with the backtest for the same period — a big gap means the backtest was overfit. Days of observation prove nothing.

Going live — only four changes

When — and only when — dry-run confirms the backtest over weeks, live trading needs exactly four edits to config.json. Nothing else changes.

  • dry_run: false — real orders from this point on.
  • Fill in exchange key and secret — create an API key with trade-only permission. Never enable withdrawals.
  • Set stake_amount to money you can genuinely afford to lose entirely.
  • Keep fee realistic — it quietly decides whether small edges survive.
  • Going live is not an upgrade, it is a risk decision. Start with the minimum stake, verify the stop-loss actually fires on the exchange, and remember docker compose down stops everything instantly.

The three errors everyone hits

  • "pairlists is a required property" — the pairlists block is missing from config.json. Our file above already includes it.
  • Data format mismatch — if you downloaded with --data-format-ohlcv jsongz, you must backtest with the same flag.
  • Zero trades — your timerange is too short, or the strategy's timeframe doesn't match the data. Widen the window first.

Educational content, not financial advice. Past performance does not predict future results.