4. syyskuu 2026 · backtesting

Sekä stop-loss että tavoitehinta osuivat saman kynttilän aikana. Kumman backtest valitsi?

Sekä stop-loss että tavoitehinta osuivat saman kynttilän aikana. Kumman backtest valitsi?

Pitkä positio 84,120:ssa. Stop-loss 84,036:ssa, tavoitehinta 84,271:ssa. Seuraavan minuutin kynttilä muodostuu: avaus 84,118, ylin 84,290, alin 84,010, päätös 84,240.

Molemmat tasot osuvat kynttilän sisälle. Stop-lossiin osuttiin ja tavoitehintaan osuttiin, eikä neljästä OHLC-luvusta saa lainkaan tietoa siitä, kumpi osui ensin. Backtestisi palautti silti luvun. Jossain silmukassa jokin rivi teki päätöksen — luultavasti rivi, jota et koodatessasi pitänyt mallinnusoletuksena.

Tämä on suurin yksittäinen valheellisen tuoton lähde, jonka näen lyhyen aikavälin strategioissa. Se menee kulujen ja slippagen edelle, koska se ei näytä oletukselta. Se näyttää tekniseltä toteutukselta.

Väärä tapa yksi: anna if-ketjun päättää

Tavallinen rakenne:

if bar.high >= target:
    exit(target, "tp")
elif bar.low <= stop:
    exit(stop, "sl")

Kukaan ei valinnut sääntöä ”tavoitehinnat ratkaistaan ennen stop-loss-tasoja”. Tavoitehinnan tarkistus vain kirjoitettiin ensin, koska se on suotuisa polku ja se oli mielessäsi. Vaihda haarojen järjestys, ja tuottokäyrä muuttuu. Jo tämän pitäisi kertoa, että strategian tulos riippuu osittain editoristasi.

Ajoin tarkoituksella tavallisen keskiarvoon palautuvan scalping-strategian BTCUSDT-perpetuaalilla: 3 kuukautta 1 minuutin kynttilöitä, 4,812 kauppaa, stop-loss 0.10% ja tavoitehinta 0.18% sisäänmenosta. Samat signaalit, samat kulut, vain tasatilanteen ratkaisusääntö vaihtui.

12.6%kaupoista osui molempiin tasoihin yhden kynttilän aikana
2.31Sharpe, tavoitehinta ratkaistaan ensin
0.18Sharpe, stop-loss ratkaistaan ensin
0.94Sharpe, ratkaistu 1 sekunnin kynttilöillä

Kahdeksasosa kaupoista ratkaisee koko tuloksen. Näin käy, kun stop-loss ja tavoitehinta ovat lähellä toisiaan: epäselvät kaupat ovat niitä, joissa hinta liikkui molempiin suuntiin, eli useimpia kiinnostavia kauppoja, ja jokaisen arvo vastaa koko stop-lossin ja tavoitehinnan välistä matkaa sen mukaan, miten kolikko sattuu pyörähtämään. 12.6% kaupoista × 0.28% hintaväliä on 3.5% bruttonimellisarvoisesta vaihdosta otosyksikköä kohden, mikä on moninkertaisesti strategian todelliseen etuun verrattuna.

Osuus riippuu kynttilävälin koosta suhteessa tasojesi etäisyyteen, ja pahenee nopeasti kynttilävälin pidentyessä. Sama stop-loss ja tavoitehinta, samat signaalit, uudelleen näytteistettynä:

KynttiläväliKaupat, joissa molemmat tasot ovat saman kynttilän sisälläSharpe (tavoitehinta ensin)
1s0.3%0.91
1m12.6%2.31
5m34%3.60
15m49%4.42
1h71%5.88

Mieti, mitä taulukko oikeastaan kertoo. Karkeammat kynttilät paransivat backtestin tulosta. Jokainen tutkija olettaa vaistonvaraisesti tuntikynttilöiden olevan konservatiivinen valinta: vähemmän kohinaa ja vähemmän markkinamikrorakenteeseen ylisovittamista. Mutta jos kynttilänsisäinen ratkaisusääntö suosii sinua, karkeampi kynttilä on vain suurempi laatikko, jonka sisällä voit olettaa olleesi onnekas. 1 tunnin kynttilöillä 7 kauppaa 10:stä riippuu pelkästä sopimuksesta. Backtest ei testaa strategiaa, vaan sen, missä järjestyksessä kirjoitit kaksi `if`-lausetta, 3,400 kertaa.

Väärä tapa kaksi: oleta stopin täyttyvän stop-hintaan

