profit maximizer

Profit Maximizer (PMAX): Supertrend’in Bir Tık Ötesi; Python ile Yazalım

Profit maximizer (pmax) Kıvanç Özbilgiç tarafından geliştirilmiş bir indikatördür. Daha önce supertrend ile ilgili bir yazım vardı. Supertrend indikatörünü python dilinde nasıl yazılacağını yazıda anlatmıştım. Pmax, supertrend ile Anıl Özekşi tarafından geliştirilmiş MOST indikatörünün birleştirilmiş halidir.

Her iki indikatör de trend takip etmek için kullanılan, traderlar tarafından sevilen indikatörlerdendir. Fakat bu indikatörlerin zaafı olarak görülebilecek bir noktası da, yatay seyreden piyasalarda, çok fazla al-sat sinyali vererek verimsiz sonuçlar doğurmasıdır.

Pmax bu anlamda, gereksiz al-sat sinyaller üretmenin önüne geçerek, yatay seyreden piyasalarda da oldukça güzel sonuçlar alınmasına sebep olmaktadır. Hem uzun zaman aralıklarında (1, 4 saat, 1 günlük) hem de kısa zaman aralıklarında (5, 15, 30 dakika) başarılı bir şekilde kullanılabilmektedir.

Kıvanç Hoca profit maximizer (pmax) indikatörünü gayet ayrıntılı ve net bir şekilde anlattı. Aşağıda konuyla ilgili anlatımlarına link vermekle yetineceğim.

Profit Maximizer – PMax İndikatörü Anlatımı with English Subtitles – YouTube

Pmax twitter

Benim her yazıda olduğu gibi amacım bu indikatörü python ile nasıl yazarım onu anlatmak olacaktır.

Tradingview indikatörlerini neden Python diline çeviriyorum. Derdim Ne?

Bazı arkadaşlarımın aklına böyle bir soru gelebilir. Onbirkod.com üzerinde tradingview platformunda kullanılan pek çok indikatörü python diline çevirdim. Böyle bir emeğe çabaya neden giriştim?

Çünkü yapabiliyorum 🙂 Daha önemli bir sebep ise, tradingview ücretli bir platform. Bedava olan üyelik seçeneği çoğu işimizi görse de (3 indikatöre kadar izin veriyor) daha fazla özellik istediğimizde ücretli seçeneğe geçmemiz gerekiyor. Yanlış anlaşılmak istemem. Parasını sonuna kadar hakkeden çok gelişmiş, mükemmel bir platform.

Fakat hiç bir platforma bağımlı kalmak istemeyenler için python dili ve ekosistemi, kütüphaneleri çok güzel bir alternatif sunmaktadır. Python, tradingview’in dili olan pine diline veya metatrader üzerinde çalışan mql dillerine nazaran daha düzgün ve daha iyi tasarlanmış bir dil.

Python açık kaynak bir dil. Herhangi bir ücret ödemek zorunda değilsiniz. Herhangi bir sistemde (windows, linux, macos) kullanabilirsiniz.

Bağımsızlık, gelişmiş dil yapısı, platform bağımsız olması, açık kaynak olması gibi temel özelliklerinin dışında, son olarak da sayabileceğimiz en önemli sebeplerden birisi de esnekliği ve güçlü kütüphanelere sahip olması. Yapay zeka, makina öğrenmesi kütüphaneleri açısından python’un eline su dökebilecek çok fazla dil yok. Bu anlamda, al-sat (trading) bot geliştirirken, son sistem yapay zeka algoritmaları kullanarak sisteminizi tasarlayabilirsiniz. Yapabilecekleriniz hayalgücünüzle sınırlı.

Pek çok onbirkod takipçisi arkadaşım bu indikatörü çok merak ettiğini, nasıl yapılabileceğini maillerde ve yorumlarda sorduğu için bu konuya öncelik tanıdım.

Profit Maximizer (pmax) Python Implementasyonuna Başlıyoruz

Profit maximizer bendeki tradingview görüntüsü nasıl önce ondan başlayalım:

