Monitoring a Trading Bot: Logs, Metrics, and Alerts
A trading bot fails quietly. It does not crash with a stack trace on your screen. It keeps running, keeps sending orders, and keeps losing money while you sleep. The gap between a strategy that survives and one that blows up is usually not the alpha. It is whether you noticed the bot was broken in time to stop it.
This post covers what to log, what to measure, and what to alert on for an automated prediction-market strategy running against a live order book. The examples lean toward Polymarket and Kalshi, but the discipline is venue-agnostic.
Three layers, three questions
Split observability into logs, metrics, and alerts because each answers a different question at a different time.
- Logs answer 'what exactly happened?' after the fact. High detail, high volume, read during a post-mortem.
- Metrics answer 'how is it trending?' continuously. Low cardinality, aggregated, watched on a dashboard.
- Alerts answer 'do I need to act right now?' They should be rare, actionable, and route to a phone.
If you only build one thing first, build metrics and one drawdown alert. Logs help you understand a loss after it happens. An alert helps you prevent it from getting worse.
What to log
Log in a structured, machine-readable format rather than free-form text.
Structured logging means emitting each event as discrete key-value fields, usually JSON, instead of a sentence. The value is concrete: you can filter and aggregate by field instead of writing brittle regex against a message string. A useful pattern is JSON in production and human-readable text in development, which most logging libraries support through output formatters using the same log statements.
For a trading bot, log an event at every decision boundary. At minimum:
- Signal computed: the market ID, the model's fair value, the current best bid/ask, and the resulting decision (buy, sell, hold).
- Order submitted: side, size, limit price, market ID, and a client order ID you generate yourself so you can trace it end to end.
- Order acknowledged, filled, partially filled, or rejected: the venue's response, the fill price, and the rejection reason verbatim.
- Risk check outcome: which envelope rule was evaluated and whether it passed or blocked the order.
- Errors: the full stack trace, the message, and the contextual data that led to the exception, not just the exception object.
Keep field names consistent across every log line. Do not write market_id in one place and marketId in another, because inconsistency defeats the entire point of structured logs. Use UTC ISO-8601 timestamps from a synced clock so you can line up your log with the venue's fill timestamps. And never log venue API keys or secrets.
Attach a correlation ID to every log line tied to a single order lifecycle. When a fill comes back at a price you did not expect, one ID lets you pull the signal, the risk check, the submission, and the ack in a single query.
What to measure
Google's SRE book defines four golden signals for any user-facing system: latency, traffic, errors, and saturation. If you can only measure four things about a service, measure those. They translate cleanly to a trading bot, and you layer trading-specific metrics on top.
The infrastructure signals, adapted:
- Latency: time from signal to order acknowledgement. A creeping order-round-trip latency is an early warning that quotes are stale by the time you act.
- Traffic: orders submitted per minute. A sudden spike often means a loop bug re-firing the same signal.
- Errors: rejected orders and API exceptions as a rate, not a raw count. A rising rejection rate means your assumptions about the book or your balance are wrong.
- Saturation: how close you are to rate limits, and how close open positions are to your maximum. Hitting a rate limit mid-strategy leaves you unable to exit.
The trading-specific metrics are the ones that actually protect capital:
- Realized and unrealized PnL, updated per fill and marked to the current mid.
- Drawdown: current equity against the running peak. This is the single most important number to alert on.
- Open position count and total notional exposure, per market and in aggregate.
- Fill rate and slippage: how often your limit orders fill, and the gap between expected and actual fill price. Widening slippage means the market is moving against you or your prices are too passive.
- Position age: how long each position has been open versus what the strategy expected.
What to alert on
Good alerts are rare and actionable. If an alert fires and you do nothing, delete it. The goal is to nag a human only when a problem is real and ongoing, not for every transient blip.
The alerts worth waking up for:
- Drawdown breaches a daily loss threshold. This is the one that stops a slow bleed from becoming a large one.
- Order rejection rate crosses a ceiling over a short window. Repeated rejections usually mean the bot's view of the world is stale.
- The bot has stopped sending orders or heartbeats when it should be active. Silence is a failure mode too, and a bot that dies during a moving market can leave you exposed with no exit.
- Open positions or notional exceed the configured maximum. If this fires, your risk logic already failed and you need to intervene.
- Latency or slippage well outside normal range, which flags a degrading connection or a market moving faster than you can react.
Every hard limit should have an automated response, not just a notification. A daily loss stop that only sends a text is not a stop. The bot should flatten or halt on its own, and the alert tells you it happened.
Alerts are not a substitute for a kill switch
Monitoring tells you something is wrong. It does not fix anything. The layer that actually protects capital is a risk envelope that the strategy cannot override: a per-trade cap, a daily loss stop, a maximum open-position count, and a kill switch that halts trading when a limit trips.
This is the model Banger enforces. You write your strategy as a Python class, but the risk envelope is declarative and sits outside your strategy code, so a bug in the strategy cannot spend past its cap. Before any of it touches real money, you paper-trade against the live order book to see how the strategy and its alerts behave under real conditions. Banger never holds your funds; you connect your own venue keys.
# Paper-trade against the live book first, then watch your metrics before going live
pip install bangertrades
banger run strategy.py --paperThe order matters. Instrument the strategy, run it on paper until the metrics and alerts prove they behave, then go live with a hard risk envelope underneath. Logs explain the loss after the fact. Metrics show it building. The kill switch is what keeps a bad afternoon from becoming a bad month.
Sources
- Monitoring Distributed Systems (Google SRE Book)
- SRE Metrics: Core SRE Components and the Four Golden Signals of Monitoring | Splunk
- Structured Logging Best Practices (2026) | LogPulse
- Structured Logging Best Practices — JSON Logs, Context, and Tools | LogMonitor
- Structured Logging Best Practices | DEV Community (Uptrace)