AlphaTrend logo

AlphaTrend, piyasadaki trendin yönünü belirlemek için geliştirilen çoğu indikatörün aksine yüksek doğruluk oranı ve gelişmiş adaptasyon yeteneği sayesinde, hem ani piyasa dalgalanmalarını güvenilir şekilde tespit eder hem de uzun vadeli trend değişimlerini erken safhada öngörerek yatırımcılara stratejik avantajlar sunar. Ünlü Ekonomist Kıvanç Özbilgiç’in TradingView’de TypeScript ile ortaya koyduğu bu yapı, temel olarak aşağıda bahsedilen prensiplere dayanıyor.

Tam Kod

from binance import Client
import csv
import pandas as pd
from datetime import datetime
import pandas_ta as ta
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import FuncFormatter
import os
import subprocess

client = Client(None, None)


def verileriGetir(sembol, periyot, baslangic, bitis):
    mumlar = client.get_historical_klines(sembol, periyot, baslangic, bitis)
    return mumlar


def csvOlustur(sembol, mumlar):
    csvDosya = open(sembol + ".csv", 'w', newline='')
    yazici = csv.writer(csvDosya, delimiter=',')
    for mumverileri in mumlar:
        yazici.writerow(mumverileri)
    csvDosya.close()


def zamanHesapla(timestamp):
    return datetime.fromtimestamp(timestamp / 1000)


def indikator(okunacakCsv):
    basliklar = ['open_time', 'open', 'high', 'low', 'close', 'vol',
                 'close_time', 'qav', 'nat', 'tbbav', 'tbqav', 'ignore']
    df = pd.read_csv(okunacakCsv, names=basliklar)
    open_ = df['open'].astype(float)
    close = df['close'].astype(float)
    high = df['high'].astype(float)
    low = df['low'].astype(float)
    volume = df['vol'].astype(float)
    ap = 14
    tr = ta.true_range(high, low, close)
    atr = ta.sma(tr, ap)
    noVolumeData = False
    coeff = 1
    upt = []
    downT = []
    Trend = [0.0]
    src = close
    rsi = ta.rsi(src, ap)
    mfi = ta.mfi(high, low, close, volume, ap)

    for i in range(len(low)):
        if pd.isna(atr[i]):
            upt.append(0)
        else:
            upt.append(low[i] - (atr[i] * coeff))

    for i in range(len(high)):
        if pd.isna(atr[i]):
            downT.append(0)
        else:
            downT.append(high[i] + (atr[i] * coeff))

    for i in range(1, len(close)):
        if noVolumeData and rsi[i] >= 50:
            if upt[i] < Trend[i - 1]:
                Trend.append(Trend[i - 1])
            else:
                Trend.append(upt[i])
        elif not noVolumeData and mfi[i] >= 50:
            if upt[i] < Trend[i - 1]:
                Trend.append(Trend[i - 1])
            else:
                Trend.append(upt[i])
        else:
            if downT[i] > Trend[i - 1]:
                Trend.append(Trend[i - 1])
            else:
                Trend.append(downT[i])

    k1 = Trend
    k2 = [0, 0] + Trend[:-2]  # Trend'in 2 birim kaydırılmış hali

    at = pd.DataFrame({'k1': k1, 'k2': k2})
    return at


