feat: Add SunnyBands indicator implementation with ATR and signal generation
This commit is contained in:
parent
c3f8d7ce80
commit
fc7a6e7343
@ -0,0 +1 @@
|
|||||||
|
# Initialize indicators package
|
||||||
83
src/indicators/sunny_bands.py
Normal file
83
src/indicators/sunny_bands.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
class SunnyBands:
|
||||||
|
def __init__(self, length: int = 50, atr_multiplier: float = 1.5, smooth_factor: int = 2):
|
||||||
|
"""
|
||||||
|
Initialize SunnyBands indicator
|
||||||
|
|
||||||
|
Args:
|
||||||
|
length (int): DMA Length (default: 50)
|
||||||
|
atr_multiplier (float): ATR Multiplier (default: 1.5)
|
||||||
|
smooth_factor (int): Smoothing Factor (default: 2)
|
||||||
|
"""
|
||||||
|
self.length = length
|
||||||
|
self.atr_multiplier = atr_multiplier
|
||||||
|
self.smooth_factor = smooth_factor
|
||||||
|
|
||||||
|
def calculate_atr(self, high: pd.Series, low: pd.Series, close: pd.Series) -> pd.Series:
|
||||||
|
"""Calculate Average True Range"""
|
||||||
|
tr1 = high - low
|
||||||
|
tr2 = abs(high - close.shift(1))
|
||||||
|
tr3 = abs(low - close.shift(1))
|
||||||
|
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||||
|
return tr.rolling(window=self.length).mean()
|
||||||
|
|
||||||
|
def calculate(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Calculate SunnyBands indicator
|
||||||
|
|
||||||
|
Args:
|
||||||
|
df (pd.DataFrame): DataFrame with 'high', 'low', 'close' columns
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
pd.DataFrame: DataFrame with added columns for DMA and bands
|
||||||
|
"""
|
||||||
|
# Calculate DMA (Double EMA)
|
||||||
|
ema1 = df['close'].ewm(span=self.length, adjust=False).mean()
|
||||||
|
dma = ema1.ewm(span=self.smooth_factor, adjust=False).mean()
|
||||||
|
|
||||||
|
# Calculate ATR
|
||||||
|
atr = self.calculate_atr(df['high'], df['low'], df['close'])
|
||||||
|
|
||||||
|
# Calculate Bands
|
||||||
|
upper_band = dma + (atr * self.atr_multiplier)
|
||||||
|
lower_band = dma - (atr * self.atr_multiplier)
|
||||||
|
|
||||||
|
# Generate signals
|
||||||
|
bullish = (df['close'] > lower_band) & (df['close'].shift(1) <= lower_band)
|
||||||
|
bearish = (df['close'] < upper_band) & (df['close'].shift(1) >= upper_band)
|
||||||
|
|
||||||
|
# Add results to DataFrame
|
||||||
|
results = pd.DataFrame({
|
||||||
|
'dma': dma,
|
||||||
|
'upper_band': upper_band,
|
||||||
|
'lower_band': lower_band,
|
||||||
|
'bullish_signal': bullish,
|
||||||
|
'bearish_signal': bearish
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_signals(self, df: pd.DataFrame) -> dict:
|
||||||
|
"""
|
||||||
|
Get the current trading signals based on SunnyBands
|
||||||
|
|
||||||
|
Args:
|
||||||
|
df (pd.DataFrame): DataFrame with price data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Dictionary containing current signals and band values
|
||||||
|
"""
|
||||||
|
results = self.calculate(df)
|
||||||
|
|
||||||
|
# Get latest values
|
||||||
|
current = results.iloc[-1]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'dma': current['dma'],
|
||||||
|
'upper_band': current['upper_band'],
|
||||||
|
'lower_band': current['lower_band'],
|
||||||
|
'is_bullish': current['bullish_signal'],
|
||||||
|
'is_bearish': current['bearish_signal']
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user