Múlt héten átküldted a jegyzetfüzetet: ugyanaz a jelzés, ugyanaz az univerzum, ugyanaz a 14 hónapnyi BTCUSDT perp adat. Csak a végrehajtás változott. Többé nem ütötted át a spreadet, hanem egy tickkel beljebb helyeztél ki vételi ajánlatokat, a Sharpe-mutató pedig 0.42-ről 2.14-re ugrott. Azt kérdezted, valódi-e az eredmény, vagy elrontottál valamit.
Elrontottál valamit. Végig akarom venni, pontosan hol, mert a hiba egyetlen sorban van, a mögötte húzódó tanulság viszont sokkal nagyobb ennél az egy sornál.
Íme a teljesülési szabályod, kimásolva a motorodból:
if bar.low <= limit_price: fill(limit_price)
Ez azt mondja: ha a piacon ebben a percben a limitáramon vagy az alatt kötés történt, akkor a limitáramon teljesült a megbízásom. Valójában csak azt kódolja, hogy az ár megérintette a szintedet. Az érintés nem jelent teljesülést. A kettő között ott a queue, te pedig üresnek modellezted.
Mi áll előtted
Amikor 84,120.0-s vételi ajánlatot teszel ki BTCUSDT perpen, a már ott pihenő megbízások mögé kerülsz a sorban. Ennél a kontraktusnál a könyv legjobb árszintjén rendszerint 4 és 30 BTC közötti mennyiség áll, a napszaktól függően; a mintád időszakában a medián körülbelül 12 BTC. A megbízásod 0.4 BTC-s. Ahhoz, hogy köss, az eladóknak elegendő összmennyiséggel kell eladniuk ezen az árszinten ahhoz, hogy mindenkit kiszolgáljanak, aki előtted érkezett, még mielőtt a szintet visszavonnák alólad, vagy a piac feljebb lépne.
A backtesztednek tehát nem azt kellene kérdeznie, hogy „elérte-e az ár a 84,120.0-t”, hanem azt, hogy „legalább 12.4 BTC-nyi piaci eladás teljesült-e 84,120.0-n, amíg ott állt a megbízásom”. Ez a két esemény nagyon különbözik. Az adataidban nagyjából háromszoros az eltérés.
Három teljesülési szabály, három különböző stratégia
Újrafuttattam a jelzésedet ugyanazokkal a belépésekkel és három végrehajtási modellel. Ugyanaz az alfa, ugyanazok a díjak, ugyanaz a funding. Csak a teljesülési logikát változtattam meg.
| Teljesülési szabály | Teljesülések | Átlagos 60 másodperces edge a teljesülés után | Sharpe |
|---|---|---|---|
Érintés: low <= limit | 4,180 | +2.6 bp | 2.14 |
Szigorú átlépés: low < limit - 1 tick | 1,712 | +0.4 bp | 0.61 |
| Queue-szimuláció árszinten mért forgalommal | 1,306 | +0.9 bp | 0.77 |
A középső sor az a durva javítás, amivel először mindenki próbálkozik: csak akkor számolunk teljesülést, ha a piacon az ár szigorúan átlépte a limitáradat, azon az elven, hogy ha túljutott rajta, akkor biztosan elfogyasztotta a megbízásodat. Ez nagyjából helyes irány, és eloszlatja a fantázia nagy részét. Ugyanakkor csúnyán torzít is, amire még kitérek.
Az alsó sor az, amit meg kellene építened. Nem kell hozzá L3-adatfolyam, és nem kell egyesével rekonstruálni a megbízásokat sem. A legtöbb szükséges adatod már megvan.
Queue-szimuláció, amit az aggTrades-adatokból is felépíthetsz
A kline-ok helyett töltsd le az összesített kötési adatfolyamot. Minden kötés tartalmazza az árat, a mennyiséget, az időbélyeget és a maker oldali jelzőt, amelyből kiderül, hogy a kezdeményező vevő vagy eladó volt. Ez elég egy használható szimulációhoz, amely a saját passzív megbízásodat modellezi:
- Amikor kiteszed a megbízást, rögzítsd az adott áron álló mennyiséget. Ha csak 100ms-os könyvadatod van, használd a legutóbbi pillanatképet; az ebből eredő hiba kicsi ahhoz képest, amit most javítasz.
- Állítsd be a
queue_ahead = resting_size. Légy pesszimista, és feltételezd, hogy te vagy az utolsó. Az vagy, hacsak nem te hoztad létre az árszintet. - Haladj végig a kötési adatfolyamon. Minden, a limitáradon vagy az alatt végrehajtott, eladói kezdeményezésű kötés a mennyiségével csökkenti a
queue_ahead-t. Amikor negatívvá válik, a limitáradon teljesül a megbízásod, az adott időbélyeggel. - Ha az ár egy tickkel eltávolodik, ne állítsd nullára a queue-t. Csökkentsd fokozatosan. Néhány előtted álló megbízást visszavonnak, amikor az árszint elavul, másokat nem. Az érintési szinttől teljes másodpercnyi távolságban másodpercenkénti 30-40%-os csökkenés jobban egyezett a rekonstrukcióimmal, mint bármelyik szélsőséges feltételezés.
- Ha a stratégiád visszavonja a megbízást és újat tesz ki, az újat az új árszinten álló queue végére sorold. Ezt a lépést hagyják ki sokan, és itt bújik meg a megmaradt önáltatás.
A 2. lépésnél vitatkozni akarsz majd velem. Igen, néha közel vagy a sor elejéhez, mert az árszint kialakulásának pillanatában tetted ki a megbízást. Rendben, mérd meg, ne feltételezd. Naplózd a kitételkor ott álló mennyiséget, és hagyd, hogy az adatok megmutassák, a megbízásaid mekkora hányada került valóban korán a sorba. A te stratégiádnál ez 11% volt, mert a jelzésed egy elmozdulás után szól, vagyis a szint, amelyhez csatlakozol, már létezik, és már tömeg áll rajta.
Azok a teljesülések jönnek össze, amelyeknek nem örülnél
Most jön a valóban fontos rész, és az ok, amiért a szigorú átlépés szabálya torzít.
Gondolj bele, mikor fogy el teljesen a vételi ajánlatod. Akkor, amikor az eladói nyomás elég nagy ahhoz, hogy az egész árszintet felvegye. Vagyis szükségszerűen éppen akkor, amikor a piac lefelé halad át a limitáradon. A legbiztosabban teljesülő megbízásaid azok, amelyekkel azonnal rossz irányba kerülsz.
Bontsd fel a teljesüléseidet aszerint, hogyan jöttek létre, és mérd meg a 60 másodperces mark-outot:
| Teljesülés típusa | Teljesülések aránya | Mark-out 60 másodpercnél |
|---|---|---|
| Az árszinten kötés történt, az ár visszapattant | 38% | +3.1 bp |
| Az árszinten kötés történt, az ár nem mozdult | 21% | +0.2 bp |
| Az ár legalább 2 tickkel áthaladt az árszinten | 41% | −2.4 bp |
A naiv backteszted mindhárom csoport teljesüléseit beszámította, és mindet ingyenesnek vette. A szigorú átlépés szabálya szinte kizárólag a harmadik csoportot adja, ezért omlott össze az edge-e még a queue-szimulációénál is jobban. Egyik sem helyes. A queue-szimuláció reális összetételt ad, és az egész játék ezen múlik: a passzív végrehajtással megkeresed a spreadet, cserébe viszont kedvezőtlen szelekció ér, és e kettő aránya adja a tényleges stratégiádat.
A régi részvénykereskedési desk megközelítése ma is megállja a helyét: a maker megbízással ingyenes opciót írsz ki a piacnak. Akkor élnek vele, amikor megéri élni vele. A backteszted beszedte a prémiumot, de megfeledkezett az opció kifizetési lábáról.
A kimaradó kötések a stratégiát változtatják meg, nem csupán a költséget
Ez az a rész, amin a leginkább szeretném, ha elgondolkodnál. Ha rosszul modellezed a taker végrehajtást, a megfelelő ügyleteket kapod meg rossz áron, és a díjak korrekciója a hiba nagy részét helyrehozza. Ha rosszul modellezed a maker végrehajtást, akkor teljesen más ügyletek jönnek létre. A 4,180 belépésedből nagyjából 2,900 meg sem történt. Néhány a legjobb jelzéseid közül maradt ki: olyan gyertyákon, amelyek hirtelen felszúrtak, majd visszafordultak, vagyis pontosan olyan helyzetekben, amikor a piac nélküled ment tovább.
A nem teljesült ágra tehát valódi logika kell. Mit csinál a stratégia, ha a belépés nem teljesül, mire a jelzés elavul? Taker megbízással üldözöd az árat, kifizetve a spreadet és a piaci hatást? Lejjebb teszel ki új ajánlatot, és elfogadsz egy másik belépési bázist? Kihagyod az ügyletet, és pozíció nélkül maradsz? Mindegyik választás érdemben más tőkegörbét eredményez, és egyik sem az, hogy „tegyük fel, hogy teljesült”. A futtatásainkban egy őszinte árkövetési szabály — ha 20 másodperc után sincs teljesülés, átlépés, legfeljebb 3 bp csúszással — visszahozta a kimaradt ügyletek nagyjából harmadát, valamint a naiv és a queue-szimulációs Sharpe-mutató közötti különbség körülbelül felét. Ez igazán érdekes eredmény, és csak akkor bukkan elő, ha a teljesülési modell elég valósághű ahhoz, hogy a kérdésnek legyen értelme.
Gyors realitásellenőrzés, 10 perc: fogd a valós idejű papírkereskedési naplódat és a backtesztedet ugyanarra az időszakra. A teljesülési arányt hasonlítsd össze, ne a PnL-t. Ha a backteszt a pihenő megbízások 100%-át teljesítettnek veszi, a papírkereskedésben pedig 34% teljesül, akkor ez nem stratégiák összehasonlítása, hanem teljesülési modellhiba. Javítsd ki, mielőtt egyetlen hozamszámra is ránézel.
Még két kisebb dolog, ha már itt tartunk
Post-only elutasítások. Ha a maker díjszint biztosítására post-only megbízást használsz, és a könyv elmozdul a döntésed és a tőzsde visszaigazolása között, a megbízás elutasítva érkezik vissza, nem kerül be a könyvbe. A papírkereskedési naplóinkban ez normál órákban a BTCUSDT-nél a próbálkozások 3-6%-át teszi ki, egy amerikai CPI-adat közzététele utáni percben pedig meghaladja a 15%-ot. Az elutasított megbízás nem teljesült megbízás, de nem is bent álló, nem teljesült ajánlat: olyan ügylet, amely soha nem létezett. Ha a backteszted nem kezeli ezt az állapotot, éppen azokban a piaci helyzetekben lesz túl magas az ügyletek száma, amelyek a leginkább érdekelnek.
Saját ügyleteid megelőzése és a saját piaci lábnyomod. 0.4 BTC-vel nem mozdítod meg a BTCUSDT-t, úgyhogy ezt hagyd ki. Viszont említetted, hogy egy közepes kapitalizációjú altcoin perp piacon is kipróbálnád, ahol a könyv legjobb árszintjén gyakran 15k dollár alatti névértékű mennyiség áll. Ott a megbízásod már számottevő részét teszi ki a queue-nak, és az előtted álló mennyiségről készített pillanatképed tartalmazza a legutóbbi megbízásod jelenlétének hatását. Ha a méreted meghaladja az árszinten álló mennyiség nagyjából 10%-át, a szimulációnak figyelembe kell vennie, hogy a többi résztvevő reagál rád; őszintén szólva ettől a ponttól jobban bíznék a papírkereskedésben, mint bármilyen szimulációban, amit te vagy én írhatunk.
Futtasd újra a queue-szimulációval, és küldd el a teljesüléstípusonként bontott mark-out táblázatot. Ha a visszapattanó csoportban marad az edge nagy része, és az áthaladó csoport nem emészti fel az egészet, talán van valami, amit érdemes papíron kipróbálni. Ha az egész a 2,900 olyan teljesülésen múlt, amelyet soha nem kaptál volna meg, jobb most megtudni, mint négy hét múlva, amikor azt nézed, hogy a papírszámla nem azt csinálja, amit a jegyzetfüzet ígért.
← Összes bejegyzés

