Futures momentum bot: the printed profit is a restart artifact
Subject: a multi-timeframe momentum bot trading major crypto perpetual futures on Binance, running as a paper original and a demo-account copy. Every figure below was reproduced from raw logs and public exchange data.
No evidence of an edge before or after costs. The bot’s printed total of +$53.66 comes from three June positions closed at September prices after a 93-day pause. On the 343 trades that ran normally, the bot loses money on every symbol, in both directions, and on every day since restart.
1. Scope and sources
| Claim under test | Source of truth | Result |
|---|---|---|
| Bot’s cumulative “Total” line is its trading profit | Trade log, rebuilt trade by trade | Not reproduced |
| Entries and exits happen at logged prices | Binance public 1-minute klines | Confirmed, stop overshoot noted |
| Signals use only information available at entry | Code review and feature replay | Confirmed, 3 minor data defects |
| The demo copy reproduces the paper bot | Demo account sync log vs paper log | Not reproduced |
Read-only engagement. No API keys were requested or used; no orders were placed or cancelled. Fees modelled at 5 bp per side (Binance USDⓈ-M taker); a stress case adds 2 bp per side of slippage.
2. Scorecard
| Dimension | Score | Basis |
|---|---|---|
| Code correctness | 2 / 5 | No fee accounting; stats reset double counts |
| Data integrity & look-ahead | 3 / 5 | No look-ahead in signals; unclosed bar in ATR |
| Accounting truth | 1 / 5 | Printed total overstated by $107.61 |
| Execution realism | 2 / 5 | Fills at last price; stops overshoot median 4.2 bp |
| Live safety & state | 1 / 5 | Stale positions restored; demo positions deleted silently |
| Operational health | 4 / 5 | No errors in 24 h; ~31 s loop |
| Statistical evidence | 1 / 5 | CI excludes zero — on the losing side |
| Claims vs reality | 1 / 5 | Earlier internal figure of +$57.09 not supportable |
3. Restated PnL
| Line | Amount |
|---|---|
| Total printed by the bot | +$53.66 |
| Remove: 3 June positions restored from state and closed at September prices on restart (HYPE +68.98, ETH +48.07, SOL −56.75) | −$60.30 |
| Remove: two statistics resets on June 6 counted twice in the running total | −$9.11 |
| = Clean trading result before fees (343 trades) | −$15.75 |
| Add: taker fees at 5 bp per side, never charged in code | −$38.20 |
| Verified net result | −$53.95 |
| Stress: plus 2 bp slippage per side | −$69.23 |
20 further June positions were never closed in the log; their PnL is unknown and excluded rather than estimated.
4. Statistical evidence
| Slice | Trades | Net after fees | Per trade |
|---|---|---|---|
| All clean trades | 343 | −$53.95 | −$0.157 |
| June segment | — | −$22.25 | — |
| Sep 8 onward | — | −$31.70 | — |
| Demo-account copy (closes recorded) | 47 | −$9.32 | t = −2.6 |
Per-trade mean after fees is −$0.157, 95% confidence interval [−$0.253, −$0.061]. The interval excludes zero on the losing side. Every symbol and both directions are negative after fees, and so is every calendar day from September 8 to 14. No subset was selected after looking at results.
5. Findings
Stale positions restored across a 93-day pause
- Evidence
- Restart log 2026-09-07 23:51:08 restores 3 positions opened in June and closes them within the first loop at current prices.
- Impact
- +$60.30 of the printed total — more than the entire reported gain.
- Fix
- On start, refuse to restore any position older than its maximum holding time; close or quarantine it and log the adjustment separately from trading PnL.
- Status
- Confirmed
No trading fees in PnL
- Evidence
- PnL computed as price difference × size with no fee term,
bot.py:340–344. - Impact
- −$38.20 on 343 trades; turns a small loss into a statistically clear one.
- Fix
- Charge the venue’s taker rate on both legs of every fill; store fee as its own field.
- Status
- Confirmed
Demo copy loses positions to a shared account
- Evidence
- 83 of 133 opens vanished: the exchange sync deleted them with no PnL after another bot’s opposite trades netted the same symbols. 440 entries were skipped because of positions no running bot owned.
- Impact
- Demo results cannot validate the paper bot; slippage cannot be measured because demo fill prices are not recorded.
- Fix
- One sub-account (or hedge mode) per bot; record order responses and fill prices; close positions on stop.
- Status
- Confirmed
Statistics reset double counts the running total
- Evidence
- Two resets on June 6 re-add the pre-reset balance.
- Impact
- +$9.11 overstatement in the printed total.
- Fix
- Derive totals from the trade ledger on demand instead of a mutable counter.
- Status
- Confirmed
Stop-loss exits overshoot
- Evidence
- Stops are checked on a ~31 s loop at last price; overshoot vs the stop level is median 4.2 bp, p90 21.8 bp.
- Fix
- Place a resting reduce-only stop order on the exchange at entry.
- Status
- Confirmed
Three data defects in features
- Evidence
- ATR includes the unclosed hourly bar (
:100); next-day market name breaks on the last day of a month (:125); hourly market lookup assumes a fixed UTC−4 offset with the UTC date (:121). - Impact
- Small today; the UTC−4 assumption breaks at the November DST change.
- Status
- Confirmed
Messaging credential committed in source
- Evidence
- A notification bot token is hard-coded in both copies (
:19). Redacted in this report. - Fix
- Rotate the token; load it from an environment file with 600 permissions.
- Status
- Confirmed
6. Recommended actions
- Stop the demo copy first — its trades distort the other bot sharing the account (F-03).
- Stop the paper original and remove it from the fleet list.
- Close the orphan positions on the demo account.
- Correct the earlier internal +$57.09 figure wherever it is still referenced.
- Rotate the committed token (F-07).
- If the signal is worth researching, run it signal-only with fees, with the pre-registered criteria below — do not resume trading.
| Pre-registered signal-only test | Criterion |
|---|---|
| Metric | Net per-signal return after 10 bp round-trip costs |
| Split | First 70% of days explore, last 30% holdout, used once |
| Pass | Holdout mean > 0 with day-clustered 95% CI lower bound > 0 |
| Fail | Holdout mean ≤ 0, or explore and holdout disagree in sign |
Appendix — Method
Trades rebuilt from raw logs, not the bot’s summaries. Entry and exit prices checked against public 1-minute klines. Fees applied to every fill. Confidence intervals by bootstrap clustered on calendar day. Findings marked Confirmed were reproduced by script; scripts are delivered with the report.