Journaling & reviewing a live system
Keeping a decision journal, running periodic reviews, and comparing live vs backtest — slippage, expectancy drift, degradation — so you can tell a normal drawdown from a decayed edge.
A backtest is judged once. A live system is judged *forever*. Markets change, your broker changes, other traders arbitrage away the inefficiency you found — and edges decay. The job now is not to build; it is to monitor the edge itself and catch its death before it catches your account. That is what journaling and periodic review are for.
The decision journal
Separate from the machine's logs, keep a short human journal — every time you *change* something or *override* the system, write down what you did and, crucially, *why you believed it at the time*. Months later this is the only honest record of whether your judgement adds value or destroys it.
- What changed — parameter tweak, new instrument, size increase, manual intervention.
- Why — the reasoning and the evidence you had *then*, before you knew the outcome.
- Expected effect — what you predicted would happen. This is what makes it falsifiable.
- Reviewed outcome — filled in later: were you right? Most traders discover their "improvements" were noise.
Live vs backtest: the three degradation signals
Every review, load your structured logs (Lesson 2) and compare the live sample to the backtest that justified going live. Three numbers tell you almost everything:
- Slippage — is your realised slippage (intended price vs fill price) worse than the cost model you backtested? Persistent excess slippage quietly eats a thin edge.
- Expectancy — average P&L per trade, live vs backtest. Some shortfall is expected; a large, sustained gap means the backtest was optimistic or the edge is fading.
- Win rate & distribution — is the *shape* of returns the same, or are the winners smaller and losers bigger than history? Distribution drift is an early warning before the average moves.
import json, pandas as pd
class="c"># Load the JSON-lines log the bot wrote in Lesson class="n">2.
rows = [json.loads(l) for l in open(class="s">"bot.log") if l.strip()]
fills = pd.DataFrame([r for r in rows if r[class="s">"kind"] == class="s">"fill"])
live_slippage = fills[class="s">"slippage_bps"].mean()
backtest_slippage = class="n">2.0 class="c"># what your cost model assumed
print(fclass="s">"Live avg slippage: {live_slippage:.2f} bps")
print(fclass="s">"Backtest assumption: {backtest_slippage:.2f} bps")
drift = live_slippage - backtest_slippage
if drift > class="n">1.0:
print(fclass="s">"WARNING: slippage {drift:.1f} bps worse than modelled. Re-check the edge.")
class="c"># Expectancy drift, live vs backtest
pnl = pd.DataFrame([r for r in rows if r[class="s">"kind"] == class="s">"trade_closed"])
live_expectancy = pnl[class="s">"pnl"].mean()
print(fclass="s">"Live expectancy/trade: {live_expectancy:.2f} (backtest: class="n">0.85)")Is it a drawdown, or is it dead?
This is the hardest question in live trading, and it has no clean answer — only a disciplined way to think about it. A losing streak is *expected*: even a great strategy spends real time underwater. The question is whether the current pain is inside the range your backtest already showed you, or beyond it.
Review cadence
Match the frequency of review to the frequency of trading, and never review so often that you act on noise:
- Weekly — a five-minute operational check: any errors, any missed trades, is it healthy?
- Monthly — the real review: live-vs-backtest on slippage, expectancy, drawdown; read the decision journal.
- Quarterly — the big question: does this strategy still deserve its capital, or has the edge decayed enough to retire it?
Reviewing on this cadence — and *resisting* the urge to fiddle in between — is what separates a trader with a process from a gambler with a computer. Which brings us to the final, and hardest, subject of the entire course: you.