Skip to content
← All work

Live

Momentum portfolio bot

Rebalances a crypto basket every 3 days on Binance futures. The backtest drives the live code itself.

  • Node.js
  • ccxt
  • node-cron
  • Supabase
  • pm2
[Add equity chart screenshot]

The problem

A backtest only means something if it behaves exactly like the code that trades. Most setups write a fast “scan” engine that imitates the live worker — and hope the two agree.

What broke — twice

First: a scan engine and the live step() matched on only 84% of entries. Different strategy, same name. Caught before going live.

Second, subtler: even with identical code, the bar model checked cancel before fill. A limit order that touched entry and then closed outside the zone counted as “no trade” — on the exchange it had already filled and lost. Switching to fill-before-cancel took expected R from +0.224 to −0.04 and max drawdown from 10% to 30%.

Rules that came out of it

  1. The backtest drives the real live step() over history — no look-alike engine.
  2. A separate fast engine must entry-match the live code at ≥98% before its numbers count.
  3. Model fills conservatively: price touches the level = filled.
  4. Entry-match a new paper worker at ~10 trades, then flip small with real money.