scalperBot / core /strategy.py
nexusbert's picture
Upload 36 files
96e0cc2 verified
import pandas as pd
import numpy as np
import logging
from typing import Dict, List, Optional, Tuple, Any
from core.indicators import TechnicalIndicators
from core.data_engine import DataEngine
import yaml
logger = logging.getLogger(__name__)
class ScalpingStrategy:
def __init__(self, data_engine: DataEngine):
self.data_engine = data_engine
self.settings = yaml.safe_load(open("config/settings.yaml"))
self.ema_fast_period = self.settings["strategy"]["ema_fast"]
self.ema_slow_period = self.settings["strategy"]["ema_slow"]
self.rsi_period = self.settings["strategy"]["rsi_period"]
self.strategy_weights = {
'ema_momentum': 0.4,
'breakout': 0.35,
'pullback': 0.25
}
self.min_confidence = 0.6
def generate_signal(self, symbol: str, interval: str = "1") -> Tuple[str, float, float]:
try:
current_price = self.data_engine.get_prices(symbol, limit=1)
if not current_price:
return "NEUTRAL", 0.0, 0.0
current_price = current_price[-1]
ema_signal, ema_conf = self._ema_momentum_strategy(symbol, interval)
breakout_signal, breakout_conf = self._breakout_strategy(symbol, interval)
pullback_signal, pullback_conf = self._pullback_strategy(symbol, interval)
buy_signals = []
sell_signals = []
if ema_signal == "BUY":
buy_signals.append(ema_conf * self.strategy_weights['ema_momentum'])
elif ema_signal == "SELL":
sell_signals.append(ema_conf * self.strategy_weights['ema_momentum'])
if breakout_signal == "BUY":
buy_signals.append(breakout_conf * self.strategy_weights['breakout'])
elif breakout_signal == "SELL":
sell_signals.append(breakout_conf * self.strategy_weights['breakout'])
if pullback_signal == "BUY":
buy_signals.append(pullback_conf * self.strategy_weights['pullback'])
elif pullback_signal == "SELL":
sell_signals.append(pullback_conf * self.strategy_weights['pullback'])
buy_strength = sum(buy_signals) if buy_signals else 0.0
sell_strength = sum(sell_signals) if sell_signals else 0.0
if buy_strength > self.min_confidence and buy_strength > sell_strength:
final_confidence = min(buy_strength, 1.0)
return "BUY", final_confidence, current_price
elif sell_strength > self.min_confidence and sell_strength > buy_strength:
final_confidence = min(sell_strength, 1.0)
return "SELL", final_confidence, current_price
else:
return "NEUTRAL", 0.0, current_price
except Exception as e:
logger.error(f"Error generating signal for {symbol}: {e}")
return "NEUTRAL", 0.0, 0.0
def _ema_momentum_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
try:
df = self.data_engine.get_candles(symbol, interval, limit=50)
if df.empty or len(df) < self.ema_slow_period + 5:
return "NEUTRAL", 0.0
ema_fast = self.data_engine.calculate_ema(symbol, interval, self.ema_fast_period)
ema_slow = self.data_engine.calculate_ema(symbol, interval, self.ema_slow_period)
rsi = self.data_engine.calculate_rsi(symbol, interval, self.rsi_period)
if ema_fast is None or ema_slow is None or rsi is None:
return "NEUTRAL", 0.0
ema_fast_prev = df['close'].ewm(span=self.ema_fast_period, adjust=False).mean().iloc[-2]
ema_slow_prev = df['close'].ewm(span=self.ema_slow_period, adjust=False).mean().iloc[-2]
crossover_up = ema_fast_prev <= ema_slow_prev and ema_fast > ema_slow
crossover_down = ema_fast_prev >= ema_slow_prev and ema_fast < ema_slow
rsi_oversold = rsi < 35
rsi_overbought = rsi > 65
orderbook_imbalance = self.data_engine.get_orderbook_imbalance(symbol)
confidence = 0.0
signal = "NEUTRAL"
if crossover_up and rsi_oversold and orderbook_imbalance > 0.1:
confidence = 0.8
signal = "BUY"
elif crossover_down and rsi_overbought and orderbook_imbalance < -0.1:
confidence = 0.8
signal = "SELL"
return signal, confidence
except Exception as e:
logger.error(f"EMA momentum strategy error for {symbol}: {e}")
return "NEUTRAL", 0.0
def _breakout_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
try:
df = self.data_engine.get_candles(symbol, interval, limit=20)
if df.empty or len(df) < 10:
return "NEUTRAL", 0.0
volume_spike = self.data_engine.detect_volume_spike(symbol, interval, threshold=1.8)
price_change_rate = self.data_engine.get_price_change_rate(symbol, periods=3)
spread = self.data_engine.get_spread(symbol)
orderbook_imbalance = self.data_engine.get_orderbook_imbalance(symbol)
recent_high = df['high'].tail(5).max()
recent_low = df['low'].tail(5).min()
current_price = df['close'].iloc[-1]
breakout_up = current_price > recent_high * 1.001
breakout_down = current_price < recent_low * 0.999
confidence = 0.0
signal = "NEUTRAL"
if breakout_up and volume_spike and price_change_rate > 0.002 and orderbook_imbalance > 0.15:
confidence = 0.75
signal = "BUY"
elif breakout_down and volume_spike and price_change_rate < -0.002 and orderbook_imbalance < -0.15:
confidence = 0.75
signal = "SELL"
return signal, confidence
except Exception as e:
logger.error(f"Breakout strategy error for {symbol}: {e}")
return "NEUTRAL", 0.0
def _pullback_strategy(self, symbol: str, interval: str) -> Tuple[str, float]:
try:
df = self.data_engine.get_candles(symbol, interval, limit=30)
if df.empty or len(df) < 20:
return "NEUTRAL", 0.0
ema_21 = df['close'].ewm(span=21, adjust=False).mean()
ema_slope = ema_21.diff().iloc[-1]
uptrend = ema_slope > 0
downtrend = ema_slope < 0
ema_9 = df['close'].ewm(span=9, adjust=False).mean().iloc[-1]
current_price = df['close'].iloc[-1]
price_to_ema_ratio = current_price / ema_9
recent_volume = df['volume'].tail(5).mean()
previous_volume = df['volume'].tail(10).head(5).mean()
volume_trend = recent_volume / previous_volume if previous_volume > 0 else 1.0
pullback_up = uptrend and price_to_ema_ratio < 0.995
pullback_down = downtrend and price_to_ema_ratio > 1.005
volume_decrease_on_pullback = volume_trend < 0.8
volume_increase_on_continuation = volume_trend > 1.2
confidence = 0.0
signal = "NEUTRAL"
if pullback_up and volume_decrease_on_pullback:
if volume_increase_on_continuation and current_price > ema_9:
confidence = 0.7
signal = "BUY"
elif pullback_down and volume_decrease_on_pullback:
if volume_increase_on_continuation and current_price < ema_9:
confidence = 0.7
signal = "SELL"
return signal, confidence
except Exception as e:
logger.error(f"Pullback strategy error for {symbol}: {e}")
return "NEUTRAL", 0.0
def get_strategy_status(self, symbol: str) -> Dict[str, Any]:
try:
status = {
'symbol': symbol,
'timestamp': pd.Timestamp.now(),
'strategies': {}
}
ema_signal, ema_conf = self._ema_momentum_strategy(symbol)
breakout_signal, breakout_conf = self._breakout_strategy(symbol)
pullback_signal, pullback_conf = self._pullback_strategy(symbol)
status['strategies'] = {
'ema_momentum': {
'signal': ema_signal,
'confidence': ema_conf
},
'breakout': {
'signal': breakout_signal,
'confidence': breakout_conf
},
'pullback': {
'signal': pullback_signal,
'confidence': pullback_conf
}
}
current_price = self.data_engine.get_prices(symbol, limit=1)
status['current_price'] = current_price[-1] if current_price else None
ema_fast = self.data_engine.calculate_ema(symbol, "1", self.ema_fast_period)
ema_slow = self.data_engine.calculate_ema(symbol, "1", self.ema_slow_period)
rsi = self.data_engine.calculate_rsi(symbol, "1", self.rsi_period)
status['indicators'] = {
'ema_fast': ema_fast,
'ema_slow': ema_slow,
'rsi': rsi
}
return status
except Exception as e:
logger.error(f"Error getting strategy status for {symbol}: {e}")
return {'error': str(e)}