Oletetaan, että korjaat järjestyksen. Stop-loss ratkaistaan ensin, kirjaat tappioksi täsmälleen 0.10% plus taker-maksun ja tunnet toimineesi huolellisesti. Silti kaksi eri asiaa on pielessä.

Ensinnäkin stop on laukaisin, ei täyttö. Binance USDⓈ-M:ssä STOP_MARKET-toimeksianto muuttuu markkinatoimeksiannoksi heti, kun laukaisuehto täyttyy, ja syö sitten toimeksiantokirjan tarjonnan. Rauhallisena minuuttina siitä tulee pari tickiä slippagea. Minuuttina, joka todella laukaisi stop-lossisi — sellaisena, jossa kynttilän runko on 40 pistettä ja alla on likvidointikaskadi — toimeksiantokirja on ohut juuri siltä puolelta, jota olet ylittämässä. Otoksessani tick-aineistoon täsmäytettyjen stop-laukaisujen mediaanitäyttö oli 1.4 bps laukaisutason ohi ja 95. persentiili 11 bps. Kun stop-loss on 10 bps, häntätapaus maksaa ylimääräisen kymmenesosan siitä riskistä, jonka luulit määritelleesi.

Toinen ongelma on hienovaraisempi ja ominainen perpetual-futuureille: mikä hinta laukaisee sen. Binance käyttää stop-toimeksiannoissa oletusarvoisesti mark-hintaa, joka muodostetaan indeksistä ja tasoitetusta basis-erosta, ei kyseisen pörssin viimeisimmästä kaupasta. OHLC-sarjasi perustuu viimeisimpään hintaan. Ne ovat eri sarjoja, ja ero on suurimmillaan juuri stopit laukaisevien tapahtumien aikana.

Viimeisin hinta (kynttilädatasi)Mark-hinta (oletuslaukaisin)
Lähdetämän pörssin kaupatusean pörssin indeksi + basis-ero
Hintavarjon käyttäytyminenkoko liikevoimakkaasti tasoitettu
Tyypillinen ero1–3 bps rauhallisena, 20–35 bps kaskadiminutilla
Vaikutus backtestiinstopit, jotka laukeavat vaikka niiden ei olisi pitänyt, ja päinvastoin

Niinpä viimeisimmän hinnan aineiston 25 bps:n hintavarjo sulkee positiosi backtestissä, vaikka live-mark-hinta ei koskaan käynyt 10 bps:n päässä laukaisutasostasi. Tai päinvastoin, päivänä jolloin indeksi liikkuu ja pörssisi tulee jäljessä. Jos asetat workingType arvoksi CONTRACT_PRICE, saat ainakin live-käyttäytymisen vastaamaan dataasi. Tutkijalle se on yleensä oikea valinta, sillä mark-hinnan laukaisun rehellinen simulointi edellyttää toisen aikasarjan kuljettamista koko täyttömoottorin läpi.

Parhaiten mieleeni jäänyt esimerkki: joku tiimistämme ”paransi” strategiaa siirtämällä take-profitin 0.18%:sta 0.21%:iin. Sharpe nousi 2.3:sta 3.1:een. Uutta etua ei löytynyt. Tavoitehinta oli vain siirtynyt 1 minuutin hintavarjojen jakauman paksuimman osan ulkopuolelle, joten harvempi kauppa päätyi epäselvään luokkaan, jossa koodi huomaamatta antoi niille voiton. He olivat optimoineet tasatilanteen ratkaisusääntöä.

Väärä tapa kolme: oleta aina pahin ja kutsu sitä konservatiiviseksi

Vaistomainen korjaus on pessimismi. Jos molempiin tasoihin osutaan, kirjataan stop-loss. Valmista, ei enää optimismia, julkaisuun.

Tein ennen itsekin näin. Se on parempi kuin vaihtoehto, mutta silti väärin kahdesta syystä.

Se hylkää toimivia strategioita. Pessimistinen ratkaisu 12.6%:ssa kaupoista vei tältä strategialta 2.1 Sharpe-pistettä verrattuna tick-datalla ratkaistuun 0.94:ään. Jos todellinen luku on 0.94 ja ratkaisusääntösi näyttää 0.18, hylkäät idean ja alat työstää jotain huonompaa. Kahdella Sharpe-pisteellä pieleen menevä konservatiivisuus ei ole konservatiivisuutta, vaan kohinaa, jolla on moraalinen asenne.

