Saját függvények
Névvel ellátott számításokra bontod a kódot, és több helyen felhasználod őket.
A gyertya méretének számítását már ismered: high - low. Ha több számításban is szükséged van rá, saját függvénybe teheted. A hívásból kiderülhet, mi a számítás célja, és a képletet egy helyen tarthatod.
Egy függvény bemenete és eredménye
def price_range(top: float, bottom: float) -> float:
return top - bottomA def függvényt definiál. A függvény neve price_range. Két bemenetet vár, top és bottom néven. Mindkettő szám, amely tört értéket is tartalmazhat.
A -> float az eredmény típusát jelöli. A return kiszámítja és visszaadja az eredményt, majd befejezi az adott függvényhívást.
A price_range(105, 100) eredménye 5. A függvény nem tudja, hogy ezek árak-e, és nem választ gyertyát. A hívó adja meg a két értéket.
A függvény törzse itt négy szóközzel beljebb kezdődik. Ebben a példában a definíció a main() mellett, a fájl legkülső szintjén áll. Így a számításhoz szükséges két árat paraméterként adjuk át neki. Függvényt a main() belsejében is létrehozhatsz; lentebb ezt is kipróbáljuk.
A név hatóköre
A top és a bottom csak a price_range függvényen belül használható paraméter. A main() nem hivatkozhat közvetlenül rájuk. Ott a visszaadott eredményt használod.
Egy név hatóköre azt jelenti, hogy a kód mely részében érhető el. Két külön függvény használhat ugyanilyen paraméternevet anélkül, hogy a paramétereik egyetlen közös változóvá válnának.
A fájl legkülső szintjén definiált price_range nem éri el automatikusan a main() helyi változóit. A fájl elején importált neveket, például a close nevet viszont használhatja. A láthatóságot tehát az is befolyásolja, hol definiálod a függvényt.
A függvény definíciója és a hívása sem ugyanaz. A definíció megadja a szabályt, a hívás konkrét értékekkel végrehajtja azt.
A teljes program
Hozd létre a price_functions.py fájlt. Ebben ugyanaz a függvény számítja a gyertya teljes tartományát és az előjeles nyitóár és záróár közötti változást:
"""
@pyne edge
"""
from pynecore.lib import close, color, high, low, open, plot, script
def price_range(top: float, bottom: float) -> float:
return top - bottom
@script.indicator("Price Functions", overlay=False)
def main():
full_range = price_range(high, low)
body_change = price_range(close, open)
plot(full_range, "Full range", color=color.blue)
plot(body_change, "Body change", color=color.orange)Futtasd a demóadaton. A teljes tartomány nem negatív, mert a gyertya maximuma legalább akkora, mint a minimuma. A nyitóár és záróár közötti változás negatív is lehet. A függvény semmit nem módosít az átadott árakon; a két szám különbségét adja vissza.

