 |
August 07, 2026, 08:55:27 AM |
|
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
|