Pyne to system do tworzenia programów pracujących z danymi rynkowymi. Możesz za ich pomocą obliczać i wyświetlać wartości wynikające z cen albo określać reguły strategii tradingowej. W tej książce przejdziemy od napisania programu do sprawdzenia jego wyników.

Co nazywamy Pyne code?

Programy piszemy w Pyne code. To samodzielny język programowania przeznaczony do przetwarzania danych rynkowych. Kod opisuje, co system ma obliczyć i wyświetlić oraz od jakich warunków uzależnić operację.

Wskaźnik może na przykład obliczyć średnią cenę ostatnich dziesięciu świec i narysować ją jako linię na wykresie cenowym. Wykres cenowy pokazuje zmiany ceny w czasie. Strategia określa również reguły wejścia i wyjścia: na przykład otwiera pozycję kupna, gdy warunek zostanie spełniony. Uruchamiając ją na danych historycznych, możesz sprawdzić, jakie transakcje wynikałyby z tych reguł przy zadanych warunkach realizacji. Nazywamy to backtestem.

Najpierw tworzymy proste wskaźniki. Na nich poznasz dane i język, zanim zaczniesz pisać reguły transakcyjne.

Jaki ma związek z Pythonem?

Pyne code korzysta z zasad zapisu Pythona. Zasady te nazywamy składnią: określają na przykład położenie nawiasów i sposób oznaczania powiązanych wierszy. Nie musisz wcześniej uczyć się Pythona; potrzebne reguły poznasz w przykładach.

Dlatego pliki mają typowe dla Pythona rozszerzenie .py. Z zainstalowanym PyneCore można uruchamiać Pyne code również w środowisku Pythona. Python zapewnia środowisko wykonawcze, a PyneCore własny sposób działania Pyne i bibliotekę funkcji.

Jak program przetwarza dane?

W przykładach otrzymujemy dane rynkowe jako ciąg świec. Świeca podsumowuje dane pewnego okresu, między innymi cenę otwarcia i zamknięcia. W danych dziennych jedna świeca oznacza jeden dzień.

PyneCore wykonuje obliczenia programu kolejno na tych świecach. Może na przykład przeliczać średnią na każdej świecy z cen dostępnych do tej chwili. Zarządza przy tym wcześniejszymi wynikami i danymi, które mają przetrwać do następnej świecy.

Różni się to od działania zwykłego programu w Pythonie. Znacznik @pyne na początku pliku informuje PyneCore, że ma odpowiednio przygotować i wykonać kod. W rozdziale objaśniającym kod przyjrzymy się dokładnemu zapisowi znacznika i słowu edge używanemu w przykładach.

Czym różni się od przetwarzania wektorowego?

Wśród pythonowych frameworków tradingowych są zarówno rozwiązania przetwarzające kolejne świece, jak i wektorowe. Przy przetwarzaniu wektorowym wykonujesz operacje na całych szeregach liczb: na przykład jednocześnie obliczasz średnie i sygnały kupna dla wszystkich świec. Dane często przechowujesz wtedy w tabelach lub tablicach.

W PyneCore opisujesz działanie dla bieżącej świecy. System je wykonuje, po czym przechodzi do kolejnej. Historią obliczeń i zachowywanym stanem zarządza według własnych reguł języka Pyne.

Zapisujesz kroki w prostej funkcji

W kilku frameworkach działających świeca po świecy trzeba utworzyć klasę własnej strategii. Klasa łączy dane i operacje; zdefiniowane w niej funkcje nazywamy metodami. Ustawienia i reguły wpisujesz do metod wymaganych przez framework, a ceny i pozycję odczytujesz za pośrednictwem danych klasy.

W przykładach Pyne code zapisujesz w funkcji main(), co chcesz obliczyć i pod jakim warunkiem działać. Jej wiersze wykonują się kolejno na każdej przetwarzanej świecy: najpierw obliczasz wartość, potem sprawdzasz warunek, na końcu rysujesz sygnał lub składasz zlecenie. Przechodzeniem między świecami zajmuje się PyneCore.

Na początek nie musisz więc uczyć się tworzenia klas i dziedziczenia ani rozdzielać programu między metody frameworka. Do prostych przykładów wystarczą zmienne, wywołania funkcji i warunki. Poznasz je w następnych rozdziałach.

Śledzisz regułę w kolejności czasowej

To przypomina rozważanie decyzji transakcyjnej: „Sprawdzam obecną cenę i jej dotychczasowy ruch. Jeśli warunek jest spełniony, wchodzę. Dopóki mam pozycję, sprawdzam warunek wyjścia”. W kodzie możesz śledzić zdarzenia w tej samej kolejności, a debugger pozwala obejrzeć zmienne na konkretnej świecy.

Trudniej przypadkiem liczyć z przyszłych danych

Przy obliczeniach wektorowych dostępny może być cały szereg. Przesunięcie w złą stronę albo błędnie wybrana średnia może więc włączyć do obliczeń cenę nieznaną w chwili decyzji. Na przykład średnia z całego roku używałaby w styczniowych decyzjach także cen z późniejszych miesięcy. Program nadal może działać i pokazywać przekonujące wyniki, a błąd bywa trudny do zauważenia. Nazywa się to błędem wykorzystania przyszłych informacji, po angielsku look-ahead bias.

Szeregi czasowe Pyne udostępniają wartości bieżącej i już przetworzonych świec. Dostęp do historii nie pozwala odczytać ceny następnej świecy. Zmniejsza to ryzyko przypadkowego użycia przyszłych danych i ułatwia sprawdzenie, z czego wynikała decyzja.

Nadal trzeba uważać na przygotowanie danych. Jeśli zewnętrzne dane zawierają już informację poznaną później, samo przetwarzanie świec po kolei tego nie wykryje.

Szybkość może wymagać kompromisu

W niektórych programach wykonanie świeca po świecy może być wolniejsze niż dobrze napisane obliczenia wektorowe. Ma to znaczenie zwłaszcza przy testowaniu wielu strategii lub zestawów parametrów na dużych danych. Systemy wektorowe często przyspieszają takie obliczenia zoptymalizowanymi bibliotekami. Rzeczywista różnica zależy od programu i ilości danych.

W książce uczysz się działania świeca po świecy: reguł zapisanych chronologicznie i sprawdzania danych poprzedzających decyzję.

Inne rozwiązania: przetwarzanie wektorowe w VectorBT i strategie świeca po świecy w Backtrader (po angielsku).

Do czego służą PyneIDE i PyneCore?

PyneIDE to rozszerzenie edytora Visual Studio Code. Piszesz w nim program, wybierasz dane i uruchamiasz wykonanie. Tam też oglądasz wynik na wykresie i szukasz błędów.

PyneCore jest systemem wykonującym program. Ładuje go i przygotowuje, przetwarza nim świece, a następnie tworzy wyniki obliczeń i transakcji. PyneIDE używa go w tle i wyświetla rezultaty.

W następnym rozdziale skonfigurujesz PyneIDE i utworzysz pierwszy projekt. Korzystamy z przykładowych danych, żeby można było powtarzać uruchomienia i porównywać wyniki własnych zmian.