Ünlü bir borsa indikatörü olduğunu öğrendiğim ama aslında hiç ilgisi olmayan bir yerde büyük data analizi için sıradışı hareketlerle tahminler üretmek amacıyla kullandığım Kaufman ortalaması gerçekten hayat kurtarabiliyormuş. Bunu kullanmamı öneren, ufuk ve zihin açıcı ve gerçekten her açıdan fikirleri ile beni çok ciddi zehirleyen ve istikrarlı bir şekilde uykularımı kaçıran -ismini ne yazık ki yazamayacağım- kişiye de selam olsun 🙂
Bu uyarlanabilir hareketli ortalama, Perry Kaufman tarafından geliştirilmiştir. Perry Kaufman, 40 yılı aşkın süredir kurumlara ve bireysel yatırımcılar için sistematik stratejiler çalışan nicel finans teorisyenidir. Algoritmik ticaret programlarının geliştirilmesinde önde gelen bir uzman olarak kabul edilir. Kaufman’ın Uyarlanabilir Hareketli Ortalaması (KAMA) güçlü trend takip eden bir gösterge olup, temeli “Üstel Hareketli Ortalama” ‘ya (EMA) dayanır. Hem trend, hem de oynaklığa duyarlıdır.
Kaufman’ın Uyarlanabilir Hareketli Ortalamasını buradan sonra KAMA olarak anacağım.
İnternet gerçekten müthiş bir kaynak. Aradığınız her detayı rahatlıkla bulabiliyorsunuz. KAMA ile ilgilide -hele ki konu borsa ile alakalı olunca- onlarca kaynağa ulaşabilirisiniz. Ben sadece bunu python üzerinde kolayca nasıl kullanacağınızı göstermek istiyorum ve hedefim de bu.
İşin native matematiği ile ilgili iseniz şurada güzel bir kaynak önerebilirim;
https://fxcodebase.com/wiki/index.php/Kaufman%27s_Adaptive_Moving_Average_(KAMA)
KAMA formülü girişlerini anlamak için şu kaynak gerçekten çok açıklayıcı;
https://corporatefinanceinstitute.com/resources/equities/kaufmans-adaptive-moving-average-kama/
En altta bir çok kaynak paylaşacağım, şimdilik anlamak üzere üstteki linkler yeterli; uygulama tarafına geçeyim. Uygulama da kullandığım modüller
- Pandas : https://pypi.org/project/pandas/
- Numpy : https://pypi.org/project/numpy/
- Matplotlib : https://pypi.org/project/matplotlib/
- Görsel zenginlik için tabii ki Seaborn : https://pypi.org/project/seaborn/
Kullandığım hesaplayıcı fonksiyon şöyle;
def kama(getValue, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs): """Indicator: Kaufman's Adaptive Moving Average (KAMA) - @hmustak""" # Validate Arguments length = int(length) if length and length > 0 else 10 fast = int(fast) if fast and fast > 0 else 2 slow = int(slow) if slow and slow > 0 else 30 getValue = verify_series(getValue, max(fast, slow, length)) drift = get_drift(drift) offset = get_offset(offset) if getValue is None: return # Calculate Result def weight(length: int) -> float: return 2 / (length + 1) fr = weight(fast) sr = weight(slow) abs_diff = non_zero_range(getValue, getValue.shift(length)).abs() peer_diff = non_zero_range(getValue, getValue.shift(drift)).abs() peer_diff_sum = peer_diff.rolling(length).sum() er = abs_diff / peer_diff_sum x = er * (fr - sr) + sr sc = x * x m = getValue.size result = [npNaN for _ in range(0, length - 1)] + [0] for i in range(length, m): result.append(sc.iloc[i] * getValue.iloc[i] + (1 - sc.iloc[i]) * result[i - 1]) kama = Series(result, index=getValue.index) # Offset if offset != 0: kama = kama.shift(offset) # Handle fills if "fillna" in kwargs: kama.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: kama.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category kama.name = f"KAMA_{length}_{fast}_{slow}" kama.category = "overlap" return kama
Burada bizim senaryomuza göre Excel üzerine indirdiğimiz ~150bin verinin 200, 2, 30 ve 20, 2, 30 ‘luk KAMA değeri ile 30 datalık Hareketli ortalamasını almak üzere yola çıktık. Excelde istediğimiz kolonun grafiğini hazırlarken, başka kolonlara göre de bazı filtrasyonları da çalıştırmayı denedik. Kod içine ufak notlar aldım, inceleyebilirsiniz. Kodlardan görebildiğiniz üzere benim excelim’de referans olarak tarih, kolon_1 ve kolon_2 kolonları bulunmakta.
# -*- coding: utf-8 -*- """ @author: Hakan Müştak @2022 #hmustak @mail: hakan[@]mustak.org @web: mustak.org @social: twitter.com/hmustak """ from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series import pandas as pd from pandas import Series from numpy import nan as npNaN import seaborn as sns from matplotlib import pyplot as plt def kama(getValue, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs): """Indicator: Kaufman's Adaptive Moving Average (KAMA)""" # Validate Arguments length = int(length) if length and length > 0 else 10 fast = int(fast) if fast and fast > 0 else 2 slow = int(slow) if slow and slow > 0 else 30 getValue = verify_series(getValue, max(fast, slow, length)) drift = get_drift(drift) offset = get_offset(offset) if getValue is None: return # Calculate Result def weight(length: int) -> float: return 2 / (length + 1) fr = weight(fast) sr = weight(slow) abs_diff = non_zero_range(getValue, getValue.shift(length)).abs() peer_diff = non_zero_range(getValue, getValue.shift(drift)).abs() peer_diff_sum = peer_diff.rolling(length).sum() er = abs_diff / peer_diff_sum x = er * (fr - sr) + sr sc = x * x m = getValue.size result = [npNaN for _ in range(0, length - 1)] + [0] for i in range(length, m): result.append(sc.iloc[i] * getValue.iloc[i] + (1 - sc.iloc[i]) * result[i - 1]) kama = Series(result, index=getValue.index) # Offset if offset != 0: kama = kama.shift(offset) # Handle fills if "fillna" in kwargs: kama.fillna(kwargs["fillna"], inplace=True) if "fill_method" in kwargs: kama.fillna(method=kwargs["fill_method"], inplace=True) # Name & Category kama.name = f"KAMA_{length}_{fast}_{slow}" kama.category = "overlap" return kama # İstediğimiz Kama limitleri KAMA_1_value = 200 KAMA_2_value = 20 # İstediğimiz HO Limitleri HO_data = 30 # Sayfaya açılacak ekranda label2larda şık göürnsün KAMA_data_label = f"{KAMA_1_value},2,30" KAMA_fast_label = f"{KAMA_2_value},2,30" HO_label = f"HO: {HO_data} data" # veriyi barındıran excel uniformity_data_file = "ExcelDoc.xlsx" # excelden gelen veriyi pandas aracılığı ile dataset oluşturulmasında kullanıyoruz all_dataset = pd.read_excel(uniformity_data_file, 'Sheet1') # örnek olsun diye excelden gelen kolnlarda filtrasyon denemeleri all_dataset = all_dataset[all_dataset.FILTRE_KOLON_2 <= 10] all_dataset = all_dataset[all_dataset.FILTRE_KOLON_3 == 'DENEME'] # KAMA değerlerini dataset üzerinde yeni kolonlara hesaplıyoruz calcKAMA_1_Value = kama(all_dataset['KOLON_1'], KAMA_1_value, 2, 30, 1, 0) calcKAMA_2_Value = kama(all_dataset['KOLON_1'], KAMA_2_value, 2, 30, 1, 0) all_dataset['calcKAMA_1_Value'] = calcKAMA_1_Value all_dataset['calcKAMA_2_Value'] = calcKAMA_2_Value # Hareketli ortalamayı da hesaplıyoruz - Hazır elimiz değmişken all_dataset['HO'] = all_dataset.KOLON_1.rolling(HO_data).mean() # Son 3000 data desek? all_dataset = all_dataset.tail(3000) # Matplotlib oluşturmaya başladık plt.figure(figsize=(12, 6)) plt.subplots_adjust(left=0.05, right=0.99, bottom=0.05, top=0.99, wspace=0.2, hspace=0.2) # ve seaborn ile show başlıyor :) sns.set() # sns.set_theme(style="whitegrid", palette="pastel") sns.lineplot(data=all_dataset, x='Tarih', y='kolon_1', color='limegreen', label='Güncel Data', linewidth=0.3) sns.lineplot(data=all_dataset, x='Tarih', y='calcKAMA_2_Value', color='red', label=KAMA_data_label, linewidth=.6) sns.lineplot(data=all_dataset, x='Tarih', y='calcKAMA_2_Value', color='blue', label=KAMA_fast_label, linewidth=.6) sns.lineplot(data=all_dataset, x='Tarih', y='HO', color='gray', label=HO_label, linewidth=1.2) sns.lineplot(data=all_dataset, x='Tarih', y=100, color='maroon', label='LIMIT', linewidth=1.5) plt.show()
Bu üstte paylaştığım en basic haliyle kodun mevcut herhangi bir veriseti ile çalışabilmesi için. Ben bir arayüzle tüm değişkenlerin kullanıcı tarafından girilebilen ve GUI olan başka bir versiyon da yazdım, onu da sorunsuzca kullanmaktayım.
Ekran görüntüleri de şöyle;
Teknik olarak faydalandığım bazı siteler;
- https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work
- https://school.stockcharts.com/doku.php?id=technical_indicators:kaufman_s_adaptive_moving_average
- https://www.tradingview.com/scripts/kama/
- https://en.wikipedia.org/wiki/Moving_average
Bir soru yada sorununuz olursa ulaşabilirsiniz : twitter.com/hmustak
Hakan Müştak @2022-11
Bir yanıt yazın