Bitcoin Forum
August 08, 2026, 04:44:26 AM *
News: COLDCARD users only: critical vulnerability risks funds stored on COLDCARD devices; immediate action required
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [DEV] Signal validation framework: my own backtest killed 3 versions of my bot.  (Read 10 times)
Raul Tejedor (OP)
Newbie
*
Offline

Activity: 2
Merit: 0


View Profile
August 07, 2026, 08:55:27 AM
 #1

I've been building a signal system for perpetual futures and I want to
share the architecture and — more importantly — the results, including
the negative ones, which are most of them.

I'm not here to sell returns. I'm here to show the validation framework,
which is the part I think matters to anyone building their own system.

───────────────────────────────────────────────
1. SIGNAL ARCHITECTURE
───────────────────────────────────────────────

The engine builds a directional score from public OHLCV data, in four
layers:

a) Return separation by magnitude
   Threshold epsilon = 0.15 x standard deviation of the window.
   Returns below it form the "weak" bucket; the rest, "strong".
   Direction is estimated with median/MAD (robust) instead of
   mean/stdev, so a couple of outliers can't dominate the estimate.

   signal    = median(weak) / MAD(weak)
   coherence = sign(median(weak)) == sign(median(strong)) ? +1 : -1
   output    = signal * coherence

b) Volatility regime classification
   Relative dispersion of recent volatility, winsorized at 15% per
   side over a 10-sample window, with a floor at 0.15.
   Ratio median(last 5) / median(full window) defines
   LOW_VOL (<0.7), NORMAL, HIGH_VOL (>1.5).

c) Accumulator with autocorrelation correction
   This is the part I think is most useful in this whole post.

   Return windows overlap: each computation shares almost all its data
   with the previous one. Observations are NOT independent, so a
   classic z-score inflates — precisely when the market is flat and
   internal dispersion collapses.

   Effective sample size correction:

     rho1  = lag-1 autocorrelation (clamped to [0, 0.99])
     n_eff = n * (1 - rho1) / (1 + rho1)
     se    = std / sqrt(n_eff)
     score = mean / se

   Only positive autocorrelation is penalized, since that's what the
   overlap produces. Without this I was seeing 9-sigma scores in
   sideways markets.

d) Adaptive SL/TP
   The same score that gives direction sizes the expected move:

     z_factor = min(|score| / Z_MAX, 1)
     SL = base_sl * (1 - z_factor*0.40) * (2 - consistency)
     TP = base_tp * (1 + z_factor*0.60) * consistency

   With a hard filter: if TP < 1.5 * SL, the trade is discarded even
   when direction is correct. Being right doesn't help if R:R doesn't
   compensate.

───────────────────────────────────────────────
2. VALIDATION FRAMEWORK
───────────────────────────────────────────────

Anti-self-deception rules implemented:

- No look-ahead. At candle i, only data up to i (closed) is used.
  Signal at i -> entry at the OPEN of i+1.
- Pessimistic resolution: if SL and TP are both touched within the
  same candle, SL is assumed.
- Current (unclosed) candle always discarded — prevents repainting
  between runs.
- Real costs: 0.04% taker per side + 0.02% slippage.
- Walk-forward across time blocks.
- Confidence intervals on win rate (the mean alone isn't enough).
- Per-component ablation: each sub-score tested in isolation.
- Break-even computed from the actual average ratio, not assumed.

───────────────────────────────────────────────
3. RESULTS (the part that matters)
───────────────────────────────────────────────

Backtest on BTCUSDT 1h, 8000 candles (Sept 2025 - Jul 2026), official
Binance Vision data:

  Trades            : 107
  Win rate          : 56.1%
  Break-even req.   : 56.0%  (average ratio 1:0.79)
  Margin            : +0.1 points
  Expectancy        : +0.050% per trade (net)
  Profit factor     : 1.03
  Max drawdown      : -8.9%
  Final equity      : $9,873 from $10,000

Translation: statistically indistinguishable from zero. The system
showed no demonstrable edge.

Scalping version on 5m, 4 months, n=1653:
  Win rate 28.1% against a 33.3% break-even (TP=2xSL).
  Final equity: $301 from $10,000. -97%.
  Cause: 13 trades/day paying 0.12% in costs each.

I also backtested a manual exit rule ("close when the signal flips")
over the same period:
  Without the rule : 107 trades, equity $9,873
  With the rule    : 166 trades, equity $9,334
  The rule made it $539 worse. 79 exits on signal reversal, averaging
  -0.937%, only 18 of them green.

───────────────────────────────────────────────
4. BUGS I FOUND IN MY OWN CODE
───────────────────────────────────────────────

Sharing these because they're easy to write and hard to spot:

1. abs() silently killing a condition
   return abs(signal) * abs(coherence)
   Both +1 and -1 became 1: the coherence check filtered nothing.
   Worse, abs(signal) erased the sign, so a clearly bearish series
   produced a POSITIVE score.

2. A metric that was actually a constant in disguise
   "Consistency" came out of an iteration v = 0.7v + 0.3*mean.
   That's a contraction mapping: it ALWAYS converges. The result was
   1.000 in every case. Verified: 1.000000 on stable volatility,
   0.999818 on erratic volatility. It measured nothing.

3. Accidental squaring
   acc.push(signal * anomaly), where anomaly already contained signal.
   The accumulated value lost its direction entirely. Measured:
   +3.426 on a clearly bearish series.

4. Regime decided by a single candle
   The classifier used arr[-1] — the candle still forming. With
   identical underlying volatility, the regime flipped from LOW_VOL
   (tradeable) to HIGH_VOL (blocked) depending on what minute of the
   hour you ran it. The signal changed on its own while nothing real
   changed.

5. A 5-sample window used to measure "stability"
   std/mean over 5 values collapses to ~0 with a single outlier.
   Since consistency multiplies TP, that collapse pushed the target
   below the cost of trading — silently blocking every signal with no
   visible reason.

───────────────────────────────────────────────
5. WHAT I'M OFFERING
───────────────────────────────────────────────

Access to the system and the validation framework for anyone who wants
to evaluate it against their own criteria. Runs on Python (numpy +
requests), no heavy dependencies. Data via Binance/Bybit/OKX with
automatic failover — Colab is geoblocked by Binance (HTTP 451) and the
bot detects it and switches source.

What I'm NOT offering: returns, free signals, or a pretty equity curve.
The numbers above are everything I have and they're public.

If you build your own systems, the validation framework is probably
worth more to you than the system itself.

quantbot.army

───────────────────────────────────────────────

Happy to have you tear the methodology apart. If you spot a bias I
haven't accounted for, that's exactly what I'm after — every bug in
section 4 was found because something (or someone) questioned an
assumption I was treating as settled.

Not financial advice. This is an analysis and validation tool. web : quantbot.army
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!