ethereum-tether 5 dakikalık mum grafiği

İlk bakışta pmax indikatörünün nasıl güzel çalıştığını görebilirsiniz. 5 dakikalık ethereum-usdt grafiğinde al (buy) verdiği noktada alım yapmış olsaydık, direnç noktalarına yakın yerlerde satış yapıp kar edebilirdik. Tabi her şey bu kadar basit olmuyor. Ama yine de bize güzel bir ipucu verdiğini de kabul etmek lazım.

Pmax indikatörü ile fiyat hareketlerini (price action) de işin içine katarak güzel sonuçlar alabilirsiniz. Hem day trading hem de swing trading amaçlı kullanabilirsiniz. Hiç bir indikatör yüzde yüz başarılı olmaz. Bu imkansız fakat risk:ödül (risk/reward) olasılıklarına uygun yatırım yaparsanız uzun vadede kazançlı olmamanız için hiç bir sebep yok.

Bendeki tradingview ayarlarına bakalım:

pmax settings

Pmax çok esnek bir indikatör; Hareketli ortalama tipi olarak SMA, EMA, WMA ve VAR gibi çeşitli seçeneklerimiz var.
Buradaki senaryomuzda VAR indikatörünü kullanarak implementasyon yapacağım.

VAR, diğer bir ismi de VIDYA içlerinden en zor olanı ve kullandığım ta-lib içerisinde bulunmayan bir indikatör.
VAR yatay seyreden piyasalarda daha randımanlı çalışan bir ortalama tipi. Diğer bir özelliği de kümülatif olarak çalışıyor.

Yazdığım kodları isterseniz diğer ortalamalara da çok rahat bir şekilde uyarlayabilirsiniz.

VAR (Vidya): Değişken Endeks Dinamik Ortalama Nedir?

İlk defa Tushar Chande tarafından geliştirildi. Üssel hareketli ortalama (EMA) performansını arttırmak için geliştirilmiştir. Hatalı al-sat sinyallerini elemeye, ortalamayı yumuşatmaya, daha düzgün bir değer elde etmeye imkan sağlamaktadır.

Değişkenliği ölçmek için Chande Momentum Osilatör (CMO) kullanılıyor içerisinde.

Teknik detaylar ve hesaplama yöntemini bulmak için aşağıda verdiğim linklere bakabilirsiniz:

http://www.fxcorporate.com/help/MS/NOTFIFO/i_Vidya.html

https://www.metatrader5.com/en/terminal/help/indicators/trend_indicators/vida

VAR (VIDYA) ve pmax fonksiyonlarını sizlere python olarak sunacağım. Sizler de bunları dilediğiniz şekilde, botlarınızda kullanabilirsiniz.

Kurulması Gereken Paketler

numpy
ta-lib
python-binance

Pmax hesaplamak için gereken bazı değerler var. VAR (Vidya) onlardan birisi, o yüzden öncelikle VAR dizisini oluşturan fonksiyonu yazalım:

