Kripto Algoritmanı Jesse ile Test Et (Backtesting)

Yeni bir kripto algoritma geliştirdin. Çok kazançlı olacağını düşünüp, bir an önce canlı ortamda al-sat yapmak istiyorsun. Peki canlı ortamda denemeden önce geliştirdiğin algoritmanın geçmiş verilerle nasıl sonuç vereceğini, kazançlı olup olmadığını öğrenmek istemez misin? Backtesting sayesinde, yani geçmiş verilerle kripto algoritmanı çalıştırıp verimini, karlılığını görebilirsin.

Böylece bir sürü zaman ve para kaybından kurtulursun.

Yeni bir Kripto Bot çatısı olan Jesse ile kripto algoritmanı kolaylıkla test edebilirsin. Piyasada zipline ve backtrader gibi benzer işi yapan farklı kütüphaneler var. Fakat adı geçen kütüphanelerin yapısının karmaşıklığından dolayı öğrenmesi daha zordur.

Jesse ise basitliği, anlaşılırlığı ve kolay kullanımı sayesinde benim gözümde diğerlerinden birkaç adım ilerisinde durmaktadır.

Jesse Çatısının diğer bir harika özelliği ise binance ve bitfinex gibi yaygın kullanılan borsalarla entegre olması. Dolayısıyla verileri çekmek için ekstra bir efor harcamak gerekmiyor.

Jesse sadece bir backtesting çatısı değil, aynı zamanda ileri de canlı da trade yapabilmeye olanak sağlayacak bir araç. Canlı trade kısmı henüz geliştirilme aşamasında. Bittiği zaman, testlerinizi çalıştırdığınız gibi aynı stratejiyi canlı trade için de kullanabileceksiniz.

Jesse Çatısının Kurulumu

Kuruluma geçmeden önce sisteminizde öncelikle bulunması gereken yazılım ve servisleri görelim:

  • Python >= 3.6
  • pip >= 19.3.0
  • PostgreSQL >= 10
  • ta-lib >= 0.4

Jesse bir python kütüphanesi olduğu için, dolayısıyla sistemde Python kurulu olması gerekiyor. Pip, paket kurulumu için gerekiyor.

Geçmiş verileri saklamak için de bir PostgreSQL veritabanı servisine ihtiyacımız var. Ta-lib kütüphanesini önceki kripto bot ile ilgili yazılarımda anlatmıştım. Jesse, indikatörleri hesaplamak için bu kütüphaneyi kullanıyor.

Dolayısıyla ta-lib kütüphanesini sistemimize kurmamız gerekiyor.

TA-lib Windows kurulumu

Windows 10 makinasında kurulumu en kolay bir şekilde, binary dosyasını aşağıdaki siteden python sürümünüzle uyumlu olanı indirerek yapabilirsin.

https://www.lfd.uci.edu/~gohlke/pythonlibs/

Yukarıdaki siteden kendi python (3.6) sürümümle uyumlu olan TA_Lib‑0.4.18‑cp36‑cp36m‑win_amd64.whl dosyasını indirdim.

Siz bu dosya yerine hangi python sürümünü kullanıyorsanız onunla uyumlu sürümü indirin.

Kurulum için pip ya da pip3, hangisi sizin için geçerliyse onu kullanın.

Dosyayı indirdikten sonra, pycharm terminal ekranından pip3 install diyerek kurulumu gerçekleştiriyorum:

pip3 install TA_Lib-0.4.17-cp36-cp36m-win_amd64.whl

TA-lib Linux Kurulumu

Linux üzerinde TA-lib çalıştırabilmeniz için öncelikle Ta-lib c kütüphanesini kurmanız gerekiyor.

Ta-lib c kütüphanesini indirin:

wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar -xzf ta-lib-0.4.0-src.tar.gz
cd ta-lib/
./configure --prefix=/usr
make
sudo make install

Bu işlemi tamamladıktan sonra ta-lib python paketini yükleyelim:

pip3 install ta-lib

Jesse ile bağlantılı paketleri yükleyin

pip3 install -r https://raw.githubusercontent.com/jesse-ai/jesse/master/requirements.txt

Nihayet sıra geldi Jesse’nin kendisini kurmaya 🙂

pip3 install jesse

Genel olarak kurulum biraz zahmetli olsa da bir kere yaptıktan sonra geri dönüp bakma ihtiyacınız olmayacaktır.

Yeni Jesse Projesi Oluşturalım

