Dla zaawansowanych: jak działają wskaźniki?
Poznasz źródła SMA, EMA, RSI, MACD, ATR i wstęg Bollingera oraz napiszesz własną odmianę wskaźnika.
Łatwiej rozwijać wskaźnik, gdy rozumiesz, skąd bierze się jego wartość. Co wchodzi do obliczenia? Co zapamiętuje na następną świecę? Co zmieni inna średnia lub źródło cen? Kod źródłowy odpowiada także na te pytania.
Biblioteka ta PyneCore jest napisana w Pyne code. Jej zmienne Persistent, wywołania i warunki korzystają z poznanych mechanizmów. Całe źródło jest dostępne, więc gotowy wskaźnik możesz prześledzić jak własny program.
To rozdział zaawansowany o czytaniu źródeł i eksperymentowaniu. Nie trzeba rozumieć całej biblioteki naraz. Zacznij od krótkiej funkcji, potem śledź wywołania, na których się opiera.
Otwórz rzeczywistą implementację
- Otwórz wcześniejsze
moving_averages.pyw PyneIDE. - W
ta.ema(close, 10)przytrzymaj Command w macOS albo Ctrl w Windows lub Linux i kliknijema. Możesz też użyć Go to Definition z menu prawego przycisku. - Edytor otworzy zainstalowane
ta.pyprzy definicjiema. - Przeczytaj opis i ciało. Gdy wywołuje inną funkcję, możesz przejść do jej definicji.

