Audits › Controls › Auditable log
Accounting and reconciliation · control 13 of 21
Auditable log: does your trading bot have it?
Does it keep a persistent record of every decision and order: time, reason, size, and the exchange's response?
Why it matters
Without a record nobody can tell what happened, and there is nothing to show the exchange in a dispute.
How to check it in the code
- Search for logger, log_trade, journal, trades.db, csv.
- Check the log includes the reason for the decision, not only the order.
- Check the log survives a restart (file or database, not only stdout).
This is what the audit does for every bot in the list, on public code, without installing or running anything. Verdict values: present, partial, absent, not applicable, not verified. See the method.
Results across audited bots
Across 10 audited bots: 9 present, 1 partial, 0 absent, 0 not applicable, 0 not verified.
| Bot | Verdict | Evidence | Note |
|---|---|---|---|
| HKUDS/Vibe-Trading | Present | agent/src/live/audit.py: append-only audit.jsonl (fsynced every write) plus a hash-chained tamper-evident copy audit_chain.jsonl via src/governance/ledger.py; secrets redacted via src.tools.redaction.redact_payload before any write | Also fans out to per-run trace and SSE bus. |
| hummingbot/hummingbot | Present | hummingbot/client/command/stop_command.py references self.trading_core.markets_recorder; hummingbot/model/ contains SQL-backed models (e.g. funding_payment.py) persisting trading data locally | A persistent recorder captures market/order/trade data to a local database. |
| Drakkar-Software/OctoBot | Present | Extensive self.logger.info/debug/warning/error/exception calls throughout index_trading.py and ai_index_trading.py log every rebalance step ('Step 1/3...3/3'), every AI distribution decision (asset, percentage, action, explanation), and full debate/judge history when log_ai_decisions is enabled. | Logging is per-decision and per-order-step, not just a generic catch-all. |
| freqtrade/freqtrade | Present | freqtrade/freqtradebot.py (logger.info/warning/exception used throughout); docs/advanced-setup.md docker-compose example with '--logfile /freqtrade/user_data/logs/freqtradeN.log'; freqtrade.persistence Order/Trade models persisted to SQLite -- URLs as above | Standard Python logging to file plus a persistent SQLite database of every Trade/Order (amount, price, fees, timestamps, state) that survives restarts. |
| jesse-ai/jesse | Present | jesse/config.py ('env.logging' has explicit booleans for strategy_execution, order_submission, order_cancellation, order_execution, position_opened/increased/reduced/closed, balance_update, exchange_ws_reconnection) + jesse/services/logger.py + jesse/controllers/live_controller.py ('/live/download-log/{session_id}' endpoint) + jesse/services/failure.py (persists exception + traceback to live_session_repository) | Persistent, structured logging of orders/positions/decisions is present and downloadable per session. |
| chrisleekr/binance-trading-bot | Present | docs/operations/kill-switch.md ("Every on and off is written to the profile's audit log"); apps/api/src/routes/kill-switch.ts (c.set('auditEvent', {...}) on every route) | Kill-switch and symbol-pause actions are written to a persistent per-profile audit log with event name, target and timestamp; the broader notifier event taxonomy (order-filled, order-failed, override-unresolved, etc.) implies persisted records beyond the push notification itself. |
| alsk1992/CloddsBot | Present | src/trading/logger.ts TradeLogger persists every trade (id, platform, marketId, side, price, size, filled, cost, fees, orderId, status, timestamps) to SQLite via the Database module, with real-time events. | A persistent, structured trade log exists and is the basis for PnL/fee reporting. |
| Lumiwealth/lumibot | Present | lumibot/traders/trader.py `_set_logger()`: 'Live trades should always have full logging for both console and file' (file handler added via add_file_handler). docs/FAST_ORDER_LIFECYCLE_GUIDE.md recommends a structured telemetry contract (order.submit.request, order.cancel.response, etc.). docs/ENV_VARS.md documents `LUMIBOT_BACKTEST_AUDIT` per-fill audit columns for backtests. | |
| YizhiSong/FriesTrader | Present | trade_log.jsonl is append-only (README 'Why this is safer than it sounds') with a distinct stage per event type (risk_check, stop_loss, take_profit, conviction_trim, order, loss_limit_check, cycle_summary); every order entry carries proposal_date, order_id, order_state, fill_price, fill_quantity (PHASE_B_TASK.md Step 6). trade_log_template.jsonl documents the exact line shapes. | Strong, structured, timestamped audit trail. |
| c9s/bbgo | Partial | pkg/bbgo/environment.go (OrderService/TradeService insert filled/canceled orders and trades into SQL DB); .env.local.example (DB_DRIVER/DB_DSN) | Logging via logrus is pervasive, and orders/trades are persisted with detail when a database is configured, but the database is optional (only wired up if DB_DRIVER/DB_DSN env vars are set) so there is no guaranteed persistent audit trail out of the box. |
If your bot does not have it
The watchdog enforces daily loss, drawdown, position size and heartbeat limits from outside the bot, with a read-only key, whatever the bot's own code does.