Kendi stratejinizi oluşturmak için yeni bir Jesse projesi oluşturun:

jesse make-project projenin_ismi

Bu komut ile projenizin temel iskeleti oluşmuş olacaktır.

Projenin Konfigürasyonu

PostgreSQL Konfigürasyonu

Projenin kök dizininde bulunan config.py dosyasını açarak, postgresql bağlantı bilgilerini giriniz:

Config.py (örnek bağlantı), kendi postgresql bilgilerinizle değiştirin:
    ---
    'databases': {
        'postgres_host': '127.0.0.1',
        'postgres_name': 'jesse_db',
        'postgres_port': 5432,
        'postgres_username': 'jesse_user',
        'postgres_password': 'mypassword',
    },
    ---

Zaman Çerçevesi (time interval), Borsa (exchange) ve Kripto Para (Pair) Ayarı

Stratejimizin hangi zaman aralığı, borsa ve kripto para ikilisi üzerinde çalışacağını belirtmek için, routes.py dosyasında rota tanımlamak gerekiyor.

routes.py:
---
# trading routes
routes = [
    ('Binance', 'BTCUSDT', '4h', 'ExampleStrategy'),
]

---

Örneğimizde stratejimizi Binance borsası üzerinde BTCUSDT verilerini 4 saatlik (4h) zaman aralığı için çalıştırmış olacağız. ExampleStrategy olarak belirtilen kısmı daha sonra kendi stratejimizin ismi ile değiştireceğiz.

Proje ile hazır gelen örnek strateji şablonuna bakalım:

from jesse.strategies import Strategy

class ExampleStrategy(Strategy):
    def should_long(self) -> bool:
        return False

    def should_short(self) -> bool:
        return False

    def should_cancel(self) -> bool:
        return False

    def go_long(self):
        pass

    def go_short(self):
        pass

should_long methodunda hangi durumda long emri vereceğinizi, should_short metodunda hangi durumda shortlayacağınızı belirtiyorsunuz.

go_long methodunda long’a girerken, değerleri belirtiyorsunuz. Alış fiyatı, miktarı, stop loss değeri vs…

Kendi Stratejimizi Oluşturalım

Yukarıda bahsettiğim metodların ne işe yaradığını görmek için kendi stratejimizi oluşturalım.

Jesse’nin make-strategy komutuyla yeni bir strateji dosyası oluşturalım, ismi de MacdCrossStrategy olsun.

Jesse make-strategy MacdCrossStrategy

MacdCrossStrategy sınıfında örnek olması açısından basit bir algoritma seçiyoruz. Macd indikatörünü baz alarak, hızlı çizginin yavaş olanı yukarı yönlü kesmesi durumunda al sinyali üretiyoruz, tersi durumda, hızlı çizginin yavaş olanı aşağı yönlü kesmesi durumunda sat sinyali üretiyoruz.

from jesse.strategies import Strategy
from jesse import utils
import jesse.indicators as ta

class MacdCrossStrategy(Strategy):
    @property
    def current_macd(self):
        return ta.macd(self.candles)

    @property
    def previous_macd(self):
        return ta.macd(self.candles[:-1])        

    def should_long(self) -> bool:
        current_macd = self.current_macd.macd
        current_signal = self.current_macd.signal

        previous_macd = self.previous_macd.macd
        previous_signal = self.previous_macd.signal
        
        # # Yukari yonlu cakisma var mı kontrol ediyorum?
        # if current_macd > current_signal and previous_macd < previous_signal:
        #     return True

        # Yukari yonlu cakisma var mı kontrol ediyorum?
        if current_macd > current_signal and previous_macd < previous_signal:
            return True

        return False

    def should_short(self) -> bool:
        return False

    def should_cancel(self) -> bool:
        return True

    def go_long(self):
        qty = 1
                  stop = entry - 2*self.atr

        entry = self.price
        self.buy = qty, entry
    self.stop_loss = qty, stop        

    def update_position(self):
        current_macd = self.current_macd.macd
        current_signal = self.current_macd.signal

        previous_macd = self.previous_macd.macd
        previous_signal = self.previous_macd.signal

        asagi_yonlu_cakisma_var = current_macd < current_signal and previous_macd > previous_signal

        # Asagi yonlu cakisma varsa hepsini satiyorum
        if self.is_long and asagi_yonlu_cakisma_var:
            self.liquidate()            

    def go_short(self):
        pass