def BackTest(sembol, bakiye, baslangic_bakiye):
    try:
        cuzdan = bakiye
        baslangic_cuzdan = baslangic_bakiye
        alimSayisi = 0
        satimSayisi = 0
        toplamKoin = 0
        komisyonOrani = 0.00075  # %0.075 komisyon oranı
        komisyon = 0
        csvName = sembol + ".csv"
        basliklar = ['open_time', 'open', 'high', 'low', 'close', 'vol',
                     'close_time', 'qav', 'nat', 'tbbav', 'tbqav', 'ignore']
        df = pd.read_csv(csvName, names=basliklar)
        acilisZamani = df['open_time']
        kapanis = df['close'].astype(float)
        at = indikator(csvName)
        k1 = at['k1']
        k2 = at['k2']
        sinyalSirasi = ['s']
        alis_kapanis = []
        satis_kapanis = []
        alis_zaman = []
        satis_zaman = []
        output_file = open("Backtest_Sonuclari.txt", "w", encoding='utf-8')

        for i in range(1, at.shape[0]):
            # Alış sinyali
            if k1[i - 1] <= k2[i - 1] and k1[i] > k2[i] and sinyalSirasi[-1] != 'a':
                if cuzdan > 0:
                    alimSayisi += 1
                    alis_kapanis.append(kapanis[i])
                    alis_zaman.append(acilisZamani[i])
                    islem_tutari = cuzdan
                    komisyon_tutar = komisyonOrani * islem_tutari
                    komisyon += komisyon_tutar
                    net_bakiye = islem_tutari - komisyon_tutar
                    toplamKoin = net_bakiye / kapanis[i]
                    output_file.write(
                        f"{zamanHesapla(acilisZamani[i])} tarihinde "
                        f"{kapanis[i]} fiyatından {round(toplamKoin, 6)} "
                        f"adet {sembol} alındı\n"
                    )
                    sinyalSirasi.append('a')
                    cuzdan = 0
                else:
                    sinyalSirasi.append('a')
            # Satış sinyali
            elif k1[i - 1] >= k2[i - 1] and k1[i] < k2[i] and sinyalSirasi[-1] != 's':
                if toplamKoin > 0:
                    satimSayisi += 1
                    satis_kapanis.append(kapanis[i])
                    satis_zaman.append(acilisZamani[i])
                    islem_tutari = toplamKoin * kapanis[i]
                    komisyon_tutar = komisyonOrani * islem_tutari
                    komisyon += komisyon_tutar
                    net_tutar = islem_tutari - komisyon_tutar
                    cuzdan = net_tutar
                    output_file.write(
                        f"{zamanHesapla(acilisZamani[i])} tarihinde "
                        f"{kapanis[i]} fiyatından {round(toplamKoin, 6)} "
                        f"adet {sembol} satıldı\n"
                    )
                    sinyalSirasi.append('s')
                    toplamKoin = 0
                else:
                    sinyalSirasi.append('s')

        # Backtest sonucu
        output_file.write("-----------------------------------\n")
        output_file.write(f"Başlangıç Spot Cüzdan : ${round(baslangic_cuzdan, 2)}\n")
        output_file.write(f"Toplam verilen Komisyon : ${round(komisyon, 2)}\n")

        if toplamKoin > 0:
            son_fiyat = kapanis.iloc[-1]
            mevcut_deger = toplamKoin * son_fiyat
            output_file.write(f"Son Cüzdan (Nakit): ${round(cuzdan, 2)}\n")
            output_file.write(f"Kalan {sembol} miktarı : {round(toplamKoin, 6)} adet\n")
            output_file.write(f"Kalan {sembol} değeri (Son fiyattan): ${round(mevcut_deger, 2)}\n")
            output_file.write(f"Toplam Portföy Değeri: ${round(cuzdan + mevcut_deger, 2)}\n")
        else:
            output_file.write(f"Son Cüzdan : ${round(cuzdan, 2)}\n")
            output_file.write(f"Toplam Portföy Değeri: ${round(cuzdan, 2)}\n")

        output_file.write(f"Toplam Alım Sayısı : {alimSayisi}\n")
        output_file.write(f"Toplam Satım Sayısı : {satimSayisi}\n")
        output_file.write("-----------------------------------\n")
        output_file.close()
        sinyal_grafigi(acilisZamani, kapanis, alis_zaman, alis_kapanis,
                       satis_zaman, satis_kapanis, sembol)
    except Exception as e:
        print("Bir hata oluştu:", e)


def verigetirmefonksiyonu(sembol, tarih1, tarih2):
    csvOlustur(sembol, verileriGetir(sembol, Client.KLINE_INTERVAL_1DAY, tarih1, tarih2))
    print(sembol, "Veriler Getirildi.")


def sinyal_grafigi(acilisZamani, kapanis, alis_zaman, alis_kapanis,
                   satis_zaman, satis_kapanis, sembol):
    acilisZamani = [zamanHesapla(zaman) for zaman in acilisZamani]
    alis_zaman = [zamanHesapla(zaman) for zaman in alis_zaman]
    satis_zaman = [zamanHesapla(zaman) for zaman in satis_zaman]

    plt.figure(figsize=(16, 8), dpi=100)
    plt.plot(acilisZamani, kapanis, color='black', linewidth=1.1, label='Kapanış Fiyatı')

    plt.scatter(alis_zaman, alis_kapanis, color='green', marker='^', s=100, label='Alış Sinyali')
    plt.scatter(satis_zaman, satis_kapanis, color='red', marker='v', s=100, label='Satış Sinyali')

    plt.title(f'Alış ve Satış Sinyalleri - {sembol}', fontsize=16)
    plt.xlabel('Tarih', fontsize=14)
    plt.ylabel('Fiyat (USD)', fontsize=14)

    ax = plt.gca()
    date_format = mdates.DateFormatter('%d-%m-%Y')
    ax.xaxis.set_major_formatter(date_format)
    plt.xticks(rotation=45)

    plt.grid(True, which='both', linestyle='--', linewidth=0.5, alpha=0.7)

    def y_axis_format(y, pos):
        return '${:,.0f}'.format(y)
    ax.yaxis.set_major_formatter(FuncFormatter(y_axis_format))

    plt.legend(fontsize=12)
    plt.tight_layout()
    plt.savefig('sinyal_grafigi.png')
    plt.close()


