# source: https://raw.githubusercontent.com/vigoferrel/qbtc-unified/ef7ffc8f45cc7ab041884cd0c08a2043acc1f0cb/freqtrade_qbtc/strategies/QBTCSimple.py
"""
Github_vigoferrel_qbtc_unified__QBTCSimple__20251009_202533 - Back to Basics: Solo lo que funciona
=================================================

FILOSOFÍA SIMPLE:
- Basado 100% en EVIDENCIA de backtests anteriores
- QBTCOptimal mostró +0.04% en períodos cortos
- ROI exits tenían 100% win rate
- El problema son los stop losses agresivos

CAMBIOS SIMPLES:
✅ Keep: ROI targets que funcionan (100% win rate)
✅ Keep: Señales oversold_bounce y trend_pullback que funcionaron
❌ Remove: technical_breakdown que causaba pérdidas
🔧 Fix: Stop loss menos agresivo (3% → 4%)
🔧 Fix: Condiciones más selectivas

Target: >60% win rate, >5% profit mensual

Creado: 2025-09-10
Autor: QBTC Trading System - Simple 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__QBTCSimple__20251009_202533(IStrategy):
    
    # Evidence-based settings
    INTERFACE_VERSION = 3
    timeframe = '5m'  # Proven best timeframe
    can_short = False
    stoploss = -0.04  # WIDER: 4% instead of 2.5% (less aggressive)
    
    # ROI from successful tests - KEEP WHAT WORKS
    minimal_roi = {
        "0": 0.06,     # 6% immediate
        "10": 0.035,   # 3.5% after 10min
        "30": 0.02,    # 2% after 30min
        "90": 0.015,   # 1.5% after 1.5h
        "240": 0.01    # 1% after 4h
    }
    
    # Conservative settings
    max_open_trades = 4
    stake_currency = 'USDT'
    stake_amount = 100
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False  # RESPECT ROI - they worked!
    
    # Simple orders
    order_types = {
        'entry': 'market',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': True
    }
    
    order_time_in_force = {
        'entry': 'gtc',
        'exit': 'gtc'
    }
    
    # SIMPLE PARAMETERS - Only the essentials
    rsi_oversold = IntParameter(25, 35, default=30, space="buy")
    volume_spike = DecimalParameter(1.5, 2.5, default=2.0, space="buy")
    trend_strength = DecimalParameter(0.01, 0.03, default=0.02, space="buy")
    
    # EXIT PARAMETERS
    rsi_overbought = IntParameter(75, 85, default=80, space="sell")
    volume_exhaustion = DecimalParameter(0.3, 0.6, default=0.45, space="sell")
    
    def __init__(self, config: dict) -> None:
        super().__init__(config)
        self.logger = logging.getLogger(__name__)
        
        self._stats = {
            'oversold_entries': 0,
            'trend_entries': 0,
            'roi_exits': 0,
            'signal_exits': 0
        }
        
    def informative_pairs(self):
        return []
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """SIMPLE INDICATORS - Only what we need"""
        
        # Basic RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=9)
        
        # Simple EMAs
        dataframe['ema_21'] = ta.EMA(dataframe, timeperiod=21)
        dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100)
        
        # Volume
        dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=20)
        dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma']
        
        # MACD for trend
        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        
        # Bollinger Bands
        bollinger = ta.BBANDS(dataframe, timeperiod=20)
        dataframe['bb_lower'] = bollinger['lowerband']
        dataframe['bb_upper'] = bollinger['upperband']
        dataframe['bb_percent'] = (dataframe['close'] - dataframe['bb_lower']) / (dataframe['bb_upper'] - dataframe['bb_lower'])
        
        # Simple trend strength
        dataframe['trend_strength'] = (dataframe['ema_21'] - dataframe['ema_50']) / dataframe['ema_50']
        
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        SIMPLE ENTRY LOGIC - Only proven signals
        Based on evidence from successful backtests
        """
        
        pair = metadata['pair']
        
        # Initialize
        dataframe.loc[:, 'enter_long'] = 0
        dataframe.loc[:, 'enter_tag'] = ''
        
        # ENTRY 1: OVERSOLD BOUNCE - Proven to work
        oversold_bounce = (
            (dataframe['rsi'] <= self.rsi_oversold.value) &              # Oversold
            (dataframe['volume_ratio'] >= self.volume_spike.value) &     # Volume spike
            (dataframe['bb_percent'] <= 0.25) &                         # Near BB lower
            (dataframe['close'] > dataframe['open']) &                  # Green candle
            (dataframe['macd'] > dataframe['macdsignal'].shift(1)) &    # MACD improving
            (dataframe['close'] > dataframe['bb_lower'] * 1.002)        # Above BB lower
        )
        
        dataframe.loc[oversold_bounce, 'enter_long'] = 1
        dataframe.loc[oversold_bounce, 'enter_tag'] = 'oversold_bounce'
        
        # ENTRY 2: TREND PULLBACK - Also proven to work
        trend_pullback = (
            (dataframe['trend_strength'] >= self.trend_strength.value) & # Uptrend
            (dataframe['close'] > dataframe['ema_100']) &               # Above major EMA
            (dataframe['close'] <= dataframe['ema_21']) &               # Pullback to EMA21
            (dataframe['close'] > dataframe['ema_21'] * 0.997) &        # Not far below
            (dataframe['rsi'] > 40) & (dataframe['rsi'] < 65) &         # Good RSI range
            (dataframe['volume_ratio'] >= 1.0) &                       # Decent volume
            (dataframe['macd'] > dataframe['macdsignal'])               # MACD positive
        )
        
        # Don't overwrite oversold signals
        pullback_mask = trend_pullback & (dataframe['enter_long'] == 0)
        dataframe.loc[pullback_mask, 'enter_long'] = 1
        dataframe.loc[pullback_mask, 'enter_tag'] = 'trend_pullback'
        
        # Logging
        if oversold_bounce.any():
            self._stats['oversold_entries'] += 1
            self.logger.info(f"🎯 OVERSOLD BOUNCE: {pair} | RSI={dataframe['rsi'].iloc[-1]:.1f} | Vol={dataframe['volume_ratio'].iloc[-1]:.1f}x")
            
        if pullback_mask.any():
            self._stats['trend_entries'] += 1
            self.logger.info(f"📈 TREND PULLBACK: {pair} | Strength={dataframe['trend_strength'].iloc[-1]:.3f} | RSI={dataframe['rsi'].iloc[-1]:.1f}")
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        SIMPLE EXIT LOGIC - Remove problematic exits
        Keep only what works reliably
        """
        
        dataframe.loc[:, 'exit_long'] = 0
        dataframe.loc[:, 'exit_tag'] = ''
        
        # EXIT 1: Overbought momentum loss
        overbought_exit = (
            (dataframe['rsi'] >= self.rsi_overbought.value) &           # Overbought
            (dataframe['rsi_fast'] < dataframe['rsi_fast'].shift(1)) &  # RSI declining
            (dataframe['volume_ratio'] < 1.0)                          # Volume drying
        )
        
        dataframe.loc[overbought_exit, 'exit_long'] = 1
        dataframe.loc[overbought_exit, 'exit_tag'] = 'overbought_exit'
        
        # EXIT 2: Volume exhaustion - ONLY when really obvious
        volume_exhaustion = (
            (dataframe['volume_ratio'] < self.volume_exhaustion.value) & # Very low volume
            (dataframe['bb_percent'] > 0.8) &                           # Near BB upper
            (dataframe['close'] < dataframe['close'].shift(1)) &        # Price declining
            (dataframe['rsi'] > 70)                                     # Still elevated RSI
        )
        
        volume_mask = volume_exhaustion & (dataframe['exit_long'] == 0)
        dataframe.loc[volume_mask, 'exit_long'] = 1
        dataframe.loc[volume_mask, 'exit_tag'] = 'volume_exhaustion'
        
        # NOTE: technical_breakdown REMOVED - it was causing losses
        
        return dataframe
    
    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:
        """
        Simple validation
        """
        
        # Log stats periodically
        total_entries = self._stats['oversold_entries'] + self._stats['trend_entries']
        if total_entries > 0 and total_entries % 15 == 0:
            oversold_rate = (self._stats['oversold_entries'] / total_entries) * 100
            trend_rate = (self._stats['trend_entries'] / total_entries) * 100
            self.logger.info(f"📊 ENTRY DISTRIBUTION: Oversold {oversold_rate:.1f}% | Trend {trend_rate:.1f}%")
        
        self.logger.info(f"✅ SIMPLE ENTRY: {pair} | {entry_tag} | ${rate:.4f}")
        return True
