Python ile Teknik İndikatör Hesaplama — RSI, MACD, Bollinger, ATR
En yaygın dört teknik indikatörü ta-lib olmadan, sıfırdan Python'da hesaplıyoruz. Her indikatörün BIST'e özgü parametre önerileri ve görselleştirme dahil.
Yıllarca hazır kütüphanelerin ürettiği indikatör değerlerine güvendim. Bir gün aynı hisse için farklı iki platformda RSI değerlerinin örtüşmediğini fark ettim. O günden sonra her indikatörü bir kez sıfırdan yazmayı alışkanlık haline getirdim. Neyi hesapladığını bilmeden kullanmak, kör uçmak gibi.
Neden Sıfırdan?
ta-lib gibi kütüphaneler hızlı ama kurulumu zahmetli, bazı ortamlarda çalışmıyor. Daha önemlisi: kara kutu gibi kullanılıyor. RSI hesaplamasının iki farklı smoothing yöntemi var — Wilder's ve EMA bazlı. Hangisini kullandığınızı bilmeden sonuçları karşılaştıramazsınız.
Adım 1: Veri Hazırlığı
!pip install yfinance --quiet
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
ticker = "GARAN.IS"
df = yf.download(ticker, start="2022-01-01", end="2025-01-01", progress=False)
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.droplevel(1)
df = df[df["Volume"] > 0].ffill().dropna()
df.index = pd.to_datetime(df.index)
print(f"{ticker} | {len(df)} gün | {df.index[0].date()} → {df.index[-1].date()}")
Adım 2: RSI — Göreceli Güç Endeksi
RSI, belirli bir penceredeki yükseliş ve düşüş güçlerini karşılaştırır.
def hesapla_rsi(close, period=14):
delta = close.diff()
kazanc = delta.clip(lower=0)
kayip = (-delta).clip(lower=0)
ort_kazanc = kazanc.ewm(alpha=1/period, adjust=False).mean()
ort_kayip = kayip.ewm(alpha=1/period, adjust=False).mean()
rs = ort_kazanc / ort_kayip
rsi = 100 - (100 / (1 + rs))
return rsi
df["RSI"] = hesapla_rsi(df["Close"], period=14)
print(df[["Close", "RSI"]].tail(5).round(2))
Adım 3: MACD — Hareketli Ortalama Yakınsama/Iraksama
MACD üç bileşenden oluşur: MACD çizgisi, sinyal çizgisi ve histogram.
def hesapla_macd(close, hizli=12, yavas=26, sinyal=9):
ema_hizli = close.ewm(span=hizli, adjust=False).mean()
ema_yavas = close.ewm(span=yavas, adjust=False).mean()
macd_cizgi = ema_hizli - ema_yavas
sinyal_cizgi = macd_cizgi.ewm(span=sinyal, adjust=False).mean()
histogram = macd_cizgi - sinyal_cizgi
return macd_cizgi, sinyal_cizgi, histogram
df["MACD"], df["MACDSinyal"], df["MACDHist"] = hesapla_macd(df["Close"])
Adım 4: Bollinger Bands
Fiyatın standart sapma bazlı bantların dışına çıkmasını ölçer.
def hesapla_bollinger(close, period=20, std_carpan=2):
orta = close.rolling(period).mean()
std = close.rolling(period).std()
ust = orta + std_carpan * std
alt = orta - std_carpan * std
b_yuzdesi = (close - alt) / (ust - alt)
bant_genisligi = (ust - alt) / orta
return orta, ust, alt, b_yuzdesi, bant_genisligi
df["BB_Orta"], df["BB_Ust"], df["BB_Alt"], df["BB_B"], df["BB_Genislik"] = \
hesapla_bollinger(df["Close"])
Adım 5: ATR — Ortalama Gerçek Aralık
ATR volatiliteyi ölçer. Süpertrend ve dinamik stop-loss hesaplamalarının temel taşı.
def hesapla_atr(high, low, close, period=14):
tr1 = high - low
tr2 = (high - close.shift(1)).abs()
tr3 = (low - close.shift(1)).abs()
true_range = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
atr = true_range.ewm(alpha=1/period, adjust=False).mean()
return atr
df["ATR"] = hesapla_atr(df["High"], df["Low"], df["Close"], period=14)
df["ATR_Pct"] = df["ATR"] / df["Close"] * 100
Adım 6: Dört İndikatörü Tek Grafik
fig = plt.figure(figsize=(14, 14))
gs = gridspec.GridSpec(4, 1, height_ratios=[3, 1, 1, 1], hspace=0.4)
son_300 = df.tail(300)
ax1 = fig.add_subplot(gs[0])
ax1.plot(son_300["Close"], color="black", linewidth=0.9, label="Kapanış")
ax1.plot(son_300["BB_Orta"], color="blue", linewidth=0.8, linestyle="--", label="BB Orta")
ax1.plot(son_300["BB_Ust"], color="gray", linewidth=0.7)
ax1.plot(son_300["BB_Alt"], color="gray", linewidth=0.7)
ax1.fill_between(son_300.index, son_300["BB_Alt"], son_300["BB_Ust"], alpha=0.05, color="blue")
ax1.set_title(f"{ticker} — RSI | MACD | Bollinger | ATR")
ax1.legend(fontsize=8); ax1.grid(alpha=0.3)
ax2 = fig.add_subplot(gs[1])
ax2.plot(son_300["RSI"], color="purple", linewidth=0.9)
ax2.axhline(70, color="red", linestyle="--", alpha=0.6)
ax2.axhline(30, color="green", linestyle="--", alpha=0.6)
ax2.set_ylabel("RSI"); ax2.set_ylim(0, 100); ax2.grid(alpha=0.3)
ax3 = fig.add_subplot(gs[2])
ax3.plot(son_300["MACD"], color="blue", linewidth=0.9, label="MACD")
ax3.plot(son_300["MACDSinyal"], color="orange", linewidth=0.9, label="Sinyal")
renkler = ["green" if v >= 0 else "red" for v in son_300["MACDHist"]]
ax3.bar(son_300.index, son_300["MACDHist"], color=renkler, alpha=0.6)
ax3.set_ylabel("MACD"); ax3.legend(fontsize=7); ax3.grid(alpha=0.3)
ax4 = fig.add_subplot(gs[3])
ax4.plot(son_300["ATR_Pct"], color="darkorange", linewidth=0.9)
ax4.fill_between(son_300.index, 0, son_300["ATR_Pct"], alpha=0.2, color="orange")
ax4.set_ylabel("ATR %"); ax4.grid(alpha=0.3)
plt.tight_layout()
plt.show()
Sonuç
- RSI, MACD, Bollinger ve ATR'yi sıfırdan yazmak bir kez bile olsa yapılması gereken bir alıştırma.
- BIST'te parametre seçimi önemli: yüksek volatilite dönemlerinde ATR period'u ve Bollinger std çarpanını artırmak daha sağlıklı sinyal üretiyor.
- Bu indikatörlerin sınırı şu: hepsi gecikmeli — geçmiş fiyatları kullanarak hesaplanıyor.
- Bir sonraki adım: bu indikatörleri Plotly ile interaktif grafiklere dönüştürmek.
Bu yazıdaki kodlar eğitim amaçlıdır; yatırım tavsiyesi değildir.