Analiza · trend_pullback · macaklin

Gdje prestaje prednost

Prednost tvoje mean-reversion strategije traje točno tri dana. Nakon toga se pretvara u gubitak — i to je najjasniji rezultat u cijeloj analizi.

Tradeova: 616 Simbola: 8 Razdoblje: 08.2022 – 07.2026 Izvor: data/backtests/*.csv

Sažetak

Tri nalaza

Vremenski izlaz

Prednost umire nakon 3. bara

Tradeovi zatvoreni unutar 3 dana: +1,31% prosječno, 84% pogodaka. Tradeovi koji prežive 4 dana i više: −1,58% prosječno, 32% pogodaka. Prijelaz je nagao, ne postupan.

Stop

Rep gubitaka je nesrazmjerno velik

12,7% tradeova završi ispod −3% i nose 75% svih gubitaka. Deset najgorih tradeova samo po sebi je 21% ukupnog gubitka. Najgori pojedinačni: −19,55% (TSLA).

Fiksni vs ATR

Jedan postotak ne odgovara svim dionicama

Najgori trade na SPY-u je −6,65%, na TSLA −19,55%. Isti stop od 3% na SPY-u je normalan, a na TSLA se okida na običnom šumu. To je cijeli argument za ATR.

Prije svega — strukturni nalaz

bot/backtest.py uopće ne simulira stop-loss, a bot/main.py ga uživo primjenjuje (check_stop_loss, STOP_LOSS_PCT = 0.03). To znači da tvoj backtest ne opisuje ono što tvoj bot radi. Onaj trade od −19,55% live bot nikad ne bi imao — bio bi zatvoren oko −3%. Sve brojke u ovoj analizi zato su donja granica stvarnosti, a paritet backtest↔live ti je trenutno slomljen na risk sloju.

Nalaz 1

Vremenski izlaz

Strategija kupuje dip u uzlaznom trendu i čeka odskok. Ako odskok dođe, dođe brzo. Podjela svih 616 tradeova po trajanju pokazuje da se prijelaz iz dobitka u gubitak događa između trećeg i petog bara — i to nije blagi pad nego preokret.

Prosječan rezultat po tradeu, prema trajanju
616 zatvorenih tradeova, trend_pullback, dnevni barovi
Prva dva stupca nose gotovo sav profit strategije. Od četvrtog bara nadalje svaka skupina je u minusu, a skupina 11–20 barova nema nijedan dobitni trade. Prijeđi mišem preko stupca za broj tradeova i postotak pogodaka.
Što se dogodi s tradeovima koji prežive N barova
Preživi dulje odTradeovaUdioProsjekPogodaka
1 bara50181,3%+0,245%63,7%
2 bara29447,7%−0,895%42,9%
3 bara18830,5%−1,583%31,9%
5 barova8113,1%−3,259%14,8%
7 barova335,4%−5,125%6,1%
10 barova91,5%−6,142%0,0%

Označeni redak je točka preokreta: čim trade preživi drugi bar, prosjek te skupine pada u minus.

Statistička ograda — pročitaj ovo

Ovo još nije dokaz da vremenski izlaz zarađuje. Postoji pristranost odabira: strategija izlazi na snagu (RSI(2) > 70), pa trade koji traje dugo traje dugo upravo zato što nije odskočio. Duga trajanja su djelomično posljedica gubitka, ne uzrok.

Ono što ovi podaci dokazuju jest da je populacija dugih tradeova jako loša i da vremenski izlaz treba ozbiljno testirati. Ono što ne mogu pokazati jest po kojoj bi se cijeni izašlo na 3. baru — za to trebaju cijene, ne samo zapisi o tradeovima. Zato je uz ovu analizu i skript koji to mjeri kako treba.

Nalaz 2

Stop i rep gubitaka

Strategija ima 68,2% pogodaka, ali prosječan gubitak (−3,04%) veći je od prosječnog dobitka (+2,03%). To je normalno za mean reversion. Problem nije prosjek nego rep: mali broj vrlo loših tradeova nosi većinu ukupnog gubitka.

Tradeovi ispod pragaBrojUdio svihZbroj gubitkaUdio svih gubitaka
−2%10216,6%−507,8 pp85,3%
−3% (tvoj live stop)7812,7%−448,3 pp75,3%
−5%315,0%−262,6 pp44,1%
−7%152,4%−167,0 pp28,1%
−10%71,1%−100,6 pp16,9%

pp = postotni bodovi, zbroj pnl_pct po tradeu. Ukupan zbroj svih 616 tradeova je +258,6 pp.

Zašto ovdje ne dajem broj "koliko bi stop zaradio"

Naivan izračun — odsijeci svaki gubitak na −3% — daje +214 pp poboljšanja. Taj broj je lažan i namjerno ga ne stavljam u zaključke.

Razlog: stop se okida na intrabar minimumu, ne na konačnom rezultatu. Trade koji je završio na +1,5% možda je usput pao na −4% i bio bi izbačen s gubitkom. Odsijecanje računa samo korist, a ne i cijenu — a cijena su prerano zatvoreni dobitnici. Pravi odgovor traži prolazak kroz low svakog bara, što skript radi.

Nalaz 3

Zašto ATR, a ne fiksni postotak

Rezultat po simbolu pokazuje da strategija radi na šest od osam dionica, a pada na dvije. Zanimljivo je koje su to dvije.

Zbroj rezultata po simbolu
postotni bodovi, zbroj svih tradeova po simbolu
TSLA i AAPL su jedini negativni. TSLA je uz to najvolatilnija dionica u skupu i ima najgori pojedinačni trade (−19,55%). Prijeđi mišem preko stupca za detalje.

Fiksni stop od 3% na SPY-u je otprilike dvostruki dnevni raspon — razuman prostor za disanje. Na TSLA je 3% često manje od jednog prosječnog dnevnog raspona, pa se stop okida na običnom šumu, prije nego strategija uopće dobije priliku. Isti broj, potpuno različito značenje.

ATR to rješava time što stop mjeri u jedinicama volatilnosti same dionice umjesto u postocima. Stop na ulaz − 2 × ATR(14) daje TSLA širok prostor, a SPY-u uzak, automatski i bez ručnog podešavanja po simbolu. Posljedica: ako uz to veličinu pozicije računaš iz udaljenosti do stopa, rizik u eurima postaje jednak na svakom simbolu — što ti trenutni MAX_POSITION_PCT = 0.10 ne daje, jer fiksira iznos pozicije, a ne rizik.

SimbolTradeovaPogodakaProsjekUkupnoNajgoriProsj. barova
NVDA8868,2%+1,04%+91,6−17,06%3,5
META7171,8%+1,08%+76,8−12,05%3,4
AMZN7774,0%+0,60%+46,2−7,97%3,1
MSFT7074,3%+0,41%+28,7−5,64%2,9
GOOGL8269,5%+0,31%+25,0−9,16%3,0
SPY9373,1%+0,24%+22,5−6,65%2,9
AAPL7557,3%−0,06%−4,3−6,78%3,3
TSLA6053,3%−0,46%−27,8−19,55%3,3

Sljedeći korak

Skript koji mjeri ono što ovi podaci ne mogu

U scripts/analyze_exits.py je gotova analiza koja prolazi kroz stvarne barove i simulira 18 kombinacija pravila izlaza. Provjerava stop intrabar preko low, a kod gapa izlazi po open, ne po stopu — dakle ne uljepšava rezultat.

cd D:\macaklin
.venv\Scripts\activate
python -m scripts.analyze_exits

Podrazumijevano vrti tvoj trend_pullback portfelj (AAPL, MSFT, SPY), 1000 dnevnih barova, trošak 5 bps po strani, i dijeli podatke 60/40 na in-sample i out-of-sample. Opcije:

python -m scripts.analyze_exits --symbols AAPL MSFT SPY NVDA GOOGL TSLA --bars 1500
python -m scripts.analyze_exits --fee-bps 10     # pesimističniji trošak
python -m scripts.analyze_exits --split 0        # bez podjele, sve odjednom

Što uspoređuje

Kako čitati rezultat

Arhitektura

Zašto ovo ne ide u strategiju

Tvoj Strategy.evaluate(df) → Signal je čista funkcija nad cijenama i ne zna ništa o poziciji — nema ulaznu cijenu ni broj barova držanja. I ATR stop i vremenski izlaz ovise upravo o tome. Ako ih ugurate u strategiju, čista funkcija prestaje biti čista i gubiš paritet backtest↔live koji si namjerno izgradio.

Ispravno mjesto je zaseban sloj — ExitPolicy u bot/services/exits.py — koji prima stanje pozicije i vraća odluku o izlazu. Isti objekt onda koristi i backtest.py i main.py, pa je stop simuliran identično kako se izvršava. U skriptu je već napisan i radi; kad odlučiš koje parametre želiš, premjesti ga iz scripts/ u bot/services/ i priključi na oba mjesta.

Redoslijed provjere unutar bara

Skript koristi: stop → signal strategije → vremenski izlaz. Stop ide prvi jer je najkonzervativniji; ako bar otvori ispod stopa, izlaz je po cijeni otvaranja, ne po stopu. Zadrži isti redoslijed u main.py — tamo check_stop_loss već ide prije strategija, što je točno.

Ograničenja

Što ova analiza ne pokriva