Full-stack walkthrough¶
Step-by-step deployment of the full-stack starter bundle. About 15 minutes from clone to first paper trade.
Demo accounts only
Use a Bybit testnet API key and an Exness MT5 demo account for this walkthrough. qkt is pre-1.0 — do not connect funded accounts.
1. Create the directory structure¶
2. Copy the bundle files¶
Copy the seven files from the bundle page into this directory. Final layout:
my-trading-stack/
├── .env.example
├── docker-compose.yml
├── qkt.config.yaml
└── strategies/
├── btc-trend.qkt
└── eur-meanrev.qkt
3. Create your .env from the template¶
Edit .env:
BYBIT_API_KEY=your-bybit-testnet-key
BYBIT_API_SECRET=your-bybit-testnet-secret
BYBIT_ENVIRONMENT=testnet # important — testnet first
BYBIT_TRADE_MODE=demo
BYBIT_ACCOUNT_LOGIN= # from the gateway's /v1/health once it runs
BYBIT_TRADER_TOKEN=a-long-random-value
BYBIT_GUARDIAN_TOKEN=another-long-random-value
MT5_LOGIN=12345678
MT5_PASSWORD=your-exness-demo-password
MT5_SERVER=Exness-MT5Trial
MT5_ENABLE_ALGO_TRADING=1
MT5_API_KEY=replace-with-a-long-random-value
VNC_PASSWORD=changeme
QKT_BROKER_EXNESS_GATEWAY_URL=http://mt5-gateway:5001
For Bybit testnet API keys: testnet.bybit.com → API Management. Real and testnet keys are different — don't mix them. The keys go to the gateway-bybit-spot service (the qkt-venue-gateway running its Bybit adapter); qkt itself only holds the gateway's trader token.
For Exness demo: any phone signup gets you Exness-MT5Trial server credentials within a minute.
4. Add .env to .gitignore¶
You should never commit credentials. Run this even if you don't plan to push the repo anywhere — it's a habit worth building early.
5. Bring up the stack¶
This starts two containers:
mt5-gateway— Wine + MT5 terminal + Flask API on port 5001qkt— the trading daemon, waits for the gateway to pass its healthcheck
Verify both are running:
docker compose ps
# Output:
# NAME STATUS PORTS
# mt5-gateway Up (healthy) 0.0.0.0:3000->3000/tcp, 0.0.0.0:5001->5001/tcp
# qkt Up
If mt5-gateway is Up (unhealthy), it's still booting Wine + MT5. Wait 60 seconds and re-check.
6. Log into MT5 once¶
The MT5 terminal needs an interactive login the first time. Connect via VNC at localhost:3000 using VNC_PASSWORD from your .env.
Inside the MT5 GUI:
- File → Login to Trade Account
- Enter login + password + server name from
.env - Click Login — the indicator bottom-right turns green
Verify from the host:
curl -H "Authorization: Bearer $MT5_API_KEY" http://localhost:5001/health/ready
# {"ok": true, "account": {"login": 12345678, "balance": 10000.00, ...}}
If ok: false, the login didn't take — back into the VNC GUI to retry.
7. Verify broker profiles loaded¶
Expected output:
brokers list shows MT5 profiles; the bybit_spot gateway account is checked when the daemon
starts (it refuses to start if the gateway reports another adapter, account or trade mode).
If exness is missing, the qkt.config.yaml didn't load — check the bind-mount path in docker-compose.yml.
8. Audit the live feeds before deploying¶
This is the step new operators skip and regret. Capture a minute of ticks from each venue and check for anomalies:
docker compose exec qkt qkt audit-ticks \
--symbol EURUSD --duration 60 --mt5-profile exness \
--reference mt5-history
Expected output:
poll samples: 240
unique in-window ticks: 96
history ticks: 121
exact timestamp matches: 96
exact bid/ask matches: 96
timestamp price mismatch: 0
missing from history: 0
quote age p95 ms: 380
result: PASS
The default reference compares TradingView with MT5. --reference mt5-history is the
appropriate mode when the deployed strategy and execution path both use MT5. Auditing
the Bybit feed is on the roadmap as part of broader broker-tick audit support — see
Planned features.
If you see gaps, out-of-order ticks, or duplicates — investigate before deploying. A flaky feed wrecks even a good strategy.
9. Deploy both strategies¶
docker compose exec qkt qkt deploy /strategies/btc-trend.qkt --as btc-trend
docker compose exec qkt qkt deploy /strategies/eur-meanrev.qkt --as eur-meanrev
Each prints a port:
10. Verify deployment¶
NAME KIND UPTIME PORT TRADES STATE
btc-trend strategy 00:00:18 47291 0 running
eur-meanrev strategy 00:00:14 47292 0 running
11. Watch them work¶
Tail one strategy's logs:
You'll see ticks arrive + rule evaluations. When a condition transitions to true, you'll see the BUY action and the broker submission. Fills come back as TradeEvent a few hundred ms later.
Check status from outside the container:
Returns the full StatusSnapshot — positions, recent trades, equity, pending stack layers, etc.
12. Stop cleanly¶
When you're done (or want to bring everything down):
# Stop strategies one at a time with --flatten to close open positions
docker compose exec qkt qkt stop btc-trend --flatten
docker compose exec qkt qkt stop eur-meanrev --flatten
# Then tear down the stack
docker compose down # keeps qkt-state volume + reports
docker compose down -v # full wipe — state + logs gone
--flatten closes any open positions at market before stopping. Without it, positions stay open on the venue and qkt reconciles them on next start.
What to do next¶
- Adapt the strategies. Change parameters, swap symbols, try different timeframes. Validate with
qkt resync --dry-run, then apply withqkt resync --as <name>. - Add more strategies. Drop more
.qktfiles intostrategies/and deploy them. The daemon assigns each one an ephemeral loopback port. - Backtest first. Don't deploy a strategy you haven't backtested. Run
qkt backtest strategies/btc-trend.qkt --from 2024-01-01 --to 2024-06-01to validate. - Set up alerts. The observability HTTP endpoints (
/status,/events,/health) are scrape-able by Prometheus. See operations/logging.
Common gotchas¶
- Compose can't pull the gateway image. Verify Docker Hub access to
elitekaycy/mt5-gateway-api:0.3.2, or overrideMT5_GATEWAY_IMAGEwith a digest-pinned/private-registry image. - MT5 logs out periodically. Some brokers force daily re-auth. VNC back in, or restart
mt5-gatewayto trigger a re-login attempt. - Bybit testnet vs mainnet.
BYBIT_ENVIRONMENT=testnetkeeps the gateway on testnet; positions/keys/symbols all live there. Don't mix testnet and mainnet keys in the same.env, and setBYBIT_TRADE_MODE=realonly together withBYBIT_ENVIRONMENT=mainnet. - Bind-mount path issues on Mac/Windows. Docker Desktop sometimes needs explicit file-sharing permissions for paths outside your home directory. Keep the project under
~/. - Port collisions. If something else is already on
47291, the daemon picks the next available. Checkqkt listfor the actual ports.
See also¶
- Bundle file listing — every file shown again for copy-paste
- Deploy live on Exness — focused MT5-only walkthrough
- Cross-broker portfolio — same architecture, less commentary
- Operations: deploy with Docker — production hardening notes