# Parametreler
okunacakCsv = 'SOLUSDT.csv'
tarih_araligi_1 = '1 Jan 2020'
tarih_araligi_2 = '02 Dec 2024'
bakiye = 100
baslangic_bakiye = 100

sembol = okunacakCsv[:-4]
verigetirmefonksiyonu(sembol, tarih_araligi_1, tarih_araligi_2)
BackTest(sembol, bakiye, baslangic_bakiye)


def open_file(file_path):
    try:
        if os.name == 'nt':
            os.system(f"start {file_path}")
        elif os.name == 'posix':
            subprocess.Popen(['open', file_path])
    except Exception as e:
        print(f"{file_path} dosyası açılamadı: {e}")


open_file('sinyal_grafigi.png')
open_file('Backtest_Sonuclari.txt')

1. Temel Yapı

ATR (Average True Range): Fiyatların oynaklığını ölçmek için yüksek, düşük ve kapanış fiyatları kullanılarak ATR hesaplanıyor. Bu değer, 14 periyotluk basit hareketli ortalama ile pürüzsüzleştiriliyor.

Trend Çizgileri (upt ve downT):

Koşullu Güncelleme: RSI veya MFI gibi hacim ve momentum göstergelerine bağlı olarak, piyasa koşullarına uyum sağlayan dinamik bir trend çizgisi (k1) oluşturuluyor. Eğer MFI/RSI 50’nin üzerindeyse destek hattı esas alınırken, aksi durumda direnç hattı kullanılıyor.

2. Python’a Adaptasyon ve Backtest Mantığı

a. Veri Çekimi ve CSV Oluşturma

Veri Çekimi: verileriGetir(sembol, periyot, baslangic, bitis) fonksiyonu, Binance API’si üzerinden belirlenen tarih aralığındaki mum (candlestick) verilerini getirir.

CSV Oluşturma: csvOlustur(sembol, mumlar) fonksiyonu, çekilen verileri CSV dosyasına yazar. Bu, pandas kütüphanesiyle veri analizi yapmayı kolaylaştırır.

b. AlphaTrend Hesaplamaları

Veri Hazırlığı: indikator(okunacakCsv) fonksiyonu, CSV’deki verileri pandas DataFrame’e aktarır ve gerekli sütunları float tipine çevirir.

Teknik Göstergeler:

Trend Hesaplaması: Her periyotta, upt ve downT dizileri hesaplanır. Ardından, önceki periyodun trend değeriyle kıyas yapılarak, mevcut periyodun trend değeri (k1) belirlenir. Bu basit koşul ifadeleri, alım-satım sinyallerini oluşturmak için kullanılır.

c. Backtest İşlemi

BackTest(sembol, bakiye, baslangic_bakiye) fonksiyonu, stratejinin geçmiş veriler üzerinde nasıl performans gösterdiğini test eder. İşleyiş şu şekilde:

Başlangıç Ayarları: Cüzdan bakiyesi, başlangıç bakiyesi, işlem sayıları, toplam coin miktarı ve komisyon oranı (örneğin, %0.075) tanımlanır.

Veri ve Gösterge Entegrasyonu: Daha önce oluşturulan CSV dosyası pandas ile okunur. indikator fonksiyonu ile hesaplanmış trend verileri (k1 ve k2) elde edilir.

İşlem Sinyalleri Üretimi:

İşlemler sırasında komisyon hesaplamaları titizlikle uygulanır.

Sonuçların Raporlanması: İşlem detayları Backtest_Sonuclari.txt dosyasına yazılır. sinyal_grafigi fonksiyonu ile matplotlib kullanılarak grafiksel rapor oluşturulur.

3. Gerekli Kütüphaneler

Projenin çalışması için aşağıdaki Python kütüphanelerine ihtiyaç var:

4. Projeyi Çalıştırma Adımları

1. Sanal Ortam Oluşturma:

python -m venv venv

Sanal ortamı aktive edin:

2. Kütüphanelerin Yüklenmesi:

pip install -r requirements.txt

3. Kodu Çalıştırma:

python backtest.py

4. Sonuçları İnceleyin:

Oluşturulan Backtest_Sonuclari.txt ve sinyal_grafigi.png dosyalarını kontrol edin.

5. Sonuç

Bu yazıda, Kıvanç Özbilgiç’in geliştirdiği AlphaTrend göstergesinin temel prensiplerini ve Python’a adaptasyonunu profesyonel bir yaklaşımla ele aldık. İndikatörün hesaplama adımlarından backtest sürecine kadar her aşama, net ve sistematik bir biçimde detaylandırıldı.

Kıvanç Özbilgiç’in bu değerli katkısı, stratejik analiz süreçlerimizi önemli ölçüde optimize etmemize olanak sağlamış ve iş akışlarımızı sadeleştirmiştir. Bu bağlamda, kendisine samimi teşekkürlerimizi sunuyoruz.