PITVÁME·CZ

Testujeme, abyste nemuseli · č. 3

Proč tvůj backtest lže: placebo test za 40 řádků

Každý backtest, který ti kdy někdo ukázal, byl ziskový — jinak by ti ho neukazoval. Většina z nich přitom neměřila strategii, ale štěstí a bull trh. Tohle je nejlevnější detektor sebeklamu, jaký známe: 300 náhodných dvojníků tvé strategie. Kód přiložen, funguje, otestovali jsme jím rok vlastní práce.

17. července 2026 čtení ~7 min python + numpy, kód volně k použití
300náhodných dvojníků
40řádků kódu
12/13našich kandidátů padlo

Znáš to: histogram zisků, křivka rostoucí doprava nahoru, „strategie porazila buy&hold o 30 %". Vypadá to jako důkaz. Jenže backtest umí lhát mnoha způsoby najednou — a ten nejzákeřnější nevyžaduje žádnou chybu v kódu. Stačí, že sis z mnoha nápadů vybral ten, který na minulosti vyšel. My jsme si těmi lžemi prošli všemi. Za rok testování nám „krásné" výsledky ukázalo šest strategií — a placebo test s OOS bránou jich dvanáct ze třinácti popravily dřív, než stály jedinou korunu.

§ 1

Tři lži, které backtest říká nejraději

Na první lež je lék out-of-sample test (vybírej na jedné části dat, suď na druhé). Na druhé dvě je lék placebo.

§ 2

Placebo: 300 náhodných dvojníků

Myšlenka je stejná jako v medicíně. Účinek léku neměříš proti „nic", ale proti cukrové pilulce. Účinek strategie neměř proti buy&hold, ale proti strategii, která dělá totéž co ta tvoje — jen náhodně.

Dvojník zachová všechno, co není signál: stejný trh, stejný počet obchodů, stejné délky držení. Jediné, co se změní, jsou časy vstupů (náhodné) a směr (mince). Vyrobíš 300 takových dvojníků a dostaneš rozdělení: „kolik na tomhle trhu s touhle aktivitou vydělá čistá náhoda". Tvoje strategie musí porazit 95. percentil toho rozdělení. Jinak neměříš informaci — měříš šum.

Obr. 1 · ilustrační schéma

Kde ve výsledcích náhody leží tvoje strategie?

p95 náhody strategie A — šum strategie B — informace p50 p95 průměrný výnos náhodných dvojníků na obchod →
Strategie A vydělala — ale uvnitř rozdělení náhody: totéž zvládne cukrová pilulka. Teprve B, za 95. percentilem, nese informaci. A ani to nestačí (viz §5).

§ 3

Kód

Žádný framework, jen numpy. Vstup: pole zavíracích cen a obchody tvé strategie jako (index_vstupu, index_výstupu, směr):

import numpy as np

def placebo_test(closes, trades, reps=300, seed=42, long_only=False):
    """Random-entry placebo: porazila by strategie 300 náhodných dvojníků?

    closes : pole zavíracích cen (1 svíčka = 1 krok)
    trades : obchody strategie [(entry_idx, exit_idx, side)], side +1/-1
    Vrací (průměrný výnos strategie, p95 náhody, podíl placebů >= strategie).
    """
    closes = np.asarray(closes, dtype=float)
    rets = [s * (closes[x] / closes[e] - 1.0) for e, x, s in trades]
    real = float(np.mean(rets))

    holds = np.array([x - e for e, x, _ in trades])   # držení v barech
    n, rng = len(trades), np.random.default_rng(seed)
    placebo = np.empty(reps)
    for r in range(reps):
        entries = rng.integers(0, len(closes) - holds.max() - 1, size=n)
        exits = entries + rng.permutation(holds)      # stejná držení, jiné časy
        sides = np.ones(n) if long_only else rng.choice((-1.0, 1.0), size=n)
        placebo[r] = np.mean(sides * (closes[exits] / closes[entries] - 1.0))

    p95 = float(np.quantile(placebo, 0.95))
    return real, p95, float((placebo >= real).mean())

# použití:
real, p95, frac = placebo_test(closes, trades, long_only=True)
print(f"strategie {real*1e4:+.1f} bp/obchod | p95 náhody {p95*1e4:+.1f} bp"
      f" | {'PROŠLA' if real > p95 else 'NEPROŠLA'}"
      f" ({frac:.0%} dvojníků bylo lepších)")

Sanity check, který jsme spustili před publikací: náhodná strategie na náhodné procházce neprošla (−10,6 bp vs p95 +80,6 bp; 60 % dvojníků bylo lepších) a podvodník, který zná budoucnost, prošel s přehledem (+525 bp, 0 % dvojníků lepších). Test měří přesně to, co má.

§ 4

Nejdůležitější přepínač: long_only

Tady padá nejvíc dip-buying strategií. Když tvoje strategie jen nakupuje, dvojníci musí taky jen nakupovat. Jinak srovnáváš „long v bull trhu" proti „mince hází long/short" — a lichotíš si.

V našem sanity checku porazily náhodné long-only vstupy v rostoucím trhu ±placebo… a proti long-only placebu neprošly.

Stejný mechanismus zabil případ 010: kupování dipů na 256 coinech „porazilo buy&hold" v desítkách případů — proti long-only placebu prošlo 23/256 (čekali bychom ~13 náhodou) a na majorech 0/14. Iluze nižší expozice, ne edge.

§ 5

Placebo v akci: rok našich testů

kandidátporazil placebo?verdikt
Kupování dipů (majoři)NE — 0/14NO-GO
Trend-following 12m (ETF koš)NE — Sharpe 0,75 vs p95 0,77NO-GO
Vol-targeting na kryptuNE — 0/3 aktivaNO-GO
Order-flow / L2 mikrostrukturaANO — o desítky sigmapřesto NO-GO

Poslední řádek je klíčový: order-flow signál porazil placebo naprosto drtivě — a stejně neprošel, protože gross 1 bp na obchod nezaplatí 36 bp nákladů. Placebo je brána nutná, ne postačující. Odhalí šum a expozici; náklady a lookahead musí hlídat další testy.

§ 6

Checklist, než uvěříš backtestu

Metodika v kostce

Test: random-entry placebo — 300 dvojníků se stejným počtem obchodů a stejnými délkami držení (permutace), náhodné časy vstupů, směr mincí (nebo long-only), brána = 95. percentil.

Ověření kódu: náhodná strategie na náhodné procházce neprošla (60 % dvojníků lepších); lookahead „podvodník" prošel (+525 bp, 0 %); long-only náhoda v bull trhu prošla proti ±placebu a neprošla proti long-only placebu — přesně dle očekávání.

Limity: nechytí lookahead bias ani náklady (na to OOS split + fee model); při překrývajících se obchodech podhodnocuje rozptyl.

Testujeme, abyste nemuseli — série poctivých pitev obchodních strategií. Č. 1: Edge existuje. Jen na něj nedosáhnete. · Č. 2: Grid bot sliboval 8–15 % měsíčně.

Kód v článku je volně k použití (MIT). Nejde o investiční doporučení.

Newsletter

Každá nová pitva do mailu

Žádný spam, žádné signály, žádné sliby zisků. Jen poctivé testy — jednou za pár týdnů, odhlášení jedním klikem.