Ebben a példában a függvény rövid, és kézzel is könnyen ellenőrizhető. Nagyobb programban összetettebb részfeladatokat is elnevezhetsz, de egyetlen összeadást nem kötelező külön függvénybe tenni.
A paraméterek sorrendje
A price_range(high, low) hívás a high értékét adja a top, a low értékét a bottom paraméternek. Ha felcseréled őket, a kivonás előjele is megfordul.
A paraméter nevét is megadhatod:
full_range = price_range(top=high, bottom=low)Ez hosszabb, de egy összetettebb hívásnál megkönnyítheti az olvasást. A megadott névnek pontosan egyeznie kell a függvény paraméterének nevével.
Függvény a main() belsejében
Egy belül definiált függvény elérheti a körülötte lévő függvény változóit is. Ez például akkor hasznos, ha több számítás ugyanazt az inputként megadott beállítást használja.
Simítsuk ki az előző program két vonalát mozgóátlaggal. Az átlag hosszát egyetlen inputban adjuk meg, és mindkét számításhoz ezt használjuk. A belső függvénynek csak a két árat adjuk át; a hosszt a main() paraméterei között találja meg.
A price_functions.py fájlban tartsd meg a külső price_range függvényt és az indikátor dekorátorát. A pynecore.lib importjához add hozzá az input és a ta nevet, majd a main() definícióját cseréld erre:
def main(
length: int = input.int(5, title="Average length", minval=1, maxval=200),
):
def average_difference(top: float, bottom: float) -> float:
return ta.sma(price_range(top, bottom), length)
average_range = average_difference(high, low)
average_body_change = average_difference(close, open)
plot(average_range, "Average range", color=color.blue)
plot(average_body_change, "Average body change", color=color.orange)A length a korábban megismert egész számú input. A belső average_difference két paramétert kap: a top és a bottom értékét a hívás adja meg. A length értékét a körülötte lévő main() függvényből olvassa ki, ezért a hívásokban ezt nem kell újra megadnod.
A belső függvény definíciója négy szóközzel kezdődik, mert a main() része. A saját törzse, a return sor már nyolc szóközzel kezdődik. Az average_difference nevet a main() belsejében használhatod; a fájl legkülső szintjén nem válik elérhetővé.
A price_range kiszámítja a két ár különbségét, a ta.sma pedig ennek mozgóátlagát adja vissza. A kék vonal így a gyertyák teljes tartományának átlagát, a narancssárga a nyitóár és záróár közötti előjeles változás átlagát mutatja. Mindkét hívás minden gyertyán lefut, ezért mindkét átlag folyamatosan számol.
Futtasd a módosított programot, majd a fogaskerékkel nyisd meg az Inputs felületet. Állítsd az Average length értékét 5-ről 20-ra, és kattints a Save gombra. A megnyitott grafikon automatikusan újraszámolódik, és mindkét vonal húszgyertyás átlagra vált. A belső függvény két hívását nem kellett módosítanod. Ha 1-re állítod a hosszt, visszakapod az eredeti program két vonalát.
Ezt a külső változókhoz való hozzáférést lezárásnak, angolul closure-nek nevezik. Az érték kiolvasása nem jelenti azt, hogy egy belső értékadással automatikusan felül is írhatod a külső változót. Ennél a példánál csak olvassuk a length értékét.
Ha Pine Scriptből fordított kódot olvasol: a PyneComp a függvényeket a main() belsejében hozza létre. A Pine Script főszinten létrehozott változói is a main() belsejébe kerülnek, így a belső függvények elérhetik őket. Ezért látsz a fordított kódban ilyen elrendezést. Saját Pyne code írásakor mindkét megoldást használhatod: a különálló, paramétereket fogadó függvényt és a körülötte lévő változókat is elérő belső függvényt.
A paraméteres változatnál a hívásból látszik minden átadott érték, és ugyanazt a függvényt más árpárral is könnyen használhatod. A belső függvény akkor lehet kényelmes, ha több számítás ugyanazokra a main()-ben létrehozott változókra épül.
A saját függvénynek is lehet állapota
A price_range csak a kapott értékekből számol. Nincs gyertyák között megőrzött változója, és nem használ előzményt. Ezért bármikor meghívhatod két értékkel.
A fenti average_difference viszont már állapotot használ, mert a benne hívott ta.sma a korábbi értékekből számol. Saját függvényben közvetlenül is létrehozhatsz Persistent vagy Series változót.
Eseményszámláló függvény
Számoljuk meg külön az emelkedő és a csökkenő gyertyákat. Ehhez olyan függvényt írunk, amely egy logikai értéket kap, és megjegyzi, hányszor kapott eddig igaz értéket.
A fájl elején importáld a Persistent nevet:
from pynecore import PersistentAz alábbi függvényt írd a main() elé, a fájl legkülső szintjére:
def count_events(event: bool) -> int:
count: Persistent[int] = 0
if event:
count += 1
return countA count kezdeti értéke nulla. Igaz event esetén eggyel nő, hamis esetén megőrzi az értékét. A return mindkét esetben visszaadja az addigi összesítést. A függvényhívás befejezése után a Persistent változó értéke megmarad a következő hívásra.
Tartsd meg az overlay=False beállítást. A main() korábbi definícióját és törzsét cseréld erre:
def main():
bullish_count = count_events(close > open)
bearish_count = count_events(close < open)
plot(bullish_count, "Bullish count", color=color.green)
plot(bearish_count, "Bearish count", color=color.red)Ugyanazt a függvényt két külön kódbeli helyről hívjuk. A két hívási helyhez külön count állapot tartozik: az első az emelkedő, a második a csökkenő gyertyákat számolja. Az első hívás nem növeli meg a második hívás számlálóját.
Ha például az első négy gyertya az alábbi sorrendben követi egymást, ezeket az értékeket kapod:
| Gyertya | Nyitóár és záróár viszonya | bullish_count | bearish_count |
|---|---|---|---|
| Első | A záróár magasabb | 1 | 0 |
| Második | A záróár alacsonyabb | 1 | 1 |
| Harmadik | A két ár azonos | 1 | 1 |
| Negyedik | A záróár magasabb | 2 | 1 |
Futtasd a demóadaton. A zöld vonal csak emelkedő gyertyán, a piros csak csökkenő gyertyán lép egyet. Egy új futtatás mindkét számlálót nulláról építi fel.
Mindkét függvényhívás minden gyertyán lefut; a növelés feltétele a függvény belsejében van. Állapotot használó függvénynél a hívások sorrendje és gyakorisága is a működés része. Ha csak néhány gyertyán hívsz meg egy függvényt, a benne vezetett előzmény is csak ezeknél a hívásoknál lép tovább.
Ha egyetlen közös számlálóra van szükséged, hívd meg egyszer a függvényt, és az eredményt tároló változót használd több helyen. Egy második hívási hely újabb, külön számlálót jelent.
Több utasítás egy függvényben
Ha az eredményhez részeredmény is kell, a return előtt kiszámíthatod:
def midpoint(top: float, bottom: float) -> float:
total = top + bottom
return total / 2A total helyi változó. A hívás végén nem válik a main() változójává. A függvényből csak az eredményét adtuk vissza.
Próbáld ki önállóan
Adj egy midpoint függvényt a programhoz, majd készíts overlay indikátort, amely a gyertyák középárát rajzolja ki. Használd a függvény top és bottom paraméterét a maximum és minimum fogadására.
A feladat megoldása
A fenti midpoint definíciót írd a main() elé. Az indikátor dekorátorában legyen overlay=True, a törzs pedig:
center = midpoint(high, low)
plot(center, "Midpoint", color=color.blue, linewidth=2)Az előző két vonal számítását és rajzolását törölheted ebből a változatból. A fel nem használt importokat is távolítsd el.
Magyarázd el a hívást
A price_range(close, open) sorhoz mondd el, melyik érték melyik paraméterbe kerül, mi történik a return sorban, és hol kapja meg a main() az eredményt. Ezt a három lépést egy hosszabb függvényhívásnál is végigkövetheted.