Current_macd değeri ile son macd değerini alıyorum. Previous_macd değeri ile de bir önceki mumda son mum olarak kabul edip macd değerini buluyorum.

Çakışmayı kontrol ederek, al ya da sat sinyali üretiyorum. MacdCrossStrategy’sinde dikkatini çekmek istediğim nokta, hedef değerini başta go_long metodunda belirtmiyorum. Çünkü dinamik olarak satış yapmak istiyorum. Aksi durumda go_long metodunda aşağıdaki gibi bir ifade yazabilirdim:

Alternatif long giriş yöntemi:
def go_long(self):
    # alış fiyatım o anki fiyat
    entry = self.price
    # stop değerim alış fiyatın atr’nin 2 katı aşağısı
    stop = entry - 2*self.atr
    # miktar
    qty = 1
    # hedefim
    profit_target = entry + 5*self.atr

    self.buy = qty, entry
    self.stop_loss = qty, stop
    self.take_profit = qty, profit_target

Bu şekilde yapmak yerine satışı macd aşağı yönlü keserse, satış yapsın diyebilmek için, update_position metodunu eklemiş oldum.

    def update_position(self):
        current_macd = self.current_macd.macd
        current_signal = self.current_macd.signal

        previous_macd = self.previous_macd.macd
        previous_signal = self.previous_macd.signal

        asagi_yonlu_cakisma_var = current_macd < current_signal and previous_macd > previous_signal

        # Asagi yonlu cakisma varsa hepsini satiyorum
        if self.is_long and asagi_yonlu_cakisma_var:
            self.liquidate()            

Artık stratejimiz hazır. Tekrar routes.py dosyasına gidelim ve orada MacdCrossStrategy sınıfını kullanacağımızı belirtelim:

…
# trading routes
routes = [
    ('Binance', 'BTCUSDT', '4h', 'MacdCrossStrategy'),
]
…

Artık test etmek istediğimiz stratejimiz hazır. Şimdi yapmamız gereken, geçmiş verileri veritabanımıza yüklemek. Aksi takdirde backtesting yapamayacağız.

Geçmiş Verileri Veritabanına Yüklemek

import-candles komutu ile verilerimizi yüklüyoruz:

jesse import-candles 'Binance' 'BTCUSDT' '2020-01-01'

Bu komutla 1 ocak 2020 tarihinden bugüne kadar olan tüm binance verilerini veritabanına yüklemiş olacağız.

Seçtiğiniz tarihe bağlı olarak biraz sürecektir.

Verilerimiz yüklendi, artık testimizi çalıştıralım.

Testi Çalıştırmak (Backtest)

jesse backtest ‘baslangic_tarihi’ ‘bitis_tarihi’ komutu ile testimizi başlatalım:

Jesse backtest ‘2020-06-01’ ‘2021-01-15’

Bu komut bize aşağıdaki gibi bir sonuç verecektir:

jesse backtest konsol çıktısı

Gördüğünüz gibi sonuçlar basit bir stratejiye göre çok güzel. Bitcoin’in boğa sezonunda olmasının bir güzelliği 😊

10000 dolarımız 28839.45 dolara yükseldi.

Konsol üzerinde temel verileri böylece görebilmiş oluyorum.

Grafik Çıktı Almak

Jesse’nin daha da güzel bir özelliği de grafik üretmesi.

Jesse backtest ‘2020-06-01’ ‘2021-01-15’ –chart

Sonuna chart parametresini eklediğimizde, bize png formatında dosya çıktı üretecektir.

Ürettiği dosyaya bakalım şimdi de:

jesse backtest chart parametresi ile

İlk grafikte bakiyemizin değişimini, ikincisi de fiyat hareketlerini gösteriyor.

Json, csv formatlarında da çıktı üretebiliriz.

Daha da güzel bir özelliği ise TradingView’da görebileceğimiz şekilde bir pine scripti üretmesi:

Jesse backtest 2020-06-01 2021-01-15 –tradingview

Üretilen dosyayı TradingView’da açalım:

tradingview pine editor

Open menüsünden New blank strategy komutunu çalıştıralım:

tradingview new blank strategy

Jesse’nin ürettiği dosyanın içeriğini editörün içerisine yapıştıralım:

tradingview pine script

Add to Chart komutunu çalıştırıp grafiğe eklemesini sağlayalım:

tradingview final chart

BackTesting Mevzusu Neden Önemlidir ve Sonuç