def generateVar(high_array, low_array):
    moving_average_length = 10

    valpha = 2/(moving_average_length + 1)

    hl2 = (high_array + low_array)/2

    vud1 = []

    before_val = 0

    for current_hl2 in hl2:
        if current_hl2 > before_val:
            vud1.append(current_hl2 - before_val)
        else:
            vud1.append(0)

        before_val = current_hl2

    vdd1 = []

    for current_hl2 in hl2:
        if current_hl2 < before_val:
            vdd1.append(before_val - current_hl2)
        else:
            vdd1.append(0)

        before_val = current_hl2

    vUD = []

    geriden_gelen_indx = 0

    len_vud1 = len(vud1)

    finished = False

    for j in range(1,9):
        window_sum = 0
        for k in range(0,j):
            window_sum = window_sum + vud1[k]
        vUD.append(window_sum)

    while geriden_gelen_indx < len_vud1:
        window_sum = 0
        for i in range(0,9):
            current_indx = geriden_gelen_indx + i
            if current_indx >= len_vud1:
                finished = True
                break
            window_sum = window_sum + vud1[current_indx]
        vUD.append(window_sum)

        if finished:
            break

        geriden_gelen_indx = geriden_gelen_indx + 1

    vUD_ar = np.asarray(vUD[:-1])

    vDD = []

    geriden_gelen_indx = 0

    len_vdd1 = len(vdd1)

    finished = False

    for j in range(1,9):
        window_sum = 0
        for k in range(0,j):
            window_sum = window_sum + vdd1[k]
        vDD.append(window_sum)

    while geriden_gelen_indx < len_vdd1:
        window_sum = 0
        for i in range(0,9):
            current_indx = geriden_gelen_indx + i
            if current_indx >= len_vdd1:
                finished = True
                break
            window_sum = window_sum + vdd1[current_indx]
        vDD.append(window_sum)

        if finished:
            break

        geriden_gelen_indx = geriden_gelen_indx + 1

    vDD_ar = np.asarray(vDD[:-1])

    vCMO = ((vUD_ar - vDD_ar) / (vUD_ar + vDD_ar))

    hl2_left = hl2[:]

    var_before = 0.0

    var = []

    for i in range(0, len(high_array)-1):
        var_current = (valpha * abs(vCMO[i])*hl2_left[i]) + (1 - valpha*abs(vCMO[i]))*var_before
        var.append(var_current)
        var_before = var_current

    var_arr = np.asarray(var)

    return var_arr

CMO osilatörü öncelikle hesaplanıyor, ardından kümülatif olarak VAR dizisi hesaplanıyor.

VAR hesaplamasını yaptıktan sonra, pmax dizisini oluşturmak için, python-binance apisini kullanarak, mum verilerini (high, low, close) okuyoruz.

Bunun için öncelikle bir config.py dosyasına binance hesabımıza ait binance api-key değerlerini yaziyoruz:

config.py
API_KEY = 'yourbinanceapikey'
API_SECRET = 'yourbinanceapisecret'

Api-key değerlerimizi doğru olarak girdikten sonra artık ohcl (open, high, close, low) verilerini okuyabiliriz. Kapanmış mumları almak için dizinin son elemanını çıkarıyoruz (close_array = close_array1[:-1])

import config

klines = client.get_klines(symbol=pair, interval=interval, limit=limit)

open_time = [int(entry[0]) for entry in klines]
open_klines = [float(entry[1]) for entry in klines]
high = [float(entry[2]) for entry in klines]
low = [float(entry[3]) for entry in klines]
close = [float(entry[4]) for entry in klines]

close_array1 = np.asarray(close)
close_array = close_array1[:-1]

high_array1 = np.asarray(high)
high_array = high_array1[:-1]

low_array1 = np.asarray(low)
low_array = low_array1[:-1]

open_array1 = np.asarray(open_klines)
open_array = open_array1[:-1]

# Vidya (VAR) hesaplamasini yapiyorum
var_arr = generateVar(high_array, low_array)

# Profit maximizer (pmax) hesaplamak icin, bir onceki satirda hesaplamis oldugum
# var arrayini parametre olarak gonderiyorum
pmax = generatePMax(var_arr, close_array, high_array, low_array, 10, 3)

generatePMax fonksiyonumuzu da yazalım:

