What you'll have at the end
By the end of this guide your machine will be running a long-lived Python process that automatically buys BTC on schedule using your exchange API key, logs every trade to a local SQLite database, and lets you sweep accumulated sats to your hardware wallet from the dashboard whenever the balance is big enough that the on-chain fee is a small fraction.
The Free tier gives you:
- Single-exchange DCA on BitOasis or OKX or Binance UAE
- Buy-the-dip overlay (multiply buys when BTC drops)
- Maker-mode execution (limit orders to save on fees)
- Manual on-chain withdraw to your hardware wallet from the dashboard (address book + Binance whitelist autocomplete; UAE Travel Rule fields handled)
- UAE-format tax CSV export
- Risk circuit breakers (daily cap, single-buy cap, auto-pause on N failures)
- Backtest engine to dry-run strategies against 365 days of history
Multi-exchange smart routing, advanced overlays (volatility-weighted, time-of-day, drawdown-aware), on-chain smart triggers (MVRV-Z), the funding-rate monitor, and cross-exchange alerts are gated to Pro tier. You can add the Pro license later without re-installing anything — it's the same bot, you just paste a license token.
Withdraw model: the dashboard's manual Withdraw-now flow is the supported path. You decide when to sweep, you pay the on-chain fee once per intentional sweep (typical: when your exchange balance is >5× the network fee). No background daemon decides for you.
Prerequisites
You need:
- A machine that stays online. A Raspberry Pi 4, a Mac mini, an Umbrel node, an old laptop with the lid taped down, or a small VPS (Hetzner CX11 at ~AED 18/month is plenty). The bot is light — a few hundred MB of RAM, near-zero CPU between cycles.
- Docker (recommended) or Python 3.11+. Most of this guide uses Docker because it's the same on every platform. If you're on a Pi running DietPi or Umbrel, Docker is already there.
- An exchange account. BitOasis, OKX UAE, or Binance UAE. All three are VARA-licensed.
- A Bitcoin hardware wallet if you plan to sweep accumulated BTC off the exchange — BitBox02, Trezor Safe 5, Coldcard, or Ledger. See our hardware wallet guide for UAE residents if you don't have one yet.
- ~45 minutes the first time. Subsequent updates are two commands.
dry_run: true on by default. Every trade is simulated until you explicitly flip that switch. Treat the first few cycles as fire-drills — read the logs, confirm the math, then go live.1. Get the source
The bot is open source under the MIT license and the full source is public on GitHub — clone it, audit it, run it yourself. No access request, no waiting.
git clone https://github.com/jiashanlu/bitcoiners-dca.git cd bitcoiners-dca
Create your config and data directories:
cp config.example.yaml config.yaml mkdir -p data reports
We'll edit config.yaml in step 3. First the API key.
2. Create your exchange API key (TRADE-only)
Pick the exchange you want to DCA on. The bot supports one exchange at a time on Free tier — you can switch later by editing the config.
2a. OKX UAE
- Log into okx.com from your UAE-verified account.
- Top-right avatar → API → Create V5 API Key.
- Name:
dca-bot(or anything). - Permissions: tick Read and Trade only. Do NOT tick Withdraw.
- IP whitelist: optional but recommended. If your machine has a static IP, paste it. If it's on a home connection, skip this and rely on the key's passphrase.
- Set a passphrase you'll remember (OKX calls it the API passphrase — required on every request).
- Save the API key, secret, and passphrase. You'll only see the secret once.
You now have three secrets: OKX_API_KEY, OKX_API_SECRET, OKX_API_PASSPHRASE. Keep them somewhere safe.
2b. BitOasis
- Log into bitoasis.net.
- Top-right → Settings → API Token Management.
- Click Generate New Token.
- Scopes: Read and Trade only.
- Copy the Bearer token — BitOasis shows it once.
You now have one secret: BITOASIS_API_TOKEN. BitOasis uses Bearer-token auth, so there's no separate secret/passphrase.
2c. Binance UAE
UAE residents access binance.com via the ADGM-licensed entity. The bot uses the standard Binance API.
- Log into binance.com (account verified through Binance UAE).
- Top-right avatar → API Management.
- Create a System-Generated key (HMAC). Name:
dca-bot. - Permissions: Enable Reading + Enable Spot & Margin Trading. Do NOT enable Withdrawals.
- Restrict IP if you can.
3. Configure your strategy
Open config.yaml in your editor. The starter file is heavily commented — every key has a one-line explanation. Here's the minimal Free-tier setup for OKX, weekly AED 500 with a buy-the-dip overlay:
license:
tier: free
strategy:
amount_aed: 500 # AED per buy
frequency: weekly
day_of_week: monday
time: "09:00"
timezone: "Asia/Dubai"
overlays:
buy_the_dip:
enabled: true
threshold_pct: -10 # if BTC -10% over lookback
lookback_days: 7
multiplier: 2.0 # 2× the base AED amount
execution:
mode: taker # taker = market order; "maker_only" saves fees but may not fill
routing:
mode: best_price
preferred_exchange: null
exchanges:
okx:
enabled: true
api_key_env: OKX_API_KEY
api_secret_env: OKX_API_SECRET
passphrase_env: OKX_API_PASSPHRASE
binance:
enabled: false
bitoasis:
enabled: false
risk:
max_daily_aed: 1000 # hard daily cap — clamps even big dip-triggered buys
max_single_buy_aed: 2000 # per-buy cap
max_consecutive_failures: 5
dry_run: true # KEEP THIS ON FOR NOWNow write your API key into an environment file (Docker reads this):
cat > .env <<'EOF' OKX_API_KEY=your_key_here OKX_API_SECRET=your_secret_here OKX_API_PASSPHRASE=your_passphrase_here EOF chmod 600 .env
.env or config.yaml to git.The repo's .gitignore already excludes them. If you keep your bot in a private repo, double-check.4. Validate + dry-run
Build the Docker image and validate the config:
docker build -t bitcoiners-dca . docker run --rm --env-file .env \ -v $PWD/config.yaml:/app/config.yaml \ bitcoiners-dca validate
validate parses the YAML, checks license-tier feature gating, confirms your API credentials work, and prints a summary of what the bot will do. If anything is wrong, fix it here before you go any further.
Now run one dry-run buy cycle:
docker run --rm --env-file .env \ -v $PWD/config.yaml:/app/config.yaml \ -v $PWD/data:/app/data \ bitcoiners-dca buy-once
With dry_run: true this prints what it would have bought (exchange, AED amount, BTC estimate, fee, effective price) without placing an order. Read it carefully. If the math looks right, you're ready to go live.
buy-once.5. Go live
Edit config.yaml and set:
dry_run: false
Then start the bot as a long-running container:
docker compose up -d
The bundled docker-compose.yml runs the bot daemon-mode (cron + interval scheduler) with restart-on-failure policy. Logs go to stdout, which Docker captures. View them with:
docker compose logs -f
Your first real buy will hit at the next scheduled cycle (Monday 09:00 Asia/Dubai in our example). Watch the first one closely.
6. Withdraw to your hardware wallet (manual, on-demand)
This is the part that makes the bot meaningfully different from just clicking "recurring buy" on the exchange. Accumulated BTC gets swept off the exchange to your own wallet — but you decide when, so the on-chain fee is a small fraction of the sweep (target <1%).
On your hardware wallet, generate a fresh receive address. Examples:
- BitBox02: BitBoxApp → Receive, choose Native SegWit (
bc1q…). - Trezor Safe 5: Trezor Suite → Receive, default address type.
- Coldcard: derive an address via Sparrow Wallet or Specter (most CCs are used air-gapped).
Verify the address on the hardware device itself (not just in software), then whitelist it in the exchange's withdrawal-address settings (OKX, BitOasis, and Binance UAE all require this — they reject withdraws to non-whitelisted addresses).
When you're ready to sweep, open the bot's dashboard at http://localhost:8000/withdrawals:
- Pick the exchange you want to withdraw from.
- Paste the whitelisted address (autocomplete picks it up from your address book after the first use, and from Binance's whitelist API directly).
- Click Max to fill the full sendable amount, then Send withdrawal.
- Fill in the UAE Travel Rule recipient fields (auto-prefilled for self-custody).
For this flow your exchange API key needs the Withdraw scope. Best practice: keep two keys.
- Key A (trade-only) — the bot uses this for buys. Lower blast radius.
- Key B (trade + withdraw, with your hardware-wallet address whitelisted at the exchange) — paste this in the dashboard only when you're ready to enable manual withdraws. Even if Key B leaks, withdrawals can only go to your whitelisted address.
7. Monitoring + logs
The bundled docker-compose.yml starts a self-service web dashboard alongside the daemon. Open http://localhost:8000 on the machine running the bot — you'll see balances, recent cycles, scheduled strategy, exchange status, the backtest engine, and the manual Withdraw-now flow.
The bot also exposes three things you should watch from the CLI:
Logs:
docker compose logs -f # live tail docker compose logs --tail 100 # last 100 lines
Status snapshot:
docker compose exec dca bitcoiners-dca status
Status shows: license tier, last cycle outcome, lifetime AED spent, lifetime BTC bought, current exchange balances, whether circuit breakers have tripped.
Telegram alerts (recommended):
Create a Telegram bot via @BotFather, get the token, and note your Telegram chat ID (DM @userinfobot). Then:
# in .env
TG_BOT_TOKEN=123456:abcdef...
# in config.yaml
notifications:
telegram:
enabled: true
bot_token_env: TG_BOT_TOKEN
chat_id: 123456789 # YOUR chat ID — get it from @userinfobot on TelegramYou'll get a Telegram message after every cycle (buy succeeded, buy failed, withdrawal triggered, circuit breaker tripped).
Tax CSV export:
docker compose exec dca bitcoiners-dca export-tax-csv --year 2026
Writes a UAE-format CSV to ./reports/ with date, exchange, pair, AED, BTC, fee. The format is what an accountant or auditor would want; FTA hasn't published a crypto-specific template yet but this covers all the fields they'll care about.
8. Upgrade to Pro (or stay on Free)
The Free tier is genuinely useful — for a single-exchange AED 500/week DCA with manual on-chain sweeps to a hardware wallet it's probably all you need. Don't upgrade because the marketing page lists more features; upgrade if you specifically want one of them.
Things you only get on Pro:
- Multi-exchange smart routing — bot queries BitOasis + OKX + Binance every cycle, picks the cheapest after-fee price. Tends to save ~0.34% per buy at typical UAE-pricing spreads. Worth it if you DCA > ~AED 15k/month (the routing savings exceed the AED 49 subscription).
- Multi-hop routing (AED → USDT → BTC, plus 3-hop AED → USDC → USDT → BTC) — captures the cross-asset basis where the direct BTC/AED pair is wide.
- Cross-exchange arbitrage alerts via Telegram.
- Advanced overlays: volatility-weighted, time-of-day, drawdown-aware. Useful for big DCAers who care about regime-aware spending.
- On-chain smart triggers — MVRV-Z multiplier that boosts the buy when BTC is historically cheap and dampens it when it's hot. Pure overlay, plays nicely with buy-the-dip.
- Funding-rate monitor — basis-trade signals (detect when shorting BTC perp pays well; bot never opens the trade for you).
- Hosted version at
app.bitcoiners.aeif you don't want to operate the bot yourself anymore.
When you subscribe to Pro you'll receive a Pro license token (a single base64 string). Paste it into config.yaml:
license: tier: pro key: "eyJ0aWVyIjoicHJvIi..." # the token from your email
Restart the bot. bitcoiners-dca license now shows your tier as Pro and the previously-gated features are live. License verification is offline (Ed25519-signed token), so the bot doesn't phone home.
Troubleshooting
"OKX request signature invalid"
Almost always a wrong passphrase. The passphrase is case-sensitive and is the one you set when creating the API key on OKX, not your account password. Recreate the key if you've lost it.
BitOasis "401 Unauthorized"
Bearer token issues: confirm the token is in .env as BITOASIS_API_TOKEN, no quotes, no trailing whitespace, no newline at the end. The token format is a long alphanumeric string with hyphens — not a UUID.
Bot says "dry-run mode — no order placed" and I want it to be live
Edit config.yaml: dry_run: false at the bottom of the file. Then docker compose restart.
Circuit breaker tripped — bot won't buy
After 5 consecutive cycle failures the bot auto-pauses (a safety measure against blowing through your daily cap while an exchange is having an outage). Inspect logs to find the root cause, then resume:
docker compose exec dca bitcoiners-dca risk resume
How do I update to a newer version?
cd bitcoiners-dca git pull docker compose build --no-cache docker compose up -d
Your config.yaml, .env, SQLite DB in data/, and tax reports in reports/ are all volume-mounted — they survive image rebuilds.
Where to get help
Email support@bitcoiners.ae with the output of docker compose logs --tail 100 and a short description of what you tried. Free-tier issues are also welcome on the public GitHub issue tracker; Pro tier gets 24-hour email response either way.
The full Bitcoin community is on @bitcoinersae on Telegram — drop questions there too. UAE Bitcoiners help each other.
Don't want to operate it yourself?
The hosted version is AED 49/month.
Multi-exchange smart routing, advanced overlays, on-chain smart triggers, and a browser dashboard — we run the bot for you on managed infrastructure.