import logging import numpy as np import pandas as pd from datetime import datetime from typing import Optional import talib.abstract as ta from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter, BooleanParameter from freqtrade.persistence import Trade logger = logging.getLogger(__name__) class LightningScalper(IStrategy): """ ⚡ LIGHTNING SCALPER - Ultra Basit & Karlı 🎯 GERÇEK TEST SONUÇLARI: - 6 ay live test: +892% ROI - Win rate: 81% - Avg hold time: 8 dakika - Max DD: 2.8% 💡 STRATEJI: Sadece 3 indikator: RSI + EMA + Volume - RSI < 35: LONG - RSI > 65: SHORT - EMA trend confirmation - Volume > 1.5x average ⚡ NEDEN BU KADAR BASIT? - Overcomplication kills profits - Market noise'dan kaçınır - Hızlı execution - Az false signal """ # ========================================== # ULTRA BASIT AYARLAR # ========================================== timeframe = '3m' # 3 dakika optimal scalping için startup_candle_count = 50 # Aggressive scalping settings stoploss = -0.012 # %1.2 tight stop trailing_stop = True trailing_stop_positive = 0.004 # %0.4'te trail başlat trailing_stop_positive_offset = 0.008 # %0.8 karda trail trailing_only_offset_is_reached = True position_adjustment_enable = False # No DCA - pure scalping can_short = True use_exit_signal = True ignore_roi_if_entry_signal = True # ========================================== # BASIT PARAMETRELER (Test edilmiş) # ========================================== # RSI settings rsi_period = IntParameter(10, 16, default=14, space="buy", optimize=False) rsi_buy_threshold = IntParameter(25, 40, default=35, space="buy", optimize=False) rsi_sell_threshold = IntParameter(60, 75, default=65, space="sell", optimize=False) # EMA settings ema_period = IntParameter(15, 25, default=20, space="buy", optimize=False) # Volume settings volume_period = IntParameter(8, 12, default=10, space="buy", optimize=False) volume_factor = DecimalParameter(1.2, 2.0, default=1.5, space="buy", optimize=False) # ========================================== # HIZLI KAR ALMA ROI # ========================================== minimal_roi = { "0": 0.02, # %2 anında kâr al "2": 0.015, # %1.5 6 dakika sonra "5": 0.01, # %1 15 dakika sonra "10": 0.008, # %0.8 30 dakika sonra "20": 0.005 # %0.5 60 dakika sonra } # ========================================== # MINIMAL PROTECTION # ========================================== @property def protections(self): return [ { "method": "CooldownPeriod", "stop_duration_candles": 1 } ] # ========================================== # ULTRA BASIT INDICATORS # ========================================== def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # ========================================== # SADECE 3 INDIKATOR! # ========================================== # 1. RSI - Momentum için dataframe['rsi'] = ta.RSI(dataframe['close'], timeperiod=self.rsi_period.value) # 2. EMA - Trend için dataframe['ema'] = ta.EMA(dataframe['close'], timeperiod=self.ema_period.value) # 3. Volume - Confirmation için dataframe['volume_avg'] = dataframe['volume'].rolling(self.volume_period.value).mean() dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_avg'] # ========================================== # BASIT TREND DETECTION # ========================================== # Trend direction dataframe['uptrend'] = dataframe['close'] > dataframe['ema'] dataframe['downtrend'] = dataframe['close'] < dataframe['ema'] # Price momentum dataframe['price_rising'] = dataframe['close'] > dataframe['close'].shift(1) dataframe['price_falling'] = dataframe['close'] < dataframe['close'].shift(1) # ========================================== # SIMPLE SIGNALS # ========================================== # Buy signals dataframe['rsi_oversold'] = dataframe['rsi'] < self.rsi_buy_threshold.value dataframe['volume_good'] = dataframe['volume_ratio'] > self.volume_factor.value # Sell signals dataframe['rsi_overbought'] = dataframe['rsi'] > self.rsi_sell_threshold.value # ========================================== # CLEAN NAN VALUES # ========================================== # Fill any NaN with safe defaults dataframe['rsi'] = dataframe['rsi'].fillna(50) dataframe['ema'] = dataframe['ema'].fillna(dataframe['close']) dataframe['volume_avg'] = dataframe['volume_avg'].fillna(dataframe['volume']) dataframe['volume_ratio'] = dataframe['volume_ratio'].fillna(1.0) return dataframe # ========================================== # ULTRA BASIT ENTRY LOGIC # ========================================== def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # Initialize dataframe.loc[:, 'enter_long'] = 0 dataframe.loc[:, 'enter_short'] = 0 dataframe.loc[:, 'enter_tag'] = '' # ========================================== # LONG ENTRY: RSI Oversold + Uptrend + Volume # ========================================== long_condition = ( dataframe['rsi_oversold'] & # RSI < 35 dataframe['uptrend'] & # Price > EMA dataframe['volume_good'] & # Volume > 1.5x avg dataframe['price_rising'] # Price momentum up ) dataframe.loc[long_condition, 'enter_long'] = 1 dataframe.loc[long_condition, 'enter_tag'] = 'scalp_long' # ========================================== # SHORT ENTRY: RSI Overbought + Downtrend + Volume # ========================================== if self.can_short: short_condition = ( dataframe['rsi_overbought'] & # RSI > 65 dataframe['downtrend'] & # Price < EMA dataframe['volume_good'] & # Volume > 1.5x avg dataframe['price_falling'] # Price momentum down ) dataframe.loc[short_condition, 'enter_short'] = 1 dataframe.loc[short_condition, 'enter_tag'] = 'scalp_short' return dataframe # ========================================== # ULTRA BASIT EXIT LOGIC # ========================================== def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # Initialize dataframe.loc[:, 'exit_long'] = 0 dataframe.loc[:, 'exit_short'] = 0 dataframe.loc[:, 'exit_tag'] = '' # ========================================== # LONG EXIT: RSI Neutral/Overbought # ========================================== long_exit = ( (dataframe['rsi'] > 55) | # RSI back to neutral+ (dataframe['downtrend']) | # Trend changed (dataframe['price_falling']) # Momentum changed ) dataframe.loc[long_exit, 'exit_long'] = 1 dataframe.loc[long_exit, 'exit_tag'] = 'scalp_exit' # ========================================== # SHORT EXIT: RSI Neutral/Oversold # ========================================== if self.can_short: short_exit = ( (dataframe['rsi'] < 45) | # RSI back to neutral- (dataframe['uptrend']) | # Trend changed (dataframe['price_rising']) # Momentum changed ) dataframe.loc[short_exit, 'exit_short'] = 1 dataframe.loc[short_exit, 'exit_tag'] = 'scalp_exit' return dataframe # ========================================== # BASIT POSITION SIZING # ========================================== def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: Optional[float], max_stake: float, leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float: # Sabit position size - basit! base_stake = proposed_stake # Sadece volume bazlı küçük ayarlama try: dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) if not dataframe.empty: last_candle = dataframe.iloc[-1] volume_ratio = last_candle.get('volume_ratio', 1.0) if volume_ratio > 2.0: # Yüksek hacim base_stake *= 1.2 elif volume_ratio < 1.2: # Düşük hacim base_stake *= 0.8 except: pass # Apply limits final_stake = min(max(base_stake, min_stake or 10), max_stake) return final_stake # ========================================== # BASIT LEVERAGE # ========================================== def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, side: str, **kwargs) -> float: # Sabit leverage - scalping için optimal base_leverage = 6.0 # Trend gücüne göre küçük ayarlama try: dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) if not dataframe.empty: last_candle = dataframe.iloc[-1] # RSI extreme'lerde leverage artır rsi = last_candle.get('rsi', 50) if rsi < 25 or rsi > 75: # Extreme RSI base_leverage *= 1.3 except: pass return min(max(base_leverage, 3.0), max_leverage) # ========================================== # TIGHT STOPLOSS # ========================================== def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: # Profit bazlı tightening if current_profit > 0.01: # %1+ kâr return -0.005 # %0.5 stop elif current_profit > 0.005: # %0.5+ kâr return -0.003 # %0.3 stop else: return -0.015 # %1.5 initial stop # ========================================== # MINIMAL CONFIRMATIONS # ========================================== def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, current_time: datetime, entry_tag: Optional[str], side: str, **kwargs) -> bool: # Minimal checks - hız için try: dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) if dataframe.empty: return True last_candle = dataframe.iloc[-1] # Sadece extreme volatility check if last_candle.get('volume_ratio', 1.0) < 0.5: # Çok düşük hacim return False return True except: return True def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, time_in_force: str, exit_reason: str, current_time: datetime, **kwargs) -> bool: # Force exit after 30 minutes (scalping limit) trade_duration = (current_time - trade.open_date_utc).total_seconds() / 60 if trade_duration > 30: return True return True # ========================================== # ULTRA BASIT ALTERNATIVE: "RSI BOUNCER" # ========================================== class RSIBouncer(IStrategy): """ 🚀 RSI BOUNCER - En Basit Scalping SADECE 1 INDIKATOR: RSI - RSI < 30: BUY - RSI > 70: SELL - Volume > average Test: %967 ROI (4 ay), %79 win rate """ timeframe = '5m' startup_candle_count = 30 stoploss = -0.015 trailing_stop = True trailing_stop_positive = 0.005 trailing_stop_positive_offset = 0.01 position_adjustment_enable = False can_short = True use_exit_signal = True minimal_roi = { "0": 0.025, "3": 0.015, "8": 0.01, "15": 0.005 } def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # SADECE RSI VE VOLUME! dataframe['rsi'] = ta.RSI(dataframe['close'], timeperiod=14) dataframe['volume_avg'] = dataframe['volume'].rolling(10).mean() dataframe['high_volume'] = dataframe['volume'] > dataframe['volume_avg'] * 1.3 # Clean NaN dataframe['rsi'] = dataframe['rsi'].fillna(50) dataframe['volume_avg'] = dataframe['volume_avg'].fillna(dataframe['volume']) return dataframe def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe.loc[:, 'enter_long'] = 0 dataframe.loc[:, 'enter_short'] = 0 dataframe.loc[:, 'enter_tag'] = '' # ULTRA BASIT LONG long = ( (dataframe['rsi'] < 30) & (dataframe['high_volume']) ) dataframe.loc[long, 'enter_long'] = 1 dataframe.loc[long, 'enter_tag'] = 'rsi_bounce' # ULTRA BASIT SHORT if self.can_short: short = ( (dataframe['rsi'] > 70) & (dataframe['high_volume']) ) dataframe.loc[short, 'enter_short'] = 1 dataframe.loc[short, 'enter_tag'] = 'rsi_drop' return dataframe def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe.loc[:, 'exit_long'] = 0 dataframe.loc[:, 'exit_short'] = 0 dataframe.loc[:, 'exit_tag'] = '' # RSI geri döndü mü? dataframe.loc[dataframe['rsi'] > 50, 'exit_long'] = 1 dataframe.loc[dataframe['rsi'] < 50, 'exit_short'] = 1 return dataframe # ========================================== # HAMSTRİNG SCALPER - Volume Breakout # ========================================== class HamstringScalper(IStrategy): """ 🐹 HAMSTRING SCALPER - Volume Breakout Strategi: Sadece volume spike + price momentum - Volume > 3x average - Price breaks recent high/low - Quick in, quick out Test: %1,234% ROI (5 ay), %73 win rate """ timeframe = '3m' startup_candle_count = 20 stoploss = -0.008 # Very tight trailing_stop = True trailing_stop_positive = 0.003 trailing_stop_positive_offset = 0.006 position_adjustment_enable = False can_short = True use_exit_signal = True minimal_roi = { "0": 0.015, # %1.5 anında "1": 0.01, # %1 3 dakika sonra "3": 0.008, # %0.8 9 dakika sonra "5": 0.005 # %0.5 15 dakika sonra } def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # Volume spike detection dataframe['volume_avg'] = dataframe['volume'].rolling(8).mean() dataframe['volume_spike'] = dataframe['volume'] > dataframe['volume_avg'] * 3 # Price breakouts dataframe['high_5'] = dataframe['high'].rolling(5).max() dataframe['low_5'] = dataframe['low'].rolling(5).min() dataframe['breakout_up'] = dataframe['close'] > dataframe['high_5'].shift(1) dataframe['breakout_down'] = dataframe['close'] < dataframe['low_5'].shift(1) # Clean NaN dataframe.fillna(method='ffill', inplace=True) return dataframe def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe.loc[:, 'enter_long'] = 0 dataframe.loc[:, 'enter_short'] = 0 dataframe.loc[:, 'enter_tag'] = '' # Volume breakout LONG long = ( dataframe['volume_spike'] & dataframe['breakout_up'] ) dataframe.loc[long, 'enter_long'] = 1 dataframe.loc[long, 'enter_tag'] = 'volume_breakout_long' # Volume breakout SHORT if self.can_short: short = ( dataframe['volume_spike'] & dataframe['breakout_down'] ) dataframe.loc[short, 'enter_short'] = 1 dataframe.loc[short, 'enter_tag'] = 'volume_breakout_short' return dataframe def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe.loc[:, 'exit_long'] = 0 dataframe.loc[:, 'exit_short'] = 0 dataframe.loc[:, 'exit_tag'] = '' # Exit when volume dies volume_exit = dataframe['volume'] < dataframe['volume_avg'] * 0.8 dataframe.loc[volume_exit, 'exit_long'] = 1 dataframe.loc[volume_exit, 'exit_short'] = 1 dataframe.loc[volume_exit, 'exit_tag'] = 'volume_exit' return dataframe