def generatePMax(var_array, close_array, high_array, low_array, atr_period, atr_multiplier):

    try:
        atr = ta.ATR(high_array, low_array, close_array, atr_period)
    except Exception as exp:
        print('exception in atr:', str(exp), flush=True)
        return []

    previous_final_upperband = 0
    previous_final_lowerband = 0
    final_upperband = 0
    final_lowerband = 0
    previous_var = 0
    previous_pmax = 0
    pmax = []
    pmaxc = 0

    for i in range(0, len(close_array)):
        if np.isnan(close_array[i]):
            pass
        else:
            atrc = atr[i]
            varc = var_array[i]

            if math.isnan(atrc):
                atrc = 0

            basic_upperband = varc + atr_multiplier * atrc
            basic_lowerband = varc - atr_multiplier * atrc

            if basic_upperband < previous_final_upperband or previous_var > previous_final_upperband:
                final_upperband = basic_upperband
            else:
                final_upperband = previous_final_upperband

            if basic_lowerband > previous_final_lowerband or previous_var < previous_final_lowerband:
                final_lowerband = basic_lowerband
            else:
                final_lowerband = previous_final_lowerband

            if previous_pmax == previous_final_upperband and varc <= final_upperband:
                pmaxc = final_upperband
            else:
                if previous_pmax == previous_final_upperband and varc >= final_upperband:
                    pmaxc = final_lowerband
                else:
                    if previous_pmax == previous_final_lowerband and varc >= final_lowerband:
                        pmaxc = final_lowerband
                    elif previous_pmax == previous_final_lowerband and varc <= final_lowerband:
                        pmaxc = final_upperband

            pmax.append(pmaxc)

            previous_var = varc

            previous_final_upperband = final_upperband

            previous_final_lowerband = final_lowerband

            previous_pmax = pmaxc

    return pmax

Supertrend kodları ile benzerliğini farkedebilirsiniz.

Supertrend hesaplarken, high ve low değerlerini sınırları hesaplarken kullanıyorduk.

basic_upperband = (highc + lowc) / 2 + atr_multiplier * atrc
 basic_lowerband = (highc + lowc) / 2 - atr_multiplier * atrc

Pmax için ise onun yerine vidya’yı kullanıyoruz:

basic_upperband = varc + atr_multiplier * atrc
basic_lowerband = varc - atr_multiplier * atrc

İki genel amaçlı metodumuzu yazdık. Şimdi de bunu basit bir bot içerisinden çağıralım. Sonsuz bir döngü içerisinde, binance verilerini okuyarak, pmax al sinyalini yakalayalım:

#python binance client objemizi olusturuyoruz.
client = Client(config.API_KEY, config.API_SECRET)

# ikilimizi seciyoruz
pair = 'ETHUSDT'

# istediğimiz mum sayısını belirliyoruz
limit = 500

# zaman araligi, 5 dakikalik grafige bakiyorum
interval = '5m'

while 1:
	# binance'in limitlerine takilmamak icin, biraz bekliyoruz. 10 saniye kadar.
	time.sleep(10)

	try:
		klines = client.get_klines(symbol=pair, interval=interval, limit=limit)
	except Exception as exp:
		# baglanti hatasi olursa, biraz bekleyip, tekrar yeni client olusturuyor,
		# donguye kaldigim yerden devam ediyorum
		msg = f'exception in get_klines {str(exp)}'
		print(msg, flush=True)
		time.sleep(10)
		client = Client(config.API_KEY, config.API_SECRET)
		continue

	open_time = [int(entry[0]) for entry in klines]
	open_klines = [float(entry[1]) for entry in klines]
	high = [float(entry[2]) for entry in klines]
	low = [float(entry[3]) for entry in klines]
	close = [float(entry[4]) for entry in klines]

	close_array1 = np.asarray(close)
	close_array = close_array1[:-1]

	high_array1 = np.asarray(high)
	high_array = high_array1[:-1]

	low_array1 = np.asarray(low)
	low_array = low_array1[:-1]

	open_array1 = np.asarray(open_klines)
	open_array = open_array1[:-1]

	# Vidya (VAR) hesaplamasini yapiyorum
	var_arr = generateVar(high_array, low_array)

	# Profit maximizer (pmax) hesaplamak icin, bir onceki satirda hesaplamis oldugum
	# var arrayini parametre olarak gonderiyorum
	pmax = generatePMax(var_arr, close_array, high_array, low_array, 10, 3)

	last_var = var_arr[-1]
	previous_var = var_arr[-2]

	last_pmax = pmax[-1]
	previous_pmax = pmax[-2]

	print('last var:', last_var, 'last pmax', last_pmax, flush=True)

	if (last_var > last_pmax and previous_var < previous_pmax):
		msg = f'buy signal for {pair}'
		print(msg, flush=True)

	if last_var < last_pmax and previous_var > previous_pmax:
		msg = f'sell signal for {pair}'
		print(msg, flush=True)		