Parametry i przejście do definicji poznałeś w Pomocy podczas pisania kodu. To samo działa dla RSI, MACD i pozostałych funkcji. Pełna referencja ta pomaga szukać funkcji i interpretować parametry.
Kod biblioteki a Edge: na początku ta.py znajdziesz @pyne lib. Biblioteka nie ogranicza się do Edge: korzysta z ogólnych narzędzi Pythona, wewnętrznych funkcji pomocniczych i dodatkowych typów. Wykonanie świeca po świecy i zarządzanie stanem będą jednak znajome. PyneFloat jest na przykład oznaczeniem typu liczbowego biblioteki, a na_float brakującą liczbą.
Poniższe fragmenty pokazują obliczenia biblioteki, nie pełne programy Edge. Własną wersję Edge napisz, wyrażając zrozumiany algorytm dozwolonymi narzędziami. Nie zmieniaj zainstalowanego ta.py; eksperymentuj we własnym pliku.
SMA: sumowanie za wzorem
Dwa wiersze obliczenia ta.sma:
length = int(length)
return lib_math.sum(source, length) / lengthŚrednia to suma okna podzielona przez liczbę elementów. Po zamianie długości na całkowitą sumowanie wykonuje lib_math.sum. Stanu nie znajdziesz w ciele sma; prowadzi go funkcja sumująca. Śledząc dalej, przejdziesz przez math.py do implementacji _math_stateful.py.
To ważny nawyk: krótka funkcja nadal może być stanowa. Działanie wywołań jest częścią obliczenia. Ręcznie napisana średnia sumowała to samo okno własną pętlą.
EMA i RMA: aktualizacja zachowanej średniej
Po rozgrzewce EMA wykonuje:
last_val = last_val + alpha * (source - last_val)
return last_vallast_val jest poprzednią średnią, source obecną wartością. Zmieniamy dawną średnią o część ich różnicy. alpha EMA wynosi 2 / (length + 1). Przy długości dziesięć dodajemy około 18,18 procent różnicy nowej ceny i starej średniej.
W źródle alpha i last_val są Persistent. Początkowo last_val brakuje, więc funkcja próbuje ustawić ją SMA tej samej długości:
if not (last_val == last_val):
last_val = sma(source, length)
return last_valDopóki danych nie wystarcza także do SMA, wynik jest brakujący. Po utworzeniu początkowej średniej aktualizujemy poprzednią wartość. not (last_val == last_val) sprawdza brak, ponieważ brakująca wartość nie równa się sobie. W swoich przykładach używałeś na(value).
RMA, wygładzanie Wildera, zaczyna podobnie, ale aktualizuje inaczej:
last_val = (last_val * (length - 1) + source) / length
return last_valPrzy długości dziesięć nowa wartość ma wagę jednej dziesiątej. EMA nadaje jej większą wagę przy tej samej długości, więc reagują inaczej na jeden szereg.
Pełny kod zawiera też obsługę brakującego wejścia i szczególny przypadek długości jeden. Nawet wersje z tym samym wzorem mogą się różnić przez inicjalizację, obsługę braków lub inny zestaw wykonanych świec. Znaczenie ma kolejność operacji zmiennoprzecinkowych; zachowaj ją przy dokładnym porównaniu.
RSI: dwie osobno wygładzane zmiany
RSI osobno traktuje wzrost i spadek źródła. Główne wiersze w PyneCore:
rma_u = rma(builtins.max(source - prev_src, 0.0), length)
rma_d = rma(builtins.max(prev_src - source, 0.0), length)
prev_src = sourceprev_src jest poprzednią poprawną wartością, zachowaną przez Persistent. Wzrost ze 100 do 103 daje ruch w górę 3 i w dół 0. Spadek ze 103 do 101 daje odpowiednio 0 i 2. Dwa RMA wygładzają serie oddzielnie; miejsca wywołania mają własny stan.
prev_src aktualizuje się po obu różnicach, jak w zadaniu z trwałą poprzednią wartością.
Stosunek wygładzonych zmian tworzy RSI:
if rma_d <= 1e-10:
return 100.0
if rma_u <= 1e-10:
return 0.0
return 100 - 100 / (1 + rma_u / rma_d)Brak ruchu w dół daje 100, brak ruchu w górę 0. Źródło uwzględnia też bardzo małe liczby i najpierw sprawdza stronę spadkową: gdy obie są pod progiem, wynik to 100. Z samego wzoru trudno poznać takie szczegóły.
Pierwsza prawidłowa cena nie daje jeszcze zmiany. RSI ją zapisuje i dopiero z następną zaczyna wygładzanie. Rozgrzewkę określa więc liczba zmian. RSI nie jest prawdopodobieństwem: 70 nie oznacza 70-procentowej szansy wzrostu.
MACD: nowy wskaźnik ze średnich
MACD liczy różnicę dwóch EMA i tworzy z niej kolejną EMA. Główne kroki bez sprawdzania braków:
fast = ema(source, fastlen)
slow = ema(source, slowlen)
macd_val = fast - slow
signal = ema(macd_val, siglen)Trzy zwracane wartości:
return macd_val, signal, macd_val - signalLinia MACD jest różnicą szybkiej i wolnej średniej. Sygnałowa jej wygładzeniem. Histogram jest różnicą linii, więc wynosi zero przy ich równości.
Jedno wywołanie daje trzy wyniki odbierane do trzech zmiennych:
macd_line, signal_line, histogram = ta.macd(close, 12, 26, 9)Kolejność ma znaczenie: MACD, sygnałowa, histogram. Dopóki obie średnie cen nie są gotowe, brakuje różnicy. Potem sygnałowa ma własną rozgrzewkę. Początkowe braki złożonego wskaźnika wynikają też z jego wnętrza.
ATR: luka cenowa też należy do zakresu
Implementacja ATR jest krótka:
return rma(tr(True), length)Znasz już RMA. Tutaj wygładza True Range, rzeczywisty zakres, czyli maksimum trzech odległości:
- różnicy obecnego maksimum i minimum;
- odległości maksimum od poprzedniego zamknięcia;
- odległości minimum od poprzedniego zamknięcia.
Przy poprzednim zamknięciu 100, obecnym minimum 108 i maksimum 110 własny zakres to tylko 2. True Range wynosi jednak max(2, 10, 8), czyli 10: uwzględnia lukę od poprzedniego zamknięcia.
Na pierwszej świecy bez poprzedniego zamknięcia tr(True) używa high - low. Źródło odczytuje poprzednią cenę z wewnętrznej danej wykonawcy. ATR pokazuje rozmiar ruchu w jednostce ceny, nie kierunek.
Wstęgi Bollingera: średnia i odchylenie
Środkowa linia ta.bb to SMA, a granice są od niej oddalone o wielokrotność odchylenia standardowego. Kod najpierw liczy odchylenie i średnią:
std_dev = stdev(series, length)
middle = sma(series, length)Zwracanie dla prawidłowego środka:
std_dev *= mult
return middle, middle + std_dev, middle - std_devOdchylenie mówi, jak wartości okna rozpraszają się wokół średniej. Przy środku 100, odchyleniu 3 i mnożniku 2 górna granica to 106, dolna 94. Trzy wyniki mają tu inną kolejność niż MACD: środek, góra, dół.
Własna wersja: najpierw odtwórz oryginał
Utwórz bands_workshop.py. Funkcja składa wstęgi z prostszych elementów biblioteki. Obok liczymy górną granicę gotowego ta.bb jako punkt odniesienia.
"""
@pyne edge
"""
from pynecore.lib import close, color, input, plot, script, ta
def custom_bands(source: float, length: int, multiplier: float) -> tuple[float, float, float]:
middle = ta.sma(source, length)
deviation = ta.stdev(source, length)
upper = middle + multiplier * deviation
lower = middle - multiplier * deviation
return middle, upper, lower
@script.indicator("Bands Workshop", overlay=True)
def main(
length: int = input.int(20, title="Length", minval=2, maxval=200),
multiplier: float = input.float(2.0, title="Deviation multiplier", minval=0.1, maxval=5.0),
):
builtin_middle, builtin_upper, builtin_lower = ta.bb(close, length, multiplier)
own_middle, own_upper, own_lower = custom_bands(close, length, multiplier)
plot(builtin_upper, "Built-in upper", color=color.blue, linewidth=3)
plot(own_upper, "Custom upper", color=color.orange)
plot(own_middle, "Custom middle", color=color.green)
plot(own_lower, "Custom lower", color=color.gray)tuple[float, float, float] oznacza wynik z trzech liczb. return middle, upper, lower zwraca trójkę, a trzy zmienne przed wywołaniem odbierają jej wartości. builtin_middle i builtin_lower nie rysujemy, ale możesz użyć ich w dalszej kontroli.
Uruchom na demonstracji. Własna i gotowa górna granica pokrywają się: cienka pomarańczowa linia biegnie po grubszej niebieskiej. Najedź na świecę i porównaj Built-in upper i Custom upper. Przy długości dwadzieścia pierwszych dziewiętnaście świec nie ma pełnego okna.