Pahempaa on, että se vääristää optimointia. Kun parametrien haku käyttää pessimististä tasatilanteen ratkaisua, optimoija oppii välttämään epäselvyyttä, koska epäselvyydestä tulee puhdas rangaistus. Se päätyy suosimaan leveitä stop-losseja ja lähellä olevia tavoitehintoja tai hitaita kynttilöitä, joissa nämä kaksi tasoa osuvat harvoin samaan kynttilään. Sitten se esittää parametreja, jotka on valittu täyttösääntöäsi eikä markkinaa vasten. Sama virhe kuin suopeassa ratkaisussa, mutta päinvastaisella merkillä, ja yhtä näkymätön tulosraportissa.

Nyrkkisääntömme ennen kaikkea muuta: jos stop_distance + target_distance on pienempi kuin kynttilävälin vaihteluvälin 75. persentiili, kynttilänsisäinen oletus vaikuttaa tulokseen enemmän kuin signaalisi. Laske molemmat luvut. Siihen menee 4 riviä koodia, ja tämä tarkistus on päättänyt useamman strategia-arvion kuin mikään muu yksittäinen asia.

Mikä oikeasti toimii

Kynttilänsisäinen hintapolku on dataa. Hanki se tai rajaa se, mitä et voi saada.

  1. Ratkaise tilanne tarkimmalla saatavilla olevalla sarjalla. Binancen aggTrades-data oleellisilta minuuteilta sisältää muutaman sata riviä ja ratkaisee kysymyksen suoraan: kumpaan tasoon osuttiin ensin ja millä hinnalla pyyhkäisy täyttyi. Et tarvitse tick-dataa koko backtestiin, vain epäselville kynttilöille. Otoksessani niitä oli 606 minuuttia 129,600 minuutista. Se on pieni lataus, ei infrastruktuuriprojekti.
  2. Jos tick-dataa ei ole saatavilla, siirry ratkaisua varten yhden tai kahden aikavälin verran tarkempaan dataan. Signaalit 15 minuutin kynttilöistä, poistumiset ratkaistaan 1 sekunnin tai 1 minuutin kynttilöillä. Epäselvien tapausten osuus putoaa 49%:sta murto-osaan prosentista, ja jäljelle jäävä osuus on niin pieni, että sen voi perustellusti sivuuttaa.
  3. Raportoi vaihteluväli aina. Aja jokainen backtest kahdesti, optimistisella ja pessimistisellä ratkaisulla, ja tulosta molemmat Sharpet ratkaistun tuloksen viereen. Tämä hajonta kuvaa kynttilänsisäistä epävarmuutta, ja sen kuuluu näkyä tulosraportissa Sharpen luottamusvälin vieressä. Kun vaihteluväli on 0.2–2.3, sen sisällä ei voi tehdä luotettavia johtopäätöksiä.
  4. Seuraa epäselvien tapausten osuutta omana päämittarinaan. Meillä se näkyy jokaisen strategian yhteenvedon yläosassa kauppamäärän ja vaihtuvuuden vieressä. Jos osuus ylittää noin 5%, testissä on poistumislogiikka, ei sisäänmenologiikka.
  5. Mallinna laukaisu erikseen täytöstä. Käytä laukaisussa pörssin todella käyttämää hintasarjaa; täytä toimeksianto laukaisuhinnan ja aineistolla kalibroidun slippagen pohjalta, älä laukaisuhintaan.

Osakkeissa on sama ongelma eri asussa. Jos osakkeen stop-loss on 62.00 ja hinta putoaa yön aikana 58.40:een, toimeksianto ei täyty 62.00:ssa vaan jossain avausnoteerauksen alapuolella. Päiväkynttilöitä käyttävä backtest, joka kirjaa hintagapeista −$0.00 slippagea, kertoo mielellään, että stop-loss-kerros pienensi laskua. Ei pienentänyt. Sitä ei vain koskaan testattu tärkeinä päivinä. Myös kaupankäyntikatkot aiheuttavat saman ilmiön: stop-lossisi täyttyy avaus-huutokaupassa, hinnalla jota kynttilän alin arvo ei koskaan näytä.

Tässä ei ole mitään erikoista. On vain tunnustettava, että kynttilä on yhteenveto ja stop-lossia sekä tavoitehintaa käyttävä strategia on veto niiden tapahtumien järjestyksestä, jotka yhteenveto jättää pois. Kun paperikaupankäynnin moottori lopulta ajaa strategian live-markkinadatalla, data kertoo oman näkemyksensä järjestyksestä eikä ole koskaan välittänyt siitä, kumman if-haaran kirjoitit ensin.

kynttilänsisäiset täytötstop-toimeksiannotbacktestingkryptofutuuritmarkkinamikrorakenne
← Kaikki kirjoitukset