Güncelleme

Pmax indikatöründe farklı ortalama tiplerini seçebiliyorsunuz. VAR (vidya) ortalama tipini esas alarak uygulamayı geliştirmiştim. EMA ortalama tipine ihtiyaç duyan olursa diye EMA ortalamasını da seçenek olarak github ortamındaki koda ekledim.

if ortalama_tipi == 'EMA':

	# EMA (EMA) hesaplamasini yapiyorum
	ema_arr = generateEma(high_array, low_array, moving_average_length=10)

	# Profit maximizer (pmax) hesaplamak icin, bir onceki satirda hesaplamis oldugum
	# var arrayini parametre olarak gonderiyorum
	pmax = generatePMax(ema_arr, close_array, high_array, low_array, 10, 3)

	last_ema = ema_arr[-1]
	previous_ema = ema_arr[-2]

	last_pmax = pmax[-1]
	previous_pmax = pmax[-2]

	print('last ema:', last_ema, 'last pmax', last_pmax, flush=True)

	if (last_ema > last_pmax and previous_ema < previous_pmax):
		msg = f'buy signal for {pair}'
		print(msg, flush=True)

	if last_ema < last_pmax and previous_ema > previous_pmax:
		msg = f'sell signal for {pair}'
		print(msg, flush=True)

Kodun son halini github üzerinden inceleyebilirsiniz:

ttufekci/pmax: profit maximizer (pmax) implementation in python (github.com)

