# source: https://raw.githubusercontent.com/vigoferrel/qbtc-unified/ef7ffc8f45cc7ab041884cd0c08a2043acc1f0cb/freqtrade_qbtc/strategies/QBTCOptimalV2.py
"""
Github_vigoferrel_qbtc_unified__QBTCOptimalV2__20251009_202533 - Versión Mejorada Basada en Resultados Reales
============================================================

Filosofía: Solo mantener las señales que FUNCIONAN, eliminar las problemáticas.
Optimizada en base a backtests que mostraron +0.04% ganancia, 53% win rate.

CAMBIOS PRINCIPALES:
- ELIMINADA: technical_breakdown (causaba la mayoría de pérdidas)
- MEJORADA: Condiciones de entrada más selectivas
- SIMPLIFICADA: Menos señales conflictivas
- OPTIMIZADA: Para timeframe 5m, períodos cortos (10-15 días)

Target: >60% win rate, >8% profit mensual, profit factor >1.5

Creado: 2025-09-10
Autor: QBTC Trading System - Optimal V2 (Evidence-Based)
"""

import talib.abstract as ta
import pandas as pd
import numpy as np
from pandas import DataFrame
from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import DecimalParameter, IntParameter
import logging
from datetime import datetime

class Github_vigoferrel_qbtc_unified__QBTCOptimalV2__20251009_202533(IStrategy):
    
    # Metadatos optimizados basados en resultados
    INTERFACE_VERSION = 3
    timeframe = '5m'  # CONFIRMADO: Mejor timeframe
    can_short = False
    stoploss = -0.025  # Slightly tighter - less room for error
    
    # ROI más agresivo para capturar ganancias rápidamente
    minimal_roi = {
        "0": 0.08,     # 8% inmediato para momentum muy fuerte
        "5": 0.05,     # 5% después de 5min (más rápido)
        "15": 0.03,    # 3% después de 15min
        "45": 0.02,    # 2% después de 45min
        "120": 0.01    # 1% después de 2h
    }
    
    # Configuración conservadora para mayor consistencia
    max_open_trades = 4  # Reduced from 6 - better risk management
    stake_currency = 'USDT'
    stake_amount = 100
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False  # CHANGED: Respect ROI for better profit taking
    
    # Orders optimized for speed and reliability
    order_types = {
        'entry': 'market',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': True,
        'stoploss_on_exchange_interval': 30
    }
    
    order_time_in_force = {
        'entry': 'gtc',
        'exit': 'gtc'  # Changed from IOC - more reliable fills
    }
    
    # PARÁMETROS OPTIMIZADOS - Más selectivos basados en evidencia
    # OVERSOLD BOUNCE - Más estricto
    rsi_oversold = IntParameter(20, 35, default=28, space="buy")  # LOWER - more selective
    volume_spike_factor = DecimalParameter(1.8, 3.0, default=2.2, space="buy")  # HIGHER - need strong volume
    
    # BREAKOUT STRATEGY - Balanced
    breakout_periods = IntParameter(15, 25, default=20, space="buy")
    breakout_volume_factor = DecimalParameter(1.5, 2.8, default=2.0, space="buy")
    
    # TREND FOLLOWING - More selective
    trend_strength = DecimalParameter(0.012, 0.025, default=0.018, space="buy")  # HIGHER - stronger trends
    pullback_rsi_max = IntParameter(50, 65, default=58, space="buy")  # LOWER - less overbought
    
    # EXIT PARAMETERS - Fine tuned
    rsi_overbought = IntParameter(78, 88, default=83, space="sell")
    volume_threshold_low = DecimalParameter(0.3, 0.6, default=0.4, space="sell")
    
    def __init__(self, config: dict) -> None:
        super().__init__(config)
        self.logger = logging.getLogger(__name__)
        
        # Enhanced tracking
        self._strategy_stats = {
            'oversold_trades': 0,
            'breakout_trades': 0, 
            'trend_trades': 0,
            'roi_exits': 0,
            'signal_exits': 0,
            'stop_exits': 0
        }
        
    def informative_pairs(self):
        return []
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """Indicadores esenciales - eliminamos complejidad innecesaria"""
        
        # Core indicators only
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=9)  # Faster RSI
        
        # Essential EMAs
        dataframe['ema8'] = ta.EMA(dataframe, timeperiod=8)
        dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
        
        # MACD for trend confirmation
        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']
        
        # Volume analysis - key for crypto
        dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=20)
        dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma']
        
        # Bollinger Bands for volatility
        bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
        dataframe['bb_lower'] = bollinger['lowerband']
        dataframe['bb_middle'] = bollinger['middleband'] 
        dataframe['bb_upper'] = bollinger['upperband']
        dataframe['bb_percent'] = (dataframe['close'] - dataframe['bb_lower']) / (dataframe['bb_upper'] - dataframe['bb_lower'])
        
        # Price action levels
        dataframe['high_20'] = dataframe['high'].rolling(window=self.breakout_periods.value).max()
        dataframe['low_20'] = dataframe['low'].rolling(window=self.breakout_periods.value).min()
        
        # Trend strength calculation
        dataframe['trend_strength'] = (dataframe['ema8'] - dataframe['ema50']) / dataframe['ema50']
        
        # Market structure
        dataframe['higher_high'] = (dataframe['high'] > dataframe['high'].shift(1))
        dataframe['higher_low'] = (dataframe['low'] > dataframe['low'].shift(1))
        
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        EVIDENCE-BASED ENTRY SYSTEM
        Only keep what works: oversold_bounce, breakout_momentum, trend_pullback
        """
        
        pair = metadata['pair']
        
        # Initialize
        dataframe.loc[:, 'enter_long'] = 0
        dataframe.loc[:, 'enter_tag'] = ''
        
        # STRATEGY 1: OVERSOLD BOUNCE - Much more selective
        oversold_conditions = (
            (dataframe['rsi'] <= self.rsi_oversold.value) &  # Very oversold
            (dataframe['volume_ratio'] >= self.volume_spike_factor.value) &  # Strong volume
            (dataframe['bb_percent'] <= 0.2) &  # Deep in lower BB
            (dataframe['close'] > dataframe['open']) &  # Green candle (bounce confirmation)
            (dataframe['close'] > dataframe['low'] * 1.01) &  # Price recovering from low
            (dataframe['macd'] > dataframe['macdsignal'].shift(1)) &  # MACD improving
            (dataframe['ema8'] > dataframe['ema8'].shift(2)) &  # EMA8 starting to turn up
            (dataframe['higher_low'])  # Market structure: higher low
        )
        
        dataframe.loc[oversold_conditions, 'enter_long'] = 1
        dataframe.loc[oversold_conditions, 'enter_tag'] = 'oversold_bounce'
        
        # STRATEGY 2: BREAKOUT MOMENTUM - Better confirmation
        breakout_conditions = (
            (dataframe['close'] > dataframe['high_20'].shift(1)) &  # Clean breakout
            (dataframe['volume_ratio'] >= self.breakout_volume_factor.value) &  # Volume confirmation
            (dataframe['rsi'] > 50) & (dataframe['rsi'] < 75) &  # Good RSI range
            (dataframe['macd'] > dataframe['macdsignal']) &  # MACD positive
            (dataframe['ema8'] > dataframe['ema21']) &  # Short term uptrend
            (dataframe['close'] > dataframe['open']) &  # Green candle
            (dataframe['higher_high'])  # Market structure: higher high
        )
        
        # Don't overwrite oversold signals
        breakout_mask = breakout_conditions & (dataframe['enter_long'] == 0)
        dataframe.loc[breakout_mask, 'enter_long'] = 1
        dataframe.loc[breakout_mask, 'enter_tag'] = 'breakout_momentum'
        
        # STRATEGY 3: TREND PULLBACK - More selective
        trend_conditions = (
            (dataframe['trend_strength'] >= self.trend_strength.value) &  # Strong uptrend
            (dataframe['close'] > dataframe['ema50']) &  # Above major EMA
            (dataframe['close'] <= dataframe['ema21']) &  # Pullback to EMA21
            (dataframe['close'] > dataframe['ema21'] * 0.995) &  # Not too deep below EMA21
            (dataframe['rsi'] <= self.pullback_rsi_max.value) &  # Not overbought
            (dataframe['rsi'] > 40) &  # Not oversold either
            (dataframe['volume_ratio'] >= 1.0) &  # Decent volume
            (dataframe['macd'] > dataframe['macdsignal']) &  # MACD still positive
            (dataframe['bb_percent'] > 0.3) & (dataframe['bb_percent'] < 0.7)  # Mid BB range
        )
        
        # Don't overwrite other signals
        trend_mask = trend_conditions & (dataframe['enter_long'] == 0)
        dataframe.loc[trend_mask, 'enter_long'] = 1
        dataframe.loc[trend_mask, 'enter_tag'] = 'trend_pullback'
        
        # Logging with better metrics
        if oversold_conditions.any():
            self._strategy_stats['oversold_trades'] += 1
            self.logger.info(f"🎯 OVERSOLD BOUNCE: {pair} | RSI={dataframe['rsi'].iloc[-1]:.1f} | Vol={dataframe['volume_ratio'].iloc[-1]:.1f}x | BB={dataframe['bb_percent'].iloc[-1]:.2f}")
            
        if breakout_mask.any():
            self._strategy_stats['breakout_trades'] += 1  
            self.logger.info(f"🚀 BREAKOUT: {pair} | Price=${dataframe['close'].iloc[-1]:.4f} | High20=${dataframe['high_20'].iloc[-1]:.4f} | Vol={dataframe['volume_ratio'].iloc[-1]:.1f}x")
            
        if trend_mask.any():
            self._strategy_stats['trend_trades'] += 1
            self.logger.info(f"📈 TREND PULLBACK: {pair} | Strength={dataframe['trend_strength'].iloc[-1]:.3f} | RSI={dataframe['rsi'].iloc[-1]:.1f} | Price=${dataframe['close'].iloc[-1]:.4f}")
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        SIMPLIFIED EXIT SYSTEM - Remove problematic technical_breakdown
        Keep only: overbought_exit, volume_collapse
        """
        
        dataframe.loc[:, 'exit_long'] = 0
        dataframe.loc[:, 'exit_tag'] = ''
        
        # EXIT 1: Overbought with momentum loss
        overbought_exit = (
            (dataframe['rsi'] >= self.rsi_overbought.value) &  # Strong overbought
            (dataframe['rsi_fast'] < dataframe['rsi_fast'].shift(1)) &  # RSI declining
            (dataframe['volume_ratio'] < 1.2) &  # Volume not supporting
            (dataframe['bb_percent'] > 0.8)  # Near upper BB
        )
        
        dataframe.loc[overbought_exit, 'exit_long'] = 1
        dataframe.loc[overbought_exit, 'exit_tag'] = 'overbought_exit'
        
        # EXIT 2: Volume collapse - Strong distribution signal
        volume_collapse = (
            (dataframe['volume_ratio'] < self.volume_threshold_low.value) &  # Very low volume
            (dataframe['close'] < dataframe['close'].shift(1)) &  # Price declining
            (dataframe['rsi'] > 70) &  # Still high RSI (distribution)
            (dataframe['bb_percent'] > 0.75) &  # High in BB range
            (dataframe['ema8'] < dataframe['ema8'].shift(1))  # EMA8 turning down
        )
        
        volume_mask = volume_collapse & (dataframe['exit_long'] == 0)
        dataframe.loc[volume_mask, 'exit_long'] = 1
        dataframe.loc[volume_mask, 'exit_tag'] = 'volume_collapse'
        
        # NOTE: technical_breakdown ELIMINATED - was causing most losses
        
        return dataframe
    
    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                       current_rate: float, current_profit: float, **kwargs) -> float:
        """
        CONSERVATIVE TRAILING STOP
        """
        
        # Base stoploss
        stoploss_value = self.stoploss
        
        # After 3% profit, use trailing stop
        if current_profit > 0.03:
            # Trail at 1.5% distance
            trail_distance = 0.015
            stoploss_value = current_profit - trail_distance
            
        return stoploss_value
    
    def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
                           rate: float, time_in_force: str, current_time: datetime,
                           entry_tag: str, side: str, **kwargs) -> bool:
        """
        FINAL VALIDATION - Keep simple
        """
        
        # Log performance stats periodically
        total_trades = sum(self._strategy_stats.values())
        if total_trades > 0 and total_trades % 10 == 0:
            self.logger.info(f"📊 STATS - Total: {total_trades} | "
                           f"Oversold: {self._strategy_stats['oversold_trades']} | "
                           f"Breakout: {self._strategy_stats['breakout_trades']} | "
                           f"Trend: {self._strategy_stats['trend_trades']}")
            
        return True
    
    def custom_exit(self, pair: str, trade: 'Trade', current_time: datetime, 
                   current_rate: float, current_profit: float, **kwargs) -> tuple:
        """
        SIMPLE PROFIT MANAGEMENT
        """
        
        # Take partial profits at 6% gain
        if current_profit >= 0.06:
            self.logger.info(f"💰 PARTIAL EXIT: {pair} at {current_profit:.1%} profit")
            return 0.4, 'partial_6pct'  # Exit 40% of position
            
        return None