Algoritmanın geçmiş performansı gelecekte de benzer sonuçları üreteceğinin garantisini vermez. Bu bakımdan backtest canlı trade yapmanın yerini tutmaz. Fakat testlerde olumsuz bir performans gösteren algoritmanın gelecekte başarılı olacağını düşünmek hayalcilik olacaktır.

Bu bakımdan backtest yapmak bir filtre görevi görerek kazanç getirmeyecek algoritmaları eleme veya iyileştirme olanağı sunarak, bize zamandan ve paradan tasarruf ettirecektir.

Örnek projenin github adresi:

samplebacktesting: Basit bir kripto algoritmanın Jesse çatısı ile testi. (github.com)

Faydalanılan Kaynaklar

Resmi sitesi:

Jesse – The Open-source Python Bot For Trading Cryptocurrencies

Github adresi:

jesse-ai/jesse: An advanced crypto trading bot written in Python (github.com)

Ta-lib kurulumu:

How to Install TA-Lib on Ubuntu Server | Dominik Sachsenhofer

Jesse’nin kendi blogu çok faydalı. Tüm yazıların okunması elzem.

Blog – Jesse

Basit bir python bot nasıl yazılır?

python ile kripto para al sat botu yazalım (trading bot): RSI, MACD, vs… (onbirkod.com)

15 thoughts on “Kripto Algoritmanı Jesse ile Test Et (Backtesting)”

  1. Mrb komutlar doğru olduğu halde aşağıdaki hatayı alıyorum neden olabilir
    Uncaught Exception: ValueError: ‘Binance’ is not a supported exchange

    1. jesse import-candles ‘Binance’ ‘BTCUSDT’ ‘2020-01-01’
      komutunu jesse import-candles Binance BTCUSDT 2020-01-01 bu şekilde denedim çalıştı

  2. Jesse make-strategy MacdCrossStrategy ” yi çalıştıramıyorum. önceki kodlar normal çalışıyor. buraya geldiğimde böyle bir hata alıyorum. neden acaba?
    (venv) C:\Users\Kullanıcı\PycharmProjects\pythonProject1>jesse make-strategy MacdCrossStrategy
    ←[31mCurrent directory is not a Jesse project. You must run commands from the root of a Jesse project.←[0m

  3. File “C:\Users\user\AppData\Local\Programs\Python\Python39\lib\pydoc.py”, line 450, in safeimport
    raise ErrorDuringImport(path, sys.exc_info())
    =========================================================================

    Uncaught Exception: ErrorDuringImport: problem in strategies.MacdCrossStrategy – NameError: name ‘self’ is not defined

    Şöyle bir hata alıyorum ne yapabilirim

  4. Merhabalar,
    Kendi postgresql bilgilerimizi nereden bulabiliriz? Önceki binance botu projesini de yapmıştım çalıştı. Emeğinize sağlık. Tek kaliteli türkçe kaynak.

  5. Merhabalar,
    Jesse ile ilgili merak ettiğim bir şey var. Normalde gerçek zamanlı olduğunda bir timeframe için sadece kapalı olan mumlarla değil aynı zamanda anlık olarak mumun durumuna göre alınan veriler de dikkate alınarak al sat komutları giriyoruz. Jesse ile geriye dönük test yaptığımızda bu durum tam olarak nasıl oluyor? İlgili timeframe’e göre sadece kapanmış mumlar üzerinden işlem yapılıyor şeklinde mi test ediyor yoksa belli saniye aralıklarıyla(örneğin her 10 saniyede 1 şeklinde) gelen verilere göre mumun o anki durumuna bağlı mı?
    Paylaşımlarınız için teşekkürler

    1. Merhabalar,
      öncelikle emeğinize sağlık, gerçekten çok faydalı bir çalışma / paylaşım oldu.
      Mantıken mum içindeki değerlere ulaşılması çok zor çünkü çekilen veri geçmişe ait OHCL (open, high, close,low) verisi.
      Benimde merak ettiğim kısım bu şekilde backtest yapmak %100 tutarlılık sağlarmı, 4 saatlik bir mum eğer imbalance mumu ise fiyatın anlık hareketleri canlı ortamda bizi bambaşka noktalara götürür gibi. Bu konuda deneyimlerinizi iletebilirseniz çok sevinirim.
      Emeğiniz için çok teşekkürler tekrar 🙂

Yorum bırakın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Scroll to Top