18 thoughts on “Profit Maximizer (PMAX): Supertrend’in Bir Tık Ötesi; Python ile Yazalım”

  1. Merhaba çok yararlı bir paylaşım olmuş, size bir önerim olacak. Ben synology nas cihazımdaki web server üzerinde çalışıyorum. Ta-Lib i yüklemeyi beceremeyince alternatif olarak pandas_ta kütüphanesi keşfettim. Talib yerine pandas_ta yı kullanıyorum. (https://github.com/twopirllc/pandas-ta) Bu kütüphanede vidya mevcut pmax ı daha kolay yazmanızı sağlayabilir. Ayrıca entegre olarak supertrend de mevcut.

    1. aynı şekilde bende pandas-ta üzerinden ilerliyorum.
      çok daha hızlı gelişen bi kütüphane. Ayrıca ta-lib yüklemeye de gerek kalmadı

  2. al sat sinyallerine bakıyorum da tepeyi geçince yada alışı geçince veriyor arada alış satış farkıda çok minimize pek sarmadı bu indikatör bana

  3. Elinize sağlık hocam :))
    şu an başlattım bakalım nasıl sonuçlanacak 🙂 buy/sell sinyalinde işleme girip çıkıyorum 50x ile..

    VETUSDT ——————START—————–
    last var: 0.07643779778265652 last pmax 0.07576949200637356
    IOSTUSDT ——————START—————–
    last var: 0.020887977208516414 last pmax 0.02071535207020709
    TRXUSDT ——————START—————–
    last var: 0.0613029012374088 last pmax 0.06095001184562004
    XLMUSDT ——————START—————–
    last var: 0.2421611079022958 last pmax 0.24365696044671648
    SXPUSDT ——————START—————–
    last var: 1.9100898932261068 last pmax 1.8944799118192102
    SANDUSDT ——————START—————–
    last var: 0.4761994686103978 last pmax 0.46060647343734257
    buy signal for SANDUSDT
    SANDUSDT :ALLL sinyali verdi ,alış fiyatı: 0.48325 ,time 12:54:30
    Long açtım!
    Alış: 0.48236 Kar: 0.48380708 Zarar: 0.48043056
    Alış: 0.48236 Kar: 0.48380708 Zarar: 0.48043056
    Alış: 0.48236 Kar: 0.48380708 Zarar: 0.48043056
    Alış: 0.48236 Kar: 0.48380708 Zarar: 0.48043056
    Alış: 0.48236 Kar: 0.48380708 Zarar: 0.48043056
    Aldım paracıkları :))
    ATOMUSDT ——————START—————–
    last var: 14.610282340961035 last pmax 14.396409050782005
    EGLDUSDT ——————START—————–
    last var: 90.1226922003912 last pmax 88.95705955043049

      1. her botun kendine özeldir aslında ama kabaca anlatayım.
        ben elimdeki paranın tamamını, alarm fiyatı ile alabileceğim coin kadar hesaplatarak al sat yapıyorum. örnek 100coin al demiyorum da, 100USDT lik coin al diyorum ve sürekli bu hesabı yaptırıyorum. işlem açmadan önce de balance kontrolü yapıyorum elimde ne var ne yok, para mı var coin mi var diye. Ona göre pozisyon başlatıyorum. Coin varsa ve long da ise coinden çıkmak için long exit şartlarını çalıştırıyorum. veya tam tersini.

        client.futures_change_leverage(symbol=symbol, leverage=50)
        buy_order = client.futures_create_order(
        symbol=symbol,
        side=SIDE_BUY,
        type=FUTURE_ORDER_TYPE_MARKET,
        quantity=quantityAL,
        isIsolated=’TRUE’

    1. Hocam pmax i future de kullanmayı çok istediğim, çok farklı ayarlarla, mumlarla denedim ama hiç mantıklı gelmedi. Siz gerçekten kullanabildinizmi?

  4. 1 haftadır yaptığım işlemlerin 10da 7si zararla kapanıyor. üstüne karlı işlemlerdeki karlığı da supertrend kadar bile değil. supertrende devam.

  5. Hocam elinize sağlık. Her hissenin fiyat hareketi farklı olduğu için pmax değerlerine hisse ile ilgili backtest ve optimizasyon nasıl yapabiliriz. Bununla ilgili bir kod örneği paylaşabilir misiniz

  6. Merhba,
    Fisher Transform indicatoru için aşağıdaki gibi bir fonksiyon oluşturmuştum. Fakat Tradingview’e göre 1 mum falan erken yada geç tepki veriyor. Bu konuda yardımcı olabilecek var mı?
    https://tr.tradingview.com/script/4L4GZQT8-Fisher-Transform-Indicator-by-Ehlers/
    def fisherT(high,low,n):
    sizeArray = len(high)
    hl = (high + low)/2
    maxHln = [max(hl[x:x+n]) for x in range(sizeArray-n+1)]
    minHln = [min(hl[x:x+n]) for x in range(sizeArray-n+1)]
    valTn = [0.33*2*((hl[x+n-1]-minHln[x])/(maxHln[x]-minHln[x])-0.5) if maxHln[x]-minHln[x] != 0 else 0.33*2*((hl[x+n-1] – minHln[x])/(0.001)-0.5) for x in range(sizeArray-n+1)]
    for i in range(1, sizeArray-n+1):
    valTn[i] = valTn[i] + 0.67 * valTn[i-1]
    if valTn[i] > 0.99:
    valTn[i] = 0.999
    elif valTn[i] < -0.99:
    valTn[i] = -0.999
    _fisher = [0.5*np.log((1.0+valTn[x])/(1.0-valTn[x])) for x in range(sizeArray-n+1)]
    _fisherSignal = []
    for i in range(1,sizeArray-n+1):
    _fisher[i] = _fisher[i] + 0.5 * _fisher[i-1]
    _fisherSignal.append(_fisher[i-1])
    fisher = np.zeros(sizeArray)
    fisherSignal = np.zeros(sizeArray)
    fisher[n-1:] = _fisher
    fisherSignal[n:] = _fisherSignal
    return fisher, fisherSignal

  7. Hocam konuyla hiç alakası yokta bir şey danışabilir miyim sizlere? Bir anda bir kodla aynı anda 10 long 10 short işlemi açtırmak mümkün mü acaba varsa nasıl bir kodla yazabiliriz?

    1. main.py kodu içindeki ortalama_tipi = ‘VAR’ yazan yeri,

      ortalama_tipi = ‘EMA’ yapmanız gerek. var’ı ema ya cevireceksiniz yani.

Yorum bırakın

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

Scroll to Top