Dokładniejsze dane otworzysz przez Open plot output CSV na pasku wykresu. Sprawdź pierwszy poprawny punkt i późniejsze wartości. Linie identyczne na oko mogą mieć małe różnice.
Spróbuj samodzielnie: środek z EMA
Zmień tylko środek custom_bands na EMA zamiast SMA. Zachowaj odchylenie i gotowe ta.bb do porównania.
Przed uruchomieniem przewidź: czy własna górna granica nadal wszędzie się pokryje? Co nastąpi po nagłej zmianie ceny?
Rozwiązanie zadania
Pierwszy wiersz obliczenia własnej funkcji:
middle = ta.ema(source, length)Granice mierzymy od tej EMA, a ta.stdev się nie zmienia. Własny środek i granice zwykle przesuną się wobec oryginału. Różnica górnych wartości równa się różnicy EMA i SMA, bo dodajemy takie samo odchylenie i mnożnik.
To już twoja eksperymentalna wersja. Sama inna linia nie mówi, czy reguła handlowa działa lepiej; sprawdź to osobną strategią na jednakowych danych i ustawieniach.
Jak czytać bibliotekę dalej
Wybierz wskaźnik i opisz, co dostaje, co pamięta i co oddaje. Śledź wywołania, aż zrozumiesz całość. Dla RSI ścieżka rsi → rma → sma prowadzi od różnic przez wygładzanie do inicjalizacji.
Czytaj też gałęzie braków, rozgrzewki i przypadków granicznych. We własnej wersji zmień najpierw jeden szczegół i porównaj z oryginałem. Oddzielisz zamierzoną zmianę od błędu obliczenia.
Źródła pozostałych funkcji również otworzysz przez Command lub Ctrl z kliknięciem. Dłuższy wskaźnik może wymagać czasu, ale metoda pozostaje ta sama: wejścia, zachowane dane, obliczenie, wynik.