Záróprojekt: egy ellenőrizhető stratégia
Összeállítod a saját beállítható stratégiádat, és végigvizsgálod a jelzéseit, kötéseit és eredményeit.
A záróprojektben egy fájlba kerülnek a könyvben tanult részek: mozgóátlagok, inputok, feltételek, saját függvény, megbízások és megjelenítés. A cél egy olyan program, amelynek minden döntését vissza tudod vezetni az adatokra és a leírt szabályokra.
Írd le a programot kód nélkül
A stratégia két EMA keresztezését figyeli. Egy harmadik, hosszabb SMA-val azt is megvizsgálja, hogy a záróár az átlag fölött van-e.
A long belépés feltétele, hogy a gyors EMA alulról a lassú EMA fölé kerüljön, és a záróár a trendszűrő SMA fölött legyen. A három hossz sorrendje legyen gyors < lassú < trend. Ha a megadott hosszak ezt nem teljesítik, a program nem ad belépési megbízást.
A long pozíció lefelé EMA-keresztezésnél piaci lezárást kap. A belépéshez tickben megadott stop és célár is tartozik. A szimuláció fix egyegységes mennyiséget, 0,1 százalékos jutalékot és két tick slippage-et használ.
Ezek a feladat szabályai. Nem következtetünk belőlük arra, hogy a program valamelyik piacon nyereséges lesz. Az ellenőrzéshez a könyv rögzített demóadatát használjuk.
A teljes program
Hozd létre a final_strategy.py fájlt:
"""
@pyne edge
"""
from pynecore.lib import close, color, input, location, plot, plotshape, script, shape, strategy, ta
def lengths_are_ordered(fast: int, slow: int, trend: int) -> bool:
return fast < slow and slow < trend
@script.strategy(
"Filtered Crossing Strategy",
overlay=True,
initial_capital=10000,
default_qty_type=strategy.fixed,
default_qty_value=1,
pyramiding=1,
commission_type=strategy.commission.percent,
commission_value=0.1,
slippage=2,
)
def main(
fast_length: int = input.int(9, title="Fast EMA length", minval=1, maxval=200),
slow_length: int = input.int(21, title="Slow EMA length", minval=1, maxval=200),
trend_length: int = input.int(50, title="Trend SMA length", minval=1, maxval=200),
use_trend_filter: bool = input.bool(True, title="Use trend filter"),
stop_ticks: int = input.int(100, title="Stop distance (ticks)", minval=1),
target_ticks: int = input.int(200, title="Target distance (ticks)", minval=1),
):
fast_average = ta.ema(close, fast_length)
slow_average = ta.ema(close, slow_length)
trend_average = ta.sma(close, trend_length)
crosses_up = ta.crossover(fast_average, slow_average)
crosses_down = ta.crossunder(fast_average, slow_average)
valid_lengths = lengths_are_ordered(fast_length, slow_length, trend_length)
trend_passes = not use_trend_filter or close > trend_average
entry_signal = valid_lengths and crosses_up and trend_passes
if entry_signal:
strategy.entry("Long", strategy.long)
if crosses_down:
strategy.close("Long")
strategy.exit("Bracket", "Long", loss=stop_ticks, profit=target_ticks)
plot(fast_average, "Fast EMA", color=color.blue, linewidth=2)
plot(slow_average, "Slow EMA", color=color.orange, linewidth=2)
plot(trend_average, "Trend SMA", color=color.gray, linewidth=2)
plotshape(entry_signal, "Entry signal", style=shape.triangleup,
location=location.belowbar, color=color.green)Mentsd el, és futtasd a demóadaton. A grafikonon három átlag és a belépési feltételt jelölő zöld háromszögek jelennek meg. A tényleges belépéseket és kilépéseket a stratégia kötésjelölései mutatják.

