borsa / analysis /indicators.py
onerozbey
Add missing API endpoints: stocks, movers, scanner, backtest, sentiment, news
32f16c2
import pandas as pd
import numpy as np
import streamlit as st
def calculate_rsi(data, window=14):
"""RSI (Relatif Güç İndeksi) hesaplar"""
delta = data.diff()
up = delta.clip(lower=0)
down = -1 * delta.clip(upper=0)
ema_up = up.ewm(com=window-1, adjust=False).mean()
ema_down = down.ewm(com=window-1, adjust=False).mean()
rs = ema_up / ema_down
return 100 - (100 / (1 + rs))
def calculate_sma(data, window):
"""Basit Hareketli Ortalama hesaplar"""
return data.rolling(window=window).mean()
def calculate_ema(data, window):
"""Üssel Hareketli Ortalama hesaplar"""
return data.ewm(span=window, adjust=False).mean()
def calculate_macd(data):
"""MACD (Hareketli Ortalama Yakınsama/Iraksama) hesaplar"""
exp1 = data.ewm(span=12, adjust=False).mean()
exp2 = data.ewm(span=26, adjust=False).mean()
macd = exp1 - exp2
signal = macd.ewm(span=9, adjust=False).mean()
histogram = macd - signal
return macd, signal, histogram
def calculate_bollinger_bands(data, window=20, num_std=2):
"""Bollinger Bantları hesaplar"""
sma = data.rolling(window=window).mean()
std = data.rolling(window=window).std()
upper_band = sma + (std * num_std)
lower_band = sma - (std * num_std)
return upper_band, sma, lower_band
def calculate_stochastic(df, k_period=14, d_period=3):
"""Stokastik Osilatör hesaplar"""
low_min = df['Low'].rolling(window=k_period).min()
high_max = df['High'].rolling(window=k_period).max()
k = 100 * ((df['Close'] - low_min) / (high_max - low_min))
d = k.rolling(window=d_period).mean()
return k, d
def calculate_adx(df, window=14):
"""ADX (Ortalama Yön İndeksi) hesaplar"""
df = df.copy()
df['H-L'] = df['High'] - df['Low']
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1)
df['DMplus'] = np.where((df['High'] - df['High'].shift(1)) > (df['Low'].shift(1) - df['Low']),
df['High'] - df['High'].shift(1), 0)
df['DMminus'] = np.where((df['Low'].shift(1) - df['Low']) > (df['High'] - df['High'].shift(1)),
df['Low'].shift(1) - df['Low'], 0)
df['TRn'] = df['TR'].rolling(window).mean()
df['DMplusN'] = df['DMplus'].rolling(window).mean()
df['DMminusN'] = df['DMminus'].rolling(window).mean()
df['DIplus'] = 100 * (df['DMplusN'] / df['TRn'])
df['DIminus'] = 100 * (df['DMminusN'] / df['TRn'])
df['DIdiff'] = abs(df['DIplus'] - df['DIminus'])
df['DIsum'] = df['DIplus'] + df['DIminus']
df['DX'] = 100 * (df['DIdiff'] / df['DIsum'])
adx = df['DX'].rolling(window).mean()
return adx, df['DIplus'], df['DIminus']
def calculate_williams_r(df, window=14):
"""Williams %R hesaplar"""
highest_high = df['High'].rolling(window=window).max()
lowest_low = df['Low'].rolling(window=window).min()
wr = -100 * ((highest_high - df['Close']) / (highest_high - lowest_low))
return wr
def calculate_cci(df, window=14):
"""CCI (Emtia Kanal İndeksi) hesaplar"""
tp = (df['High'] + df['Low'] + df['Close']) / 3
ma = tp.rolling(window=window).mean()
md = (tp - ma).abs().rolling(window=window).mean()
cci = (tp - ma) / (0.015 * md)
return cci
def calculate_atr(df, window=14):
"""ATR (Ortalama Gerçek Aralık) hesaplar"""
high_low = df['High'] - df['Low']
high_close = np.abs(df['High'] - df['Close'].shift())
low_close = np.abs(df['Low'] - df['Close'].shift())
ranges = pd.concat([high_low, high_close, low_close], axis=1)
true_range = np.max(ranges, axis=1)
atr = true_range.rolling(window=window).mean()
return atr
def calculate_highs_lows(df, window=14):
"""Yüksek ve Düşük fiyat sinyallerini hesaplar"""
df['highest_high'] = df['High'].rolling(window=window).max()
df['lowest_low'] = df['Low'].rolling(window=window).min()
return df['highest_high'], df['lowest_low']
def calculate_ultimate_oscillator(df, short=7, medium=14, long=28):
"""Ultimate Oscillator hesaplar"""
df = df.copy()
df['prior_close'] = df['Close'].shift(1)
df['true_high'] = df[['High', 'prior_close']].max(axis=1)
df['true_low'] = df[['Low', 'prior_close']].min(axis=1)
df['buying_pressure'] = df['Close'] - df['true_low']
df['true_range'] = df['true_high'] - df['true_low']
df['avg7'] = df['buying_pressure'].rolling(window=short).sum() / df['true_range'].rolling(window=short).sum()
df['avg14'] = df['buying_pressure'].rolling(window=medium).sum() / df['true_range'].rolling(window=medium).sum()
df['avg28'] = df['buying_pressure'].rolling(window=long).sum() / df['true_range'].rolling(window=long).sum()
# (4 * avg7 + 2 * avg14 + avg28) / (4 + 2 + 1)
uo = 100 * (4 * df['avg7'] + 2 * df['avg14'] + df['avg28']) / 7
return uo
def calculate_roc(df, window=14):
"""ROC (Değişim Oranı) hesaplar"""
if isinstance(df, pd.Series):
roc = ((df - df.shift(window)) / df.shift(window)) * 100
else:
roc = ((df['Close'] - df['Close'].shift(window)) / df['Close'].shift(window)) * 100
return roc
def calculate_bull_bear_power(df, window=13):
"""Bull/Bear Power göstergesini hesaplar"""
ema = df['Close'].ewm(span=window, adjust=False).mean()
bull_power = df['High'] - ema
bear_power = df['Low'] - ema
return bull_power, bear_power
def calculate_stoch_rsi(df, window=14, smooth_k=3, smooth_d=3):
"""Stochastic RSI hesaplar"""
rsi = calculate_rsi(df['Close'], window)
stoch_rsi = (rsi - rsi.rolling(window).min()) / (rsi.rolling(window).max() - rsi.rolling(window).min())
k = stoch_rsi.rolling(window=smooth_k).mean()
d = k.rolling(window=smooth_d).mean()
return k, d
def calculate_indicators(df):
"""Tüm teknik göstergeleri hesaplar"""
df = df.copy()
# Hareketli Ortalamalar
df['SMA5'] = calculate_sma(df['Close'], 5)
df['SMA10'] = calculate_sma(df['Close'], 10)
df['SMA20'] = calculate_sma(df['Close'], 20)
df['SMA50'] = calculate_sma(df['Close'], 50)
df['SMA100'] = calculate_sma(df['Close'], 100)
df['SMA200'] = calculate_sma(df['Close'], 200)
df['EMA5'] = calculate_ema(df['Close'], 5)
df['EMA10'] = calculate_ema(df['Close'], 10)
df['EMA20'] = calculate_ema(df['Close'], 20)
df['EMA50'] = calculate_ema(df['Close'], 50)
df['EMA100'] = calculate_ema(df['Close'], 100)
df['EMA200'] = calculate_ema(df['Close'], 200)
# Osilatörler
df['RSI'] = calculate_rsi(df['Close'])
macd, signal, hist = calculate_macd(df['Close'])
df['MACD'] = macd
df['MACD_Signal'] = signal
df['MACD_Hist'] = hist
# Bollinger Bantları
df['Upper_Band'], df['Middle_Band'], df['Lower_Band'] = calculate_bollinger_bands(df['Close'])
# Momentum Göstergeleri
df['ROC'] = calculate_roc(df['Close'])
df['Williams_%R'] = calculate_williams_r(df)
k, d = calculate_stochastic(df)
df['Stoch_%K'] = k
df['Stoch_%D'] = d
# --- YENİ: Ekstra Teknik Göstergeler ---
df['CCI'] = calculate_cci(df)
df['Ultimate_Osc'] = calculate_ultimate_oscillator(df)
df['StochRSI_K'], df['StochRSI_D'] = calculate_stoch_rsi(df)
df['Bull_Power'], df['Bear_Power'] = calculate_bull_bear_power(df)
# Trend Göstergeleri
adx, plus_di, minus_di = calculate_adx(df)
df['ADX'] = adx
df['Plus_DI'] = plus_di
df['Minus_DI'] = minus_di
# Volatilite Göstergeleri
df['ATR'] = calculate_atr(df)
# Hacim Göstergeleri
if 'Volume' in df.columns:
df['Volume_SMA20'] = calculate_sma(df['Volume'], 20)
for window in [5, 10, 20]:
df[f'Volume_rolling{window}_mean'] = df['Volume'].rolling(window).mean()
df[f'Volume_rolling{window}_std'] = df['Volume'].rolling(window).std()
# --- YENİ: Lagged ve Rolling Özellikler ---
for lag in [1, 3, 5, 10]:
df[f'Close_lag{lag}'] = df['Close'].shift(lag)
df[f'RSI_lag{lag}'] = df['RSI'].shift(lag)
df[f'Volume_lag{lag}'] = df['Volume'].shift(lag) if 'Volume' in df.columns else None
for window in [5, 10]:
df[f'Close_rolling{window}_mean'] = df['Close'].rolling(window).mean()
df[f'Close_rolling{window}_std'] = df['Close'].rolling(window).std()
df[f'Close_rolling{window}_min'] = df['Close'].rolling(window).min()
df[f'Close_rolling{window}_max'] = df['Close'].rolling(window).max()
if 'Volume' in df.columns:
df[f'Volume_rolling{window}_mean'] = df['Volume'].rolling(window).mean()
df[f'Volume_rolling{window}_std'] = df['Volume'].rolling(window).std()
# --- SON ---
return df
def get_signals(df):
"""Teknik analiz sinyallerini hesaplar"""
signals = pd.DataFrame(index=df.index)
# Temel Sinyaller
signals['Price'] = df['Close']
signals['Price_Change'] = df['Close'].pct_change() * 100
# Hareketli Ortalama Sinyalleri
signals['SMA5_Signal'] = np.where(df['Close'] > df['SMA5'], 1, -1)
signals['SMA10_Signal'] = np.where(df['Close'] > df['SMA10'], 1, -1)
signals['SMA20_Signal'] = np.where(df['Close'] > df['SMA20'], 1, -1)
signals['SMA50_Signal'] = np.where(df['Close'] > df['SMA50'], 1, -1)
signals['SMA100_Signal'] = np.where(df['Close'] > df['SMA100'], 1, -1)
signals['SMA200_Signal'] = np.where(df['Close'] > df['SMA200'], 1, -1)
signals['EMA5_Signal'] = np.where(df['Close'] > df['EMA5'], 1, -1)
signals['EMA10_Signal'] = np.where(df['Close'] > df['EMA10'], 1, -1)
signals['EMA20_Signal'] = np.where(df['Close'] > df['EMA20'], 1, -1)
signals['EMA50_Signal'] = np.where(df['Close'] > df['EMA50'], 1, -1)
signals['EMA100_Signal'] = np.where(df['Close'] > df['EMA100'], 1, -1)
signals['EMA200_Signal'] = np.where(df['Close'] > df['EMA200'], 1, -1)
# MACD Sinyali
signals['MACD_Signal'] = np.where(df['MACD'] > df['MACD_Signal'], 1, -1)
signals['MACD_Crossover'] = np.where(
(df['MACD'] > df['MACD_Signal']) & (df['MACD'].shift(1) <= df['MACD_Signal'].shift(1)), 1,
np.where((df['MACD'] < df['MACD_Signal']) & (df['MACD'].shift(1) >= df['MACD_Signal'].shift(1)), -1, 0)
)
# RSI Sinyali
signals['RSI_Overbought'] = np.where(df['RSI'] > 70, -1, 0)
signals['RSI_Oversold'] = np.where(df['RSI'] < 30, 1, 0)
signals['RSI_Signal'] = signals['RSI_Overbought'] + signals['RSI_Oversold']
# Bollinger Bant Sinyalleri
signals['BB_Upper'] = np.where(df['Close'] > df['Upper_Band'], -1, 0)
signals['BB_Lower'] = np.where(df['Close'] < df['Lower_Band'], 1, 0)
signals['BB_Signal'] = signals['BB_Upper'] + signals['BB_Lower']
# Stokastik Sinyaller
signals['Stoch_Overbought'] = np.where((df['Stoch_%K'] > 80) & (df['Stoch_%D'] > 80), -1, 0)
signals['Stoch_Oversold'] = np.where((df['Stoch_%K'] < 20) & (df['Stoch_%D'] < 20), 1, 0)
signals['Stoch_Signal'] = signals['Stoch_Overbought'] + signals['Stoch_Oversold']
# ADX Sinyali
signals['ADX_Trend_Strength'] = np.where(df['ADX'] > 25, 1, 0)
signals['ADX_Direction'] = np.where(df['Plus_DI'] > df['Minus_DI'], 1, -1)
signals['ADX_Signal'] = signals['ADX_Trend_Strength'] * signals['ADX_Direction']
# Williams %R
signals['Williams_%R_Overbought'] = np.where(df['Williams_%R'] > -20, -1, 0)
signals['Williams_%R_Oversold'] = np.where(df['Williams_%R'] < -80, 1, 0)
signals['Williams_%R_Signal'] = signals['Williams_%R_Overbought'] + signals['Williams_%R_Oversold']
# Toplam Sinyal
signal_cols = [col for col in signals.columns if col.endswith('_Signal')]
signals['Total_MA_Signal'] = signals[[col for col in signal_cols if 'SMA' in col or 'EMA' in col]].sum(axis=1)
signals['Total_Oscillator_Signal'] = signals[[col for col in signal_cols if 'RSI' in col or 'Stoch' in col or 'MACD' in col or 'Williams' in col]].sum(axis=1)
signals['Total_Signal'] = signals['Total_MA_Signal'] + signals['Total_Oscillator_Signal']
return signals