Mi számít minden gyertyán?
A három átlag és a két keresztezés a feltételek előtt fut le. Akkor is számoljuk őket, ha a szűrő miatt végül nem lesz belépés. Így a számítási állapotuk a teljes gyertyasoron halad végig.
A lengths_are_ordered saját függvény három számot vizsgál, és egy logikai értéket ad vissza. Nincs saját gyertyaállapota. A valid_lengths megőrzi a vizsgálat mostani eredményét a további kifejezések számára.
A trend_passes igaz, ha a szűrő ki van kapcsolva, vagy ha a záróár az SMA fölött van. Az input.bool egy kapcsolható logikai bemenetet ad. A not use_trend_filter kikapcsolt szűrőnél igaz, így a második feltételre ilyenkor nincs szükség.
A szűrő kikapcsolásakor az átlagot továbbra is kiszámítjuk és kirajzoljuk. A kapcsoló a belépés vizsgálatát módosítja, nem a vonal megjelenítését.
Érvénytelen hosszkapcsolat
A külön inputhatárok csak azt mondják meg, hogy minden hossz 1 és 200 között legyen. Attól még megadhatsz 30-as gyors és 10-es lassú hosszt. Ez a feladatban kikötött sorrendet megsérti.
Az ellenőrző függvény emiatt külön vizsgálja a kapcsolatot. A hibás sorrend mellett a vonalak továbbra is kirajzolódnak, de az entry_signal nem lehet igaz. A program így nem indul el a feladattól eltérő hosszkapcsolattal belépéseket adni.
A hibakeresésben ezt a valid_lengths változóval közvetlenül ellenőrizheted. A feltétel az egész futás alatt hamis marad, ha a mentett inputok nem megfelelőek.
Egy jelzésből nem feltétlenül lesz új kötés
A zöld háromszög a belépési feltételt jelöli. A stratégia a megbízást a szimulátorhoz adja. A teljesüléshez további feltételek is tartozhatnak: például legyen következő gyertya, megfelelő tőke és megengedett mennyiség.
A pyramiding=1 miatt már nyitott long pozíciónál a további long belépést nem feltétlenül engedi a szimulátor. A jelzés és a kötés számát ezért ne tekintsd automatikusan azonosnak.
Az adatsor elején a trendszűrő ötvenes SMA-ja még hiányzik. Bekapcsolt szűrőnél az ár fölötte levését ilyenkor nem tudjuk igaznak tekinteni, ezért a belépés sem teljesíti ezt a feltételt.
Végezd el a működési ellenőrzést
Először az alapértékekkel dolgozz, és a Properties felületen ellenőrizd a mennyiséget, költségeket és teljesülési módot. Egy korábban mentett felülírás a forrásban levő beállítást módosíthatja.
Keress egy zöld jelzést. A debuggerben vagy a grafikon értékeivel vizsgáld meg az adott és az előző gyertya két EMA-ját. Ellenőrizd a gyors és lassú átlag keresztezését, az SMA-szűrőt és a hosszkapcsolatot. Mindhárom résznek igaznak kell lennie.
Ezután a Trades táblázatban keresd meg a hozzá kapcsolható belépést. Nézd meg, melyik gyertyán és milyen áron teljesült. A kilépésnél ellenőrizd, hogy keresztezés, stop vagy célár magyarázza-e a lezárást.
Próbálj ki megjósolható eseteket
A működési ellenőrzéshez olyan módosítást használj, amelynek eredményét előre meg tudod mondani:
| Változtatás | Mit ellenőrizz? |
|---|---|
| Gyors és lassú hossz azonos | A hosszellenőrzés miatt nincs új belépési jelzés |
| Trendszűrő kikapcsolva | Az EMA-keresztezéshez nem szükséges SMA fölötti ár |
| Stop- és céltávolság nő | Ugyanaz a szinteltérés más kilépési gyertyát adhat |
| Mennyiség változik | Az árjelzés ugyanaz, a kötés pénzbeli mérete eltérhet |
Egy futásban csak egy ilyen változtatást végezz. Minden próbánál írd le előbb a várakozásodat, utána a tényleges eredményt. Ha nem egyeznek, a debuggerben keresd meg az első eltérő döntést.
Az eredmény összehasonlítása
A szűrő be- és kikapcsolásának összehasonlításakor ugyanazt az adatot, mennyiséget, költséget és hosszakat tartsd meg. A Performance tőkegörbéjét a Trades táblázattal együtt nézd. A kevés kötés vagy egy nyitott utolsó pozíció az összefoglalót is befolyásolja.
Ha valódi történelmi adaton vizsgálod a programot, a beállításhoz használt időszakot és a külön ellenőrzési időszakot rögzítsd még az eredmények megtekintése előtt. Az ellenőrzési időszak megtekintése után végzett paramétermódosítással az az időszak is a beállítás részévé válik.
A bemeneti adat elejére elegendő bemelegedési gyertya kell. Ha egy kivágott időszakot külön futtatsz, a mozgóátlagokat és a pozícióállapotot újra felépíted. Emiatt a külön futás első szakasza eltérhet ugyanannak az időszaknak egy hosszabb adatsor közepén kapott eredményétől.
Próbáld ki önállóan
Egészítsd ki a programot egy Use crossings exit kapcsolóval. Bekapcsolva maradjon meg a lefelé keresztezéses lezárás, kikapcsolva csak a stop és a célár zárjon. A lefelé keresztezést mindkét esetben számítsd ki.
A feladat megoldása
A main() paraméterlistájába:
use_crossing_exit: bool = input.bool(True, title="Use crossings exit"),A lezárási ág:
if use_crossing_exit and crosses_down:
strategy.close("Long")A crosses_down = ta.crossunder(...) sor maradjon a feltételek előtt. A strategy.exit hívás mindkét kapcsolóállásnál megmarad.
Kikapcsolt keresztezéses lezárásnál a pozíció egy lefelé EMA-keresztezés után is nyitva maradhat. A következő belépési jelzés ettől még megjelenhet, miközben a meglévő pozíció miatt nem nyílik új kötés.
Készíts saját változatot
Másold a programot új néven, és írj le egyetlen új szabályt, amelyet hozzá akarsz adni. Fogalmazd meg, milyen adatból és melyik gyertyán dönt, hogyan lehet kézzel ellenőrizni, és mely input módosítja.
Az új szabályt először külön változóként számítsd ki. Rajzold vagy figyeld meg a debuggerben, mielőtt belépés vagy kilépés feltételévé teszed. Így egy hibát a számításnál kereshetsz, mielőtt a teljes stratégia eredményét próbálnád magyarázni.
A forrás, a mentett beállítások és a használt adatok együtt írják le a kísérletedet. Ha ezeket megőrzöd, a futás újra előállítható és ellenőrizhető lesz.