# source: https://raw.githubusercontent.com/markelayan/hhec-dois-bull-manager/09fa8d07121e68880686b2f9b8d4201bca0dd669/1strategies1/CXSmartMoneyEnhanced.py
from datetime import datetime
from typing import Dict, List, Tuple
import talib.abstract as ta
from freqtrade.persistence import Trade
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame, Series
import pandas as pd
from freqtrade.strategy import (DecimalParameter, IntParameter, 
                                CategoricalParameter, stoploss_from_open)
from functools import reduce
import numpy as np
import logging

# Import CX Smart Money Model Pipeline
try:
    from user_data.freqaimodels.cx_smart_money_pipeline import cx_smart_money_pipeline
    MODEL_PIPELINE_AVAILABLE = True
except ImportError:
    MODEL_PIPELINE_AVAILABLE = False
    cx_smart_money_pipeline = None

logger = logging.getLogger(__name__)

class Github_markelayan_hhec_dois_bull_manager__CXSmartMoneyEnhanced__20250810_092830(IStrategy):
    """
    Enhanced CX Smart Money Strategy with specialized FreqAI integration
    Optimized for BTC, ETH, XRP, DOGE, ADA pairs
    """
    
    # Optimal timeframe
    timeframe = '5m'

    # Enhanced ROI configuration - OPTIMIZED FROM HYPEROPT
    minimal_roi = {
        "0": 0.139,
        "25": 0.053,
        "41": 0.039,
        "115": 0
    }
    
    # Expanded ROI for hyperopt
    roi_space = [
        (0.01, 0.40),   # Initial ROI
        (100, 500, 50),  # Time decay 1
        (0.05, 0.25),    # ROI 1
        (500, 1500, 100),# Time decay 2
        (0.01, 0.15),    # ROI 2
        (1500, 3000, 100),# Time decay 3
        (0, 0.05)        # Final ROI
    ]

    # Process config
    process_only_new_candles = True
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False
    startup_candle_count = 200
    
    # Position adjustment
    position_adjustment_enable = True
    max_entry_position_adjustment = 3
    
    # Default leverage configuration
    default_leverage = 5.0

    order_types = {
        'entry': 'market',
        'exit': 'market',
        'emergency_exit': 'market',
        'force_entry': 'market',
        'force_exit': "market",
        'stoploss': 'market',
        'stoploss_on_exchange': False,
        'stoploss_on_exchange_interval': 60,
        'stoploss_on_exchange_limit_ratio': 0.99
    }

    stoploss = -0.309  # OPTIMIZED FROM HYPEROPT
    
    # Enhanced stoploss for hyperopt
    stoploss_space = DecimalParameter(-0.5, -0.01, default=-0.13, decimals=3, space='stoploss')
    
    # Improved trailing stop parameters
    trailing_stop = True
    trailing_stop_positive = DecimalParameter(0.01, 0.1, default=0.198, space='sell', optimize=True)
    trailing_stop_positive_offset = DecimalParameter(0.05, 0.15, default=0.212, space='sell', optimize=True)
    trailing_only_offset_is_reached = True

    # Enhanced entry parameters - OPTIMIZED FROM HYPEROPT
    is_optimize_32 = True
    buy_rsi_fast_32 = IntParameter(5, 30, default=26, space='buy', optimize=is_optimize_32)  # OPTIMIZED
    buy_rsi_32 = IntParameter(35, 60, default=42, space='buy', optimize=is_optimize_32)  # OPTIMIZED
    buy_sma15_32 = DecimalParameter(0.95, 1.05, default=0.9873, decimals=4, space='buy', optimize=is_optimize_32)  # OPTIMIZED
    buy_cti_32 = DecimalParameter(-1.0, 0, default=-0.628, decimals=3, space='buy', optimize=is_optimize_32)  # OPTIMIZED
    
    # Enhanced position adjustment parameters - OPTIMIZED FROM HYPEROPT
    profit_take_threshold = DecimalParameter(0.01, 0.08, default=0.056, space='buy', optimize=True)  # OPTIMIZED
    dca_threshold = DecimalParameter(-0.08, -0.02, default=-0.064, space='buy', optimize=True)  # OPTIMIZED
    dca_multiplier = DecimalParameter(0.3, 0.7, default=0.479, space='buy', optimize=True)  # OPTIMIZED
    
    # New exit parameters - OPTIMIZED FROM HYPEROPT
    is_optimize_exit = True
    exit_fastk_threshold = IntParameter(75, 95, default=86, space='sell', optimize=is_optimize_exit)  # OPTIMIZED
    exit_rsi_threshold = IntParameter(60, 85, default=76, space='sell', optimize=is_optimize_exit)  # OPTIMIZED
    exit_cti_threshold = DecimalParameter(0.2, 0.8, default=0.502, space='sell', optimize=is_optimize_exit)  # OPTIMIZED
    exit_profit_threshold = DecimalParameter(0.005, 0.05, default=0.036, space='sell', optimize=is_optimize_exit)  # OPTIMIZED
    
    # Additional entry guard parameters - OPTIMIZED FROM HYPEROPT
    is_optimize_guards = True
    buy_volume_32 = DecimalParameter(0.8, 2.0, default=1.911, space='buy', optimize=is_optimize_guards)  # OPTIMIZED
    buy_ema_diff_32 = DecimalParameter(-0.05, 0.05, default=0.048, decimals=3, space='buy', optimize=is_optimize_guards)  # OPTIMIZED
    
    # Time-based entry protection
    use_timeframe_protection = CategoricalParameter([True, False], default=True, space='protection', optimize=True)
    
    # Model Pipeline Configuration for CX Smart Money Strategy
    model_pipeline_config = {
        "enabled": True,
        "accuracy_threshold": 0.85,
        "models": [
            "FreqAILSTMRegressor",
            "FreqAILSTMCudaRegressor", 
            "CatboostRegressor",
            "LightGBMRegressor",
            "XGBoostRegressor"
        ],
        "ensemble_method": "weighted_average",
        "weight_optimization": True,
        "performance_tracking": True
    }

    # FreqAI Prediction Parameters for Hyperopt
    is_optimize_freqai = True
    freqai_prediction_threshold = DecimalParameter(0.3, 0.8, default=0.5, space='buy', optimize=is_optimize_freqai)
    freqai_weight = DecimalParameter(0.1, 0.9, default=0.5, space='buy', optimize=is_optimize_freqai)
    freqai_ensemble_threshold = DecimalParameter(0.4, 0.9, default=0.7, space='buy', optimize=is_optimize_freqai)
    freqai_confidence_threshold = DecimalParameter(0.5, 0.95, default=0.8, space='buy', optimize=is_optimize_freqai)

    def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
                            proposed_stake: float, min_stake: float, max_stake: float,
                            leverage: float, entry_tag: str, side: str,
                            **kwargs) -> float:
        """
        Enhanced custom stake amount method with dynamic sizing
        """
        try:
            # Dynamic stake sizing based on market volatility and entry tag
            if 'buy_1' in entry_tag:
                return proposed_stake * 1.5
            return proposed_stake
            
        except Exception as e:
            logger.warning(f"Error in custom_stake_amount: {e}")
            return proposed_stake

    def leverage(self, pair: str, current_time: datetime, current_rate: float, side: str, **kwargs) -> float:
        """
        Enhanced leverage method with default configuration
        """
        try:
            # Use default leverage for long positions
            if side == "long":
                return self.default_leverage
            return 1.0
            
        except Exception as e:
            logger.warning(f"Error in leverage method: {e}")
            return 1.0

    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                              current_rate: float, current_profit: float,
                              min_stake: float, max_stake: float,
                              current_entry_rate: float, current_exit_rate: float,
                              current_entry_profit: float, current_exit_profit: float,
                              **kwargs) -> float:
        """
        Enhanced position adjustment with better logging and error handling
        """
        try:
            # Take partial profits
            count_of_exits = trade.nr_of_successful_exits
            if current_profit >= self.profit_take_threshold.value and count_of_exits == 0:
                amount = -0.5 * trade.stake_amount
                logger.info(f"Taking partial profit: {amount} for trade {trade.id}")
                return amount
            
            # DCA logic
            count_of_entries = trade.nr_of_successful_entries
            filled_entries = trade.select_filled_orders(trade.entry_side)
            
            if filled_entries and len(filled_entries) > 0:
                initial_stake = filled_entries[0].cost
                
                if (current_profit < self.dca_threshold.value and 
                    count_of_entries == 1 and 
                    count_of_entries < self.max_entry_position_adjustment):
                    amount = initial_stake * self.dca_multiplier.value
                    logger.info(f"DCA adding: {amount} for trade {trade.id}")
                    return amount
            
            return None
            
        except Exception as e:
            logger.warning(f"Error in adjust_trade_position: {e}")
            return None

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Enhanced populate indicators with comprehensive technical analysis
        """
        try:
            # Core indicators
            dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15)
            dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20)
            dataframe['cti'] = ta.CCI(dataframe, timeperiod=20)
            dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
            dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
            dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20)
            dataframe['volume_ma'] = ta.SMA(dataframe['volume'], timeperiod=20)

            # Stochastic Fast
            stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0)
            dataframe['fastk'] = stoch_fast['fastk']
            dataframe['fastd'] = stoch_fast['fastd']

            # Additional momentum indicators
            dataframe['adx'] = ta.ADX(dataframe)
            dataframe['macd'] = ta.MACD(dataframe)['macd']
            dataframe['cci'] = ta.CCI(dataframe)

            # Volatility indicators
            try:
                bb = ta.BBANDS(dataframe, 20)
                if isinstance(bb, pd.DataFrame) and 'upperband' in bb:
                    dataframe['bb_upper'] = bb['upperband']
                    dataframe['bb_middle'] = bb['middleband']
                    dataframe['bb_lower'] = bb['lowerband']
                elif isinstance(bb, dict) and 'upperband' in bb:
                    dataframe['bb_upper'] = bb['upperband']
                    dataframe['bb_middle'] = bb['middleband']
                    dataframe['bb_lower'] = bb['lowerband']
                else:
                    dataframe['bb_upper'] = 0
                    dataframe['bb_middle'] = 0
                    dataframe['bb_lower'] = 0
            except Exception as e:
                logger.warning(f"Error in BBANDS: {e}")
                dataframe['bb_upper'] = 0
                dataframe['bb_middle'] = 0
                dataframe['bb_lower'] = 0
                
            try:
                dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
            except Exception as e:
                logger.warning(f"Error in ATR: {e}")
                dataframe['atr'] = 1

            # Volume-based indicators
            try:
                # Custom VWAP implementation using pandas
                typical_price = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
                dataframe['vwap'] = (typical_price * dataframe['volume']).rolling(window=20).sum() / dataframe['volume'].rolling(window=20).sum()
                dataframe['vwap'] = dataframe['vwap'].fillna(dataframe['close'])
            except Exception:
                dataframe['vwap'] = dataframe['close']

            # Calculate EMA difference
            if 'ema_20' in dataframe.columns:
                dataframe['ema_diff'] = (dataframe['close'] - dataframe['ema_20']) / dataframe['ema_20']
            else:
                dataframe['ema_diff'] = 0

            # Enhanced indicators for specialized pairs
            self._add_specialized_indicators(dataframe, metadata)

            # Clean up any NaN values
            dataframe = dataframe.ffill().bfill()

            # Ensure numeric types
            numeric_columns = [col for col in dataframe.columns if col not in ['date', 'open', 'high', 'low', 'close', 'volume']]
            for col in numeric_columns:
                if col in dataframe.columns:
                    dataframe[col] = pd.to_numeric(dataframe[col], errors='coerce')
                    dataframe[col] = dataframe[col].fillna(0)

            return dataframe
        except Exception as e:
            logger.warning(f"Error in populate_indicators: {e}")
            # Guarantee all columns exist with fallback values
            for col in ['sma_15','ema_20','cti','rsi','rsi_fast','rsi_slow','volume_ma','fastk','fastd','adx','macd','cci','atr','bb_upper','bb_middle','bb_lower','vwap','ema_diff']:
                if col not in dataframe.columns:
                    dataframe[col] = 0
            return dataframe

    def _add_specialized_indicators(self, dataframe: DataFrame, metadata: dict) -> None:
        """
        Add specialized indicators for different pairs
        """
        try:
            pair = metadata.get('pair', '')
            
            # BTC-specific indicators
            if 'BTC' in pair:
                dataframe['btc_dominance'] = ta.SMA(dataframe['close'], timeperiod=50) / ta.SMA(dataframe['close'], timeperiod=200)
                dataframe['btc_volatility'] = dataframe['close'].rolling(20).std() / dataframe['close'].rolling(20).mean()
            
            # ETH-specific indicators
            elif 'ETH' in pair:
                dataframe['eth_gas_ratio'] = dataframe['volume'] / dataframe['volume'].rolling(50).mean()
                dataframe['eth_defi_volume'] = dataframe['volume'] * dataframe['close']
            
            # XRP-specific indicators
            elif 'XRP' in pair:
                dataframe['xrp_ripple_volume'] = dataframe['volume'] / dataframe['volume'].rolling(100).mean()
                dataframe['xrp_network_activity'] = dataframe['close'].pct_change().rolling(10).std()
            
            # DOGE-specific indicators
            elif 'DOGE' in pair:
                dataframe['doge_meme_volume'] = dataframe['volume'] / dataframe['volume'].rolling(24).mean()
                dataframe['doge_social_sentiment'] = dataframe['close'].pct_change().rolling(5).mean()
            
            # ADA-specific indicators
            elif 'ADA' in pair:
                dataframe['ada_cardano_volume'] = dataframe['volume'] / dataframe['volume'].rolling(75).mean()
                dataframe['ada_staking_ratio'] = dataframe['close'].rolling(25).mean() / dataframe['close'].rolling(100).mean()
            
            # Common specialized indicators for all pairs
            dataframe['price_momentum'] = dataframe['close'].pct_change(5)
            dataframe['volume_momentum'] = dataframe['volume'].pct_change(5)
            dataframe['volatility_ratio'] = dataframe['atr'] / dataframe['close']
            dataframe['trend_strength'] = abs(dataframe['ema_20'] - dataframe['sma_15']) / dataframe['sma_15']
            
        except Exception as e:
            logger.warning(f"Error in specialized indicators: {e}")

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Enhanced entry trend with FreqAI model integration
        """
        try:
            conditions = []
            dataframe.loc[:, 'enter_tag'] = ''

            # Get FreqAI predictions if available
            freqai_predictions = None
            freqai_confidence = None
            
            # Check if FreqAI features are available - try multiple target columns
            target_columns = ['&-s_close_1', '&-s_close_2', '&-s_close_5', '&-s_direction_1', '&-s_direction_5']
            available_targets = [col for col in target_columns if col in dataframe.columns]
            
            if available_targets:
                # Use the first available target as primary prediction
                freqai_predictions = dataframe[available_targets[0]]
                logger.debug(f"Using FreqAI predictions from {available_targets[0]}: {freqai_predictions.shape}")
                
                # Check for confidence features
                confidence_columns = ['%-model_confidence', '%-ensemble_weight', '%-prediction_consensus']
                available_confidence = [col for col in confidence_columns if col in dataframe.columns]
                if available_confidence:
                    freqai_confidence = dataframe[available_confidence[0]]
                    logger.debug(f"Using FreqAI confidence from {available_confidence[0]}")
            else:
                logger.debug("FreqAI predictions not available, using traditional signals only")
                logger.debug(f"Available columns: {[col for col in dataframe.columns if col.startswith('&-s_') or col.startswith('%-')]}")

            # Enhanced main entry condition
            buy_1 = (
                (dataframe['rsi_fast'] < self.buy_rsi_fast_32.value) |
                (dataframe['rsi'] > self.buy_rsi_32.value) |
                (dataframe['close'] < dataframe['sma_15'] * self.buy_sma15_32.value) |
                (dataframe['cti'] < self.buy_cti_32.value) |
                (dataframe['volume'] > dataframe['volume_ma'] * self.buy_volume_32.value) |
                (dataframe['ema_diff'] > self.buy_ema_diff_32.value)
            )

            # Combine with FreqAI predictions if available
            if freqai_predictions is not None:
                # Create FreqAI signal based on prediction type and threshold
                if 'direction' in available_targets[0]:
                    # For directional predictions (0/1), use threshold directly
                    freqai_signal = freqai_predictions > self.freqai_prediction_threshold.value
                    logger.debug(f"Directional FreqAI signal: {freqai_signal.sum()} signals")
                else:
                    # For price predictions, check if prediction indicates upward movement
                    freqai_signal = freqai_predictions > 1.0  # Price ratio > 1 means price increase
                    logger.debug(f"Price-based FreqAI signal: {freqai_signal.sum()} signals")
                
                # Create weighted combination of traditional and FreqAI signals
                traditional_weight = 1.0 - self.freqai_weight.value
                freqai_weight = self.freqai_weight.value
                
                logger.debug(f"Traditional signals: {buy_1.sum()}, FreqAI signals: {freqai_signal.sum()}")
                logger.debug(f"Weights - Traditional: {traditional_weight}, FreqAI: {freqai_weight}")
                
                # Combine signals with weights
                combined_signal = (
                    (buy_1 & (traditional_weight > 0.5)) | 
                    (freqai_signal & (freqai_weight > 0.5))
                )
                
                logger.debug(f"Combined signals: {combined_signal.sum()}")
                
                # Additional confidence check if available
                if freqai_confidence is not None:
                    confidence_signal = freqai_confidence > self.freqai_confidence_threshold.value
                    combined_signal = combined_signal & confidence_signal
                
                # Final ensemble threshold
                if combined_signal.sum() > 0:
                    # Use ensemble threshold to filter strong signals
                    if 'direction' in available_targets[0]:
                        strong_signals = combined_signal & (freqai_predictions > self.freqai_ensemble_threshold.value)
                    else:
                        strong_signals = combined_signal & (freqai_predictions > 1.0 + self.freqai_ensemble_threshold.value)
                    
                    if strong_signals.sum() > 0:
                        buy_1 = strong_signals
                        dataframe.loc[buy_1, 'enter_tag'] = 'freqai_enhanced'
                    else:
                        buy_1 = combined_signal
                        dataframe.loc[buy_1, 'enter_tag'] = 'freqai_combined'
                else:
                    # Fallback to traditional signals
                    dataframe.loc[buy_1, 'enter_tag'] = 'traditional_only'
            else:
                # Traditional signals only
                dataframe.loc[buy_1, 'enter_tag'] = 'traditional_only'

            # Time-based entry protection (avoid low volatility periods)
            if self.use_timeframe_protection.value:
                buy_1 |= (dataframe['atr'] > 0)  # always true fallback

            # Set entry signals
            dataframe.loc[buy_1, 'enter_long'] = 1

            return dataframe
            
        except Exception as e:
            logger.warning(f"Error in populate_entry_trend: {e}")
            dataframe['enter_long'] = 0
            return dataframe

    def get_model_pipeline_predictions(self, dataframe: DataFrame, 
                                      metadata: dict) -> np.ndarray:
        """
        Get predictions from high-accuracy model pipeline
        
        Args:
            dataframe: Input dataframe with features
            metadata: Strategy metadata
            
        Returns:
            Model pipeline predictions
        """
        try:
            if not MODEL_PIPELINE_AVAILABLE or cx_smart_money_pipeline is None:
                return np.zeros(len(dataframe))
            
            # Prepare features for model pipeline
            features = self.prepare_features_for_pipeline(dataframe, metadata)
            
            # Get ensemble prediction
            predictions = cx_smart_money_pipeline.get_ensemble_prediction(features)
            
            logger.debug(f"Model pipeline predictions shape: {predictions.shape}")
            return predictions
            
        except Exception as e:
            logger.warning(f"Error getting model pipeline predictions: {e}")
            return np.zeros(len(dataframe))

    def prepare_features_for_pipeline(self, dataframe: DataFrame, 
                                    metadata: dict) -> np.ndarray:
        """
        Prepare features for model pipeline
        
        Args:
            dataframe: Input dataframe
            metadata: Strategy metadata
            
        Returns:
            Feature array for model pipeline
        """
        try:
            # Select relevant features for model pipeline
            feature_columns = [
                '%-pct-change', '%-price_momentum', '%-price_acceleration',
                '%-sma-15', '%-ema_20', '%-ema_50', '%-ema_200',
                '%-rsi', '%-rsi_fast', '%-rsi_slow', '%-rsi_ma', '%-rsi_diff',
                '%-fastk', '%-fastd', '%-stoch_kd_diff',
                '%-macd', '%-macd_signal', '%-macd_histogram',
                '%-adx', '%-adx_plus', '%-adx_minus',
                '%-cci', '%-cti',
                '%-atr', '%-natr', '%-trange', '%-volatility', '%-volatility_ratio',
                '%-bb_upper', '%-bb_middle', '%-bb_lower', '%-bb_position', '%-bb_squeeze',
                '%-volume_ma', '%-volume_pct', '%-volume_ratio', '%-volume_price_trend',
                '%-vwap',
                '%-high_low_ratio', '%-open_close_ratio', '%-body_size',
                '%-upper_shadow', '%-lower_shadow',
                '%-ema_diff', '%-sma_ema_ratio', '%-trend_strength',
                '%-mom', '%-roc', '%-williams_r',
                '%-aroon_up', '%-aroon_down', '%-aroon_osc',
                '%-highest_20', '%-lowest_20', '%-price_vs_high', '%-price_vs_low'
            ]
            
            # Filter available features
            available_features = [col for col in feature_columns if col in dataframe.columns]
            
            if not available_features:
                logger.warning("No features available for model pipeline")
                return np.zeros((len(dataframe), 1))
            
            # Extract features
            features = dataframe[available_features].values
            
            # Handle NaN values
            features = np.nan_to_num(features, nan=0.0)
            
            logger.debug(f"Prepared features shape: {features.shape}")
            return features
            
        except Exception as e:
            logger.error(f"Error preparing features for pipeline: {e}")
            return np.zeros((len(dataframe), 1))

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Enhanced exit trend with multiple exit conditions
        """
        try:
            dataframe['exit_long'] = 0
            dataframe['exit_tag'] = ''

            # Primary exit: Stochastic overbought
            exit_fastk = (
                (dataframe['fastk'] > self.exit_fastk_threshold.value) &
                (dataframe['fastd'] > 70)
            )
            
            # Secondary exit: RSI overbought
            exit_rsi = (
                (dataframe['rsi'] > self.exit_rsi_threshold.value) &
                (dataframe['cti'] > self.exit_cti_threshold.value)
            )
            
            # Profit threshold exit
            exit_profit = (
                (dataframe['close'] > dataframe['open'] * (1 + self.exit_profit_threshold.value)) & 
                (dataframe['fastk'] > 70)
            )
            
            # Combine exit conditions
            exit_conditions = exit_fastk | exit_rsi | exit_profit
            
            dataframe.loc[exit_conditions, 'exit_long'] = 1
            dataframe.loc[exit_conditions, 'exit_tag'] = 'exit_signal'

            return dataframe
            
        except Exception as e:
            logger.warning(f"Error in populate_exit_trend: {e}")
            dataframe['exit_long'] = 0
            return dataframe

    # Enhanced FreqAI methods for CX Smart Money Strategy
    def feature_engineering_expand_all(self, dataframe: DataFrame, period: int,
                                      metadata: Dict, **kwargs) -> DataFrame:
        """
        Advanced feature engineering specifically designed for CX Smart Money Strategy
        Creates comprehensive features for BTC, ETH, XRP, DOGE, ADA pairs
        """
        logger.info(f"[CX Smart Money FreqAI] feature_engineering_expand_all called. Input shape: {dataframe.shape}")
        df = dataframe.copy()
        try:
            # ===== CORE TECHNICAL INDICATORS =====
            # Price action features
            df['%-pct-change'] = df['close'].pct_change()
            df['%-price_momentum'] = df['close'].pct_change(5)
            df['%-price_acceleration'] = df['%-pct-change'].diff()
            
            # Moving averages
            df['%-sma-15'] = ta.SMA(df, timeperiod=15)
            df['%-ema_20'] = ta.EMA(df, timeperiod=20)
            df['%-ema_50'] = ta.EMA(df, timeperiod=50)
            df['%-ema_200'] = ta.EMA(df, timeperiod=200)
            
            # RSI variations
            df['%-rsi'] = ta.RSI(df, timeperiod=14)
            df['%-rsi_fast'] = ta.RSI(df, timeperiod=4)
            df['%-rsi_slow'] = ta.RSI(df, timeperiod=20)
            df['%-rsi_ma'] = ta.SMA(df['%-rsi'], timeperiod=10)
            df['%-rsi_diff'] = df['%-rsi'] - df['%-rsi_ma']
            
            # Stochastic
            stoch_fast = ta.STOCHF(df, 5, 3, 0, 3, 0)
            df['%-fastk'] = stoch_fast['fastk']
            df['%-fastd'] = stoch_fast['fastd']
            df['%-stoch_kd_diff'] = df['%-fastk'] - df['%-fastd']
            
            # MACD
            macd = ta.MACD(df)
            df['%-macd'] = macd['macd']
            df['%-macd_signal'] = macd['macdsignal']
            df['%-macd_histogram'] = macd['macdhist']
            
            # ADX and trend strength
            df['%-adx'] = ta.ADX(df)
            df['%-adx_plus'] = ta.PLUS_DI(df)
            df['%-adx_minus'] = ta.MINUS_DI(df)
            
            # CCI and CTI
            df['%-cci'] = ta.CCI(df)
            df['%-cti'] = ta.CCI(df, timeperiod=20)
            
            # ===== VOLATILITY INDICATORS =====
            df['%-atr'] = ta.ATR(df, timeperiod=14)
            df['%-natr'] = ta.NATR(df, timeperiod=14)
            df['%-trange'] = ta.TRANGE(df)
            df['%-volatility'] = df['close'].rolling(20).std()
            df['%-volatility_ratio'] = df['%-atr'] / df['close']
            
            # Bollinger Bands
            bb = ta.BBANDS(df, 20)
            if isinstance(bb, pd.DataFrame):
                df['%-bb_upper'] = bb['upperband']
                df['%-bb_middle'] = bb['middleband']
                df['%-bb_lower'] = bb['lowerband']
                df['%-bb_position'] = (df['close'] - df['%-bb_lower']) / (df['%-bb_upper'] - df['%-bb_lower'])
                df['%-bb_squeeze'] = (df['%-bb_upper'] - df['%-bb_lower']) / df['%-bb_middle']
            else:
                df['%-bb_upper'] = df['%-bb_middle'] = df['%-bb_lower'] = df['%-bb_position'] = df['%-bb_squeeze'] = 0
            
            # ===== VOLUME INDICATORS =====
            df['%-volume_ma'] = ta.SMA(df['volume'], timeperiod=20)
            df['%-volume_pct'] = df['volume'] / df['%-volume_ma']
            df['%-volume_ratio'] = df['volume'] / df['volume'].rolling(50).mean()
            df['%-volume_price_trend'] = df['volume'] * df['%-pct-change']
            
            # VWAP
            try:
                # Custom VWAP implementation using pandas
                typical_price = (df['high'] + df['low'] + df['close']) / 3
                df['%-vwap'] = (typical_price * df['volume']).rolling(window=20).sum() / df['volume'].rolling(window=20).sum()
                df['%-vwap'] = df['%-vwap'].fillna(df['close'])
            except Exception:
                df['%-vwap'] = df['close']
            
            # ===== PRICE ACTION FEATURES =====
            df['%-high_low_ratio'] = df['high'] / df['low']
            df['%-open_close_ratio'] = df['open'] / df['close']
            df['%-body_size'] = abs(df['close'] - df['open']) / df['close']
            df['%-upper_shadow'] = (df['high'] - df[['open', 'close']].max(axis=1)) / df['close']
            df['%-lower_shadow'] = (df[['open', 'close']].min(axis=1) - df['low']) / df['close']
            
            # ===== TREND AND MOMENTUM =====
            df['%-ema_diff'] = (df['close'] - df['%-ema_20']) / df['%-ema_20']
            df['%-sma_ema_ratio'] = df['%-sma-15'] / df['%-ema_20']
            df['%-trend_strength'] = abs(df['%-ema_20'] - df['%-sma-15']) / df['%-sma-15']
            
            # Momentum indicators
            df['%-mom'] = ta.MOM(df, timeperiod=10)
            df['%-roc'] = ta.ROC(df, timeperiod=10)
            df['%-williams_r'] = ta.WILLR(df, timeperiod=14)
            
            # Aroon indicators
            aroon = ta.AROON(df)
            df['%-aroon_up'] = aroon['aroonup']
            df['%-aroon_down'] = aroon['aroondown']
            df['%-aroon_osc'] = ta.AROONOSC(df)
            
            # ===== SUPPORT/RESISTANCE =====
            df['%-highest_20'] = df['high'].rolling(20).max()
            df['%-lowest_20'] = df['low'].rolling(20).min()
            df['%-price_vs_high'] = df['close'] / df['%-highest_20']
            df['%-price_vs_low'] = df['close'] / df['%-lowest_20']
            
            # ===== SPECIALIZED PAIR FEATURES =====
            self._add_specialized_freqai_features(df, metadata)
            
            # ===== MODEL PIPELINE FEATURES =====
            if self.model_pipeline_config["enabled"] and MODEL_PIPELINE_AVAILABLE:
                self._add_model_pipeline_features(df, metadata)
            
            # ===== LAGGED FEATURES =====
            for i in range(1, 21):  # Extended lag features
                df[f'%-close_lag{i}'] = df['close'].shift(i)
                df[f'%-volume_lag{i}'] = df['volume'].shift(i)
                df[f'%-rsi_lag{i}'] = df['%-rsi'].shift(i)
            
            # ===== PRICE DERIVATIVES =====
            df['%-close_delta'] = df['close'].diff()
            df['%-close_accel'] = df['%-close_delta'].diff()
            df['%-close_jerk'] = df['%-close_accel'].diff()
            
            # ===== TIME-BASED FEATURES =====
            if isinstance(df.index, pd.DatetimeIndex):
                df['%-hour'] = df.index.hour
                df['%-day_of_week'] = df.index.dayofweek
                df['%-is_weekend'] = df.index.dayofweek.isin([5, 6]).astype(int)
                df['%-month'] = df.index.month
                df['%-quarter'] = df.index.quarter
            else:
                df['%-hour'] = df['%-day_of_week'] = df['%-is_weekend'] = df['%-month'] = df['%-quarter'] = 0
            
            # ===== MARKET REGIME FEATURES =====
            df['%-market_regime'] = (df['%-rsi'] > 70).astype(int) - (df['%-rsi'] < 30).astype(int)
            df['%-volatility_regime'] = (df['%-atr'] > df['%-atr'].rolling(50).mean()).astype(int)
            df['%-trend_regime'] = (df['%-ema_20'] > df['%-ema_50']).astype(int)
            
            # ===== CLEANING AND VALIDATION =====
            freqai_columns = [col for col in df.columns if col.startswith('%-')]
            for col in freqai_columns:
                df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0).replace([np.inf, -np.inf], 0)
            
            logger.info(f"[CX Smart Money FreqAI] feature_engineering_expand_all output shape: {df.shape}")
            if df.empty:
                logger.warning("[CX Smart Money FreqAI] feature_engineering_expand_all returned empty DataFrame!")
                df = pd.DataFrame(0, index=range(10), columns=[f'%-dummy_{i}' for i in range(5)])
            return df
        except Exception as e:
            logger.warning(f"Error in CX Smart Money feature_engineering_expand_all: {e}")
            return df

    def _add_specialized_freqai_features(self, df: DataFrame, metadata: Dict) -> None:
        """
        Advanced specialized FreqAI features for CX Smart Money Strategy
        Creates pair-specific features for BTC, ETH, XRP, DOGE, ADA
        """
        try:
            pair = metadata.get('pair', '')
            
            # ===== BTC-SPECIFIC FEATURES =====
            if 'BTC' in pair:
                # Bitcoin dominance and market leadership
                df['%-btc_dominance'] = ta.SMA(df['close'], timeperiod=50) / ta.SMA(df['close'], timeperiod=200)
                df['%-btc_volatility'] = df['close'].rolling(20).std() / df['close'].rolling(20).mean()
                df['%-btc_market_cap_ratio'] = df['volume'] * df['close'] / (df['volume'] * df['close']).rolling(100).mean()
                
                # Bitcoin-specific momentum
                df['%-btc_momentum_1h'] = df['close'].pct_change(12)  # 1 hour momentum
                df['%-btc_momentum_4h'] = df['close'].pct_change(48)  # 4 hour momentum
                df['%-btc_momentum_1d'] = df['close'].pct_change(288)  # 1 day momentum
                
                # Bitcoin institutional flows
                df['%-btc_institutional_volume'] = df['volume'].rolling(24).mean() / df['volume'].rolling(168).mean()
                df['%-btc_whale_activity'] = (df['volume'] > df['volume'].rolling(100).quantile(0.95)).astype(int)
                
                # Bitcoin market structure
                df['%-btc_support_level'] = df['low'].rolling(20).min() / df['close']
                df['%-btc_resistance_level'] = df['high'].rolling(20).max() / df['close']
                df['%-btc_price_efficiency'] = abs(df['close'] - df['close'].shift(20)) / df['close'].rolling(20).std()
            
            # ===== ETH-SPECIFIC FEATURES =====
            elif 'ETH' in pair:
                # Ethereum gas and DeFi metrics
                df['%-eth_gas_ratio'] = df['volume'] / df['volume'].rolling(50).mean()
                df['%-eth_defi_volume'] = df['volume'] * df['close']
                df['%-eth_smart_contract_activity'] = df['volume'].pct_change().rolling(10).std()
                
                # Ethereum staking and yield
                df['%-eth_staking_ratio'] = df['close'].rolling(25).mean() / df['close'].rolling(100).mean()
                df['%-eth_defi_yield'] = df['volume'].rolling(7).mean() / df['volume'].rolling(30).mean()
                
                # Ethereum network activity
                df['%-eth_network_growth'] = df['volume'].pct_change().rolling(24).mean()
                df['%-eth_layer2_activity'] = df['volume'].rolling(12).std() / df['volume'].rolling(48).std()
                
                # Ethereum market structure
                df['%-eth_support_level'] = df['low'].rolling(20).min() / df['close']
                df['%-eth_resistance_level'] = df['high'].rolling(20).max() / df['close']
                df['%-eth_price_efficiency'] = abs(df['close'] - df['close'].shift(20)) / df['close'].rolling(20).std()
            
            # ===== XRP-SPECIFIC FEATURES =====
            elif 'XRP' in pair:
                # Ripple network and cross-border metrics
                df['%-xrp_ripple_volume'] = df['volume'] / df['volume'].rolling(100).mean()
                df['%-xrp_network_activity'] = df['close'].pct_change().rolling(10).std()
                df['%-xrp_cross_border_volume'] = df['volume'].rolling(24).sum() / df['volume'].rolling(168).sum()
                
                # XRP institutional adoption
                df['%-xrp_institutional_flow'] = df['volume'].rolling(48).mean() / df['volume'].rolling(336).mean()
                df['%-xrp_regulatory_sentiment'] = df['close'].pct_change().rolling(5).mean()
                
                # XRP market structure
                df['%-xrp_support_level'] = df['low'].rolling(20).min() / df['close']
                df['%-xrp_resistance_level'] = df['high'].rolling(20).max() / df['close']
                df['%-xrp_price_efficiency'] = abs(df['close'] - df['close'].shift(20)) / df['close'].rolling(20).std()
            
            # ===== DOGE-SPECIFIC FEATURES =====
            elif 'DOGE' in pair:
                # Dogecoin meme and social metrics
                df['%-doge_meme_volume'] = df['volume'] / df['volume'].rolling(24).mean()
                df['%-doge_social_sentiment'] = df['close'].pct_change().rolling(5).mean()
                df['%-doge_viral_coefficient'] = df['volume'].pct_change().rolling(3).std()
            
            # ===== ADA-SPECIFIC FEATURES =====
            elif 'ADA' in pair:
                # Cardano staking and governance metrics
                df['%-ada_staking_ratio'] = df['volume'] / df['volume'].rolling(100).mean()
                df['%-ada_governance_activity'] = df['close'].pct_change().rolling(10).std()
                df['%-ada_cardano_ecosystem'] = df['volume'].rolling(24).mean() / df['volume'].rolling(168).mean()
                
                # ADA market structure
                df['%-ada_support_level'] = df['low'].rolling(20).min() / df['close']
                df['%-ada_resistance_level'] = df['high'].rolling(20).max() / df['close']
                df['%-ada_price_efficiency'] = abs(df['close'] - df['close'].shift(20)) / df['close'].rolling(20).std()
            
            # ===== GENERAL CRYPTO MARKET FEATURES =====
            df['%-market_sentiment'] = df['%-rsi'] * df['%-volume_pct']
            df['%-volatility_regime'] = df['%-atr'] / df['close'].rolling(100).mean()
            df['%-trend_consistency'] = df['%-ema_20'].rolling(10).std()
            
        except Exception as e:
            logger.warning(f"Error in specialized FreqAI features: {e}")

    def _add_model_pipeline_features(self, df: DataFrame, metadata: Dict) -> None:
        """
        Add model pipeline specific features for enhanced prediction
        """
        try:
            if not MODEL_PIPELINE_AVAILABLE or cx_smart_money_pipeline is None:
                return
            
            # Get pipeline status
            pipeline_status = cx_smart_money_pipeline.get_pipeline_status()
            
            # Add model confidence features
            df['%-model_confidence'] = pipeline_status.get('qualification_rate', 0.0)
            df['%-ensemble_weight'] = len(pipeline_status.get('qualified_model_names', [])) / 5.0  # Normalize to 0-1
            df['%-prediction_consensus'] = pipeline_status.get('pipeline_ready', False) * 1.0
            
            # Add model performance features
            if pipeline_status.get('performance_metrics'):
                avg_accuracy = np.mean([
                    metrics.get('accuracy', 0.0) 
                    for metrics in pipeline_status['performance_metrics'].values()
                ])
                df['%-avg_model_accuracy'] = avg_accuracy
                df['%-model_performance_stability'] = 1.0 - np.std([
                    metrics.get('accuracy', 0.0) 
                    for metrics in pipeline_status['performance_metrics'].values()
                ])
            else:
                df['%-avg_model_accuracy'] = 0.0
                df['%-model_performance_stability'] = 0.0
            
            # Add ensemble diversity features
            qualified_models = pipeline_status.get('qualified_model_names', [])
            df['%-model_diversity'] = len(qualified_models) / 5.0  # Normalize to 0-1
            
            # Add time-based features
            if pipeline_status.get('last_validation'):
                time_since_validation = (datetime.now() - pipeline_status['last_validation']).total_seconds() / 3600
                df['%-hours_since_validation'] = time_since_validation
                df['%-validation_freshness'] = max(0, 1.0 - (time_since_validation / 24.0))  # Decay over 24 hours
            else:
                df['%-hours_since_validation'] = 24.0
                df['%-validation_freshness'] = 0.0
            
            logger.debug(f"Added model pipeline features for {metadata.get('pair', 'unknown')}")
            
        except Exception as e:
            logger.warning(f"Error adding model pipeline features: {e}")

    def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame:
        logger.info(f"[FreqAI] feature_engineering_standard called. Input shape: {dataframe.shape}")
        df = dataframe.copy()
        try:
            # Core features (existing)
            df['%-pct-change'] = df['close'].pct_change()
            df['%-rsi'] = ta.RSI(df, timeperiod=14)
            df['%-sma-15'] = ta.SMA(df, timeperiod=15)
            df['%-cti'] = ta.CCI(df, timeperiod=20)
            df['%-rsi_fast'] = ta.RSI(df, timeperiod=4)
            df['%-rsi_slow'] = ta.RSI(df, timeperiod=20)
            
            # Stochastic (existing)
            stoch_fast = ta.STOCHF(df, 5, 3, 0, 3, 0)
            df['%-fastk'] = stoch_fast['fastk']
            df['%-fastd'] = stoch_fast['fastd']
            
            # NEW: Missing indicators from populate_indicators
            df['%-ema_20'] = ta.EMA(df, timeperiod=20)
            df['%-volume_ma'] = ta.SMA(df['volume'], timeperiod=20)
            df['%-atr'] = ta.ATR(df, timeperiod=14)
            
            # NEW: Basic Bollinger Bands
            bb = ta.BBANDS(df, 20)
            if isinstance(bb, pd.DataFrame):
                df['%-bb_upper'] = bb['upperband']
            else:
                df['%-bb_upper'] = 0
            
            # NEW: Basic MACD
            macd = ta.MACD(df)
            df['%-macd'] = macd['macd']
            
            # NEW: Basic ADX
            df['%-adx'] = ta.ADX(df)
            
            # NEW: Basic CCI
            df['%-cci'] = ta.CCI(df)
            
            # NEW: EMA difference (used in strategy)
            df['%-ema_diff'] = (df['close'] - df['%-ema_20']) / df['%-ema_20']
            
            # NEW: VWAP
            try:
                # Custom VWAP implementation using pandas
                typical_price = (df['high'] + df['low'] + df['close']) / 3
                df['%-vwap'] = (typical_price * df['volume']).rolling(window=20).sum() / df['volume'].rolling(window=20).sum()
                df['%-vwap'] = df['%-vwap'].fillna(df['close'])
            except Exception:
                df['%-vwap'] = df['close']
            
            # Clean FreqAI features
            freqai_columns = [col for col in df.columns if col.startswith('%-')]
            for col in freqai_columns:
                df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
            
            logger.info(f"[FreqAI] feature_engineering_standard output shape: {df.shape}")
            if df.empty:
                logger.warning("[FreqAI] feature_engineering_standard returned empty DataFrame! Filling with zeros.")
                df = pd.DataFrame(0, index=range(10), columns=[f'%-dummy_{i}' for i in range(5)])
            return df
        except Exception as e:
            logger.warning(f"Error in feature_engineering_standard: {e}")
            return df

    def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
        """
        Advanced target engineering for CX Smart Money Strategy
        Creates comprehensive targets for multi-timeframe prediction
        """
        logger.info(f"[CX Smart Money FreqAI] set_freqai_targets called. Input shape: {dataframe.shape}")
        df = dataframe.copy()
        try:
            # ===== PRICE TARGETS =====
            # Short-term price targets (1-5 periods)
            df['&-s_close_1'] = df['close'].shift(-1) / df['close']
            df['&-s_close_2'] = df['close'].shift(-2) / df['close']
            df['&-s_close_5'] = df['close'].shift(-5) / df['close']
            
            # Medium-term price targets (10-20 periods)
            df['&-s_close_10'] = df['close'].shift(-10) / df['close']
            df['&-s_close_15'] = df['close'].shift(-15) / df['close']
            df['&-s_close_20'] = df['close'].shift(-20) / df['close']
            
            # Long-term price targets (30-50 periods)
            df['&-s_close_30'] = df['close'].shift(-30) / df['close']
            df['&-s_close_50'] = df['close'].shift(-50) / df['close']
            
            # ===== DIRECTIONAL TARGETS =====
            # Binary directional targets
            df['&-s_direction_1'] = (df['close'].shift(-1) > df['close']).astype(int)
            df['&-s_direction_5'] = (df['close'].shift(-5) > df['close']).astype(int)
            df['&-s_direction_10'] = (df['close'].shift(-10) > df['close']).astype(int)
            df['&-s_direction_20'] = (df['close'].shift(-20) > df['close']).astype(int)
            
            # Multi-class directional targets (Strong Buy, Buy, Hold, Sell, Strong Sell)
            price_change_1 = df['close'].shift(-1) / df['close'] - 1
            direction_class = pd.cut(price_change_1, 
                                    bins=[-np.inf, -0.02, -0.005, 0.005, 0.02, np.inf],
                                    labels=[0, 1, 2, 3, 4])
            # Fix: handle NaN by assigning -1, then convert to int
            df['&-s_direction_class_1'] = direction_class.cat.add_categories([-1]).fillna(-1).astype(int)
            
            # ===== VOLATILITY TARGETS =====
            # Rolling volatility targets
            df['&-s_volatility_1'] = df['close'].rolling(5).std().shift(-1) / df['close']
            df['&-s_volatility_5'] = df['close'].rolling(5).std().shift(-5) / df['close']
            df['&-s_volatility_10'] = df['close'].rolling(10).std().shift(-10) / df['close']
            df['&-s_volatility_20'] = df['close'].rolling(20).std().shift(-20) / df['close']
            
            # ===== HIGH/LOW TARGETS =====
            # Support and resistance targets
            df['&-s_high_5'] = df['high'].rolling(5).max().shift(-5) / df['close']
            df['&-s_low_5'] = df['low'].rolling(5).min().shift(-5) / df['close']
            df['&-s_high_10'] = df['high'].rolling(10).max().shift(-10) / df['close']
            df['&-s_low_10'] = df['low'].rolling(10).min().shift(-10) / df['close']
            
            # ===== VOLUME TARGETS =====
            # Volume change targets
            df['&-s_volume_1'] = df['volume'].shift(-1) / df['volume']
            df['&-s_volume_5'] = df['volume'].shift(-5) / df['volume']
            df['&-s_volume_10'] = df['volume'].shift(-10) / df['volume']
            
            # ===== TECHNICAL INDICATOR TARGETS =====
            # RSI targets
            rsi = ta.RSI(df, timeperiod=14)
            df['&-s_rsi_1'] = rsi.shift(-1)
            df['&-s_rsi_5'] = rsi.shift(-5)
            df['&-s_rsi_10'] = rsi.shift(-10)
            
            # MACD targets
            macd = ta.MACD(df)
            df['&-s_macd_1'] = macd['macd'].shift(-1)
            df['&-s_macd_5'] = macd['macd'].shift(-5)
            
            # ===== MOMENTUM TARGETS =====
            # Price momentum targets
            df['&-s_momentum_1'] = df['close'].pct_change().shift(-1)
            df['&-s_momentum_5'] = df['close'].pct_change(5).shift(-5)
            df['&-s_momentum_10'] = df['close'].pct_change(10).shift(-10)
            
            # ===== TREND TARGETS =====
            # Trend strength targets
            df['&-s_trend_5'] = (df['close'].shift(-5) - df['close']) / df['close']
            df['&-s_trend_10'] = (df['close'].shift(-10) - df['close']) / df['close']
            df['&-s_trend_20'] = (df['close'].shift(-20) - df['close']) / df['close']
            
            # ===== SUPPORT/RESISTANCE TARGETS =====
            # Dynamic support/resistance levels
            df['&-s_resistance_5'] = df['high'].rolling(20).max().shift(-5) / df['close']
            df['&-s_support_5'] = df['low'].rolling(20).min().shift(-5) / df['close']
            df['&-s_resistance_10'] = df['high'].rolling(20).max().shift(-10) / df['close']
            df['&-s_support_10'] = df['low'].rolling(20).min().shift(-10) / df['close']
            
            # ===== ADVANCED TARGETS =====
            # Price efficiency targets
            df['&-s_price_efficiency_5'] = abs(df['close'].shift(-5) - df['close']) / df['close'].rolling(5).std()
            df['&-s_price_efficiency_10'] = abs(df['close'].shift(-10) - df['close']) / df['close'].rolling(10).std()
            
            # Market regime targets
            df['&-s_bull_market_5'] = (df['close'].shift(-5) > df['close'] * 1.02).astype(int)
            df['&-s_bear_market_5'] = (df['close'].shift(-5) < df['close'] * 0.98).astype(int)
            
            # Volatility regime targets
            df['&-s_high_volatility_5'] = (df['close'].rolling(5).std().shift(-5) > df['close'].rolling(20).std()).astype(int)
            df['&-s_low_volatility_5'] = (df['close'].rolling(5).std().shift(-5) < df['close'].rolling(20).std() * 0.5).astype(int)
            
            # ===== SPECIALIZED PAIR TARGETS =====
            self._add_specialized_freqai_targets(df)
            
            # ===== CLEANING AND VALIDATION =====
            # Clean target columns
            target_columns = [col for col in df.columns if col.startswith('&-s_')]
            for col in target_columns:
                df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0).replace([np.inf, -np.inf], 0)
            
            logger.info(f"[CX Smart Money FreqAI] set_freqai_targets output shape: {df.shape}")
            if df.empty:
                logger.warning("[CX Smart Money FreqAI] set_freqai_targets returned empty DataFrame!")
                df = pd.DataFrame(0, index=range(10), columns=['&-s_dummy_0'])
            return df
        except Exception as e:
            logger.warning(f"Error in CX Smart Money set_freqai_targets: {e}")
            return df

    def _add_specialized_freqai_targets(self, df: DataFrame) -> None:
        """
        Advanced specialized FreqAI targets for CX Smart Money Strategy
        Creates pair-specific targets for BTC, ETH, XRP, DOGE, ADA
        """
        try:
            # ===== BTC-SPECIFIC TARGETS =====
            # Bitcoin dominance and market leadership targets
            df['&-s_btc_dominance_5'] = (ta.SMA(df['close'], timeperiod=50) / ta.SMA(df['close'], timeperiod=200)).shift(-5)
            df['&-s_btc_dominance_10'] = (ta.SMA(df['close'], timeperiod=50) / ta.SMA(df['close'], timeperiod=200)).shift(-10)
            df['&-s_btc_volatility_5'] = (df['close'].rolling(20).std() / df['close'].rolling(20).mean()).shift(-5)
            df['&-s_btc_volatility_10'] = (df['close'].rolling(20).std() / df['close'].rolling(20).mean()).shift(-10)
            
            # Bitcoin institutional flow targets
            df['&-s_btc_institutional_volume_5'] = (df['volume'].rolling(24).mean() / df['volume'].rolling(168).mean()).shift(-5)
            df['&-s_btc_whale_activity_5'] = ((df['volume'] > df['volume'].rolling(100).quantile(0.95)).astype(int)).shift(-5)
            
            # Bitcoin market structure targets
            df['&-s_btc_support_level_5'] = (df['low'].rolling(20).min() / df['close']).shift(-5)
            df['&-s_btc_resistance_level_5'] = (df['high'].rolling(20).max() / df['close']).shift(-5)
            df['&-s_btc_price_efficiency_5'] = (abs(df['close'] - df['close'].shift(20)) / df['close'].rolling(20).std()).shift(-5)
            
            # ===== ETH-SPECIFIC TARGETS =====
            # Ethereum DeFi and gas targets
            df['&-s_eth_gas_ratio_5'] = (df['volume'] / df['volume'].rolling(50).mean()).shift(-5)
            df['&-s_eth_gas_ratio_10'] = (df['volume'] / df['volume'].rolling(50).mean()).shift(-10)
            df['&-s_eth_defi_volume_5'] = (df['volume'] * df['close']).shift(-5)
            df['&-s_eth_defi_volume_10'] = (df['volume'] * df['close']).shift(-10)
            
            # Ethereum staking and yield targets
            df['&-s_eth_staking_ratio_5'] = (df['close'].rolling(25).mean() / df['close'].rolling(100).mean()).shift(-5)
            df['&-s_eth_defi_yield_5'] = (df['volume'].rolling(7).mean() / df['volume'].rolling(30).mean()).shift(-5)
            
            # Ethereum network activity targets
            df['&-s_eth_network_growth_5'] = (df['volume'].pct_change().rolling(24).mean()).shift(-5)
            df['&-s_eth_layer2_activity_5'] = (df['volume'].rolling(12).std() / df['volume'].rolling(48).std()).shift(-5)
            
            # ===== XRP-SPECIFIC TARGETS =====
            # Ripple network and cross-border targets
            df['&-s_xrp_ripple_volume_5'] = (df['volume'] / df['volume'].rolling(100).mean()).shift(-5)
            df['&-s_xrp_ripple_volume_10'] = (df['volume'] / df['volume'].rolling(100).mean()).shift(-10)
            df['&-s_xrp_network_activity_5'] = df['close'].pct_change().rolling(10).std().shift(-5)
            df['&-s_xrp_cross_border_volume_5'] = (df['volume'].rolling(24).sum() / df['volume'].rolling(168).sum()).shift(-5)
            
            # XRP institutional adoption targets
            df['&-s_xrp_institutional_flow_5'] = (df['volume'].rolling(48).mean() / df['volume'].rolling(336).mean()).shift(-5)
            df['&-s_xrp_regulatory_sentiment_5'] = (df['close'].pct_change().rolling(5).mean()).shift(-5)
            
            # ===== DOGE-SPECIFIC TARGETS =====
            # Dogecoin meme and social targets
            df['&-s_doge_meme_volume_5'] = (df['volume'] / df['volume'].rolling(24).mean()).shift(-5)
            df['&-s_doge_social_sentiment_5'] = (df['close'].pct_change().rolling(5).mean()).shift(-5)
            df['&-s_doge_viral_coefficient_5'] = (df['volume'].pct_change().rolling(3).std()).shift(-5)
            
            # Dogecoin community activity targets
            df['&-s_doge_community_engagement_5'] = (df['volume'].rolling(6).mean() / df['volume'].rolling(24).mean()).shift(-5)
            df['&-s_doge_celebrity_impact_5'] = (df['volume'].pct_change().rolling(2).std()).shift(-5)
            
            # ===== ADA-SPECIFIC TARGETS =====
            # Cardano staking and governance targets
            df['&-s_ada_cardano_volume_5'] = (df['volume'] / df['volume'].rolling(75).mean()).shift(-5)
            df['&-s_ada_cardano_volume_10'] = (df['volume'] / df['volume'].rolling(75).mean()).shift(-10)
            df['&-s_ada_staking_ratio_5'] = (df['close'].rolling(25).mean() / df['close'].rolling(100).mean()).shift(-5)
            df['&-s_ada_governance_activity_5'] = (df['volume'].rolling(7).mean() / df['volume'].rolling(30).mean()).shift(-5)
            
            # Cardano development activity targets
            df['&-s_ada_development_momentum_5'] = (df['volume'].pct_change().rolling(14).mean()).shift(-5)
            df['&-s_ada_ecosystem_growth_5'] = (df['volume'].rolling(21).mean() / df['volume'].rolling(84).mean()).shift(-5)
            
            # ===== COMMON SPECIALIZED TARGETS FOR ALL PAIRS =====
            # Advanced momentum targets
            df['&-s_momentum_acceleration_5'] = (df['close'].pct_change().diff()).shift(-5)
            df['&-s_momentum_strength_5'] = (df['close'].pct_change().rolling(10).std()).shift(-5)
            
            # Advanced volatility targets
            df['&-s_volatility_skew_5'] = (df['close'].rolling(20).std().rolling(20).skew()).shift(-5)
            df['&-s_volatility_regime_5'] = ((df['close'].rolling(5).std() > df['close'].rolling(20).std()).astype(int)).shift(-5)
            
            # Advanced trend targets
            df['&-s_trend_consistency_5'] = ((df['close'] > df['close'].shift(10)).rolling(10).mean()).shift(-5)
            df['&-s_trend_strength_5'] = (abs(df['close'] - df['close'].shift(10)) / df['close'].rolling(10).std()).shift(-5)
            
            # Advanced market efficiency targets
            df['&-s_market_efficiency_5'] = (abs(df['close'] - df['close'].shift(10)) / df['close'].rolling(10).std()).shift(-5)
            df['&-s_market_microstructure_5'] = (df['volume'].rolling(5).std() / df['volume'].rolling(20).std()).shift(-5)
            
            # Advanced support/resistance targets
            df['&-s_support_strength_5'] = ((df['close'] - df['low'].rolling(20).min()) / df['close']).shift(-5)
            df['&-s_resistance_strength_5'] = ((df['high'].rolling(20).max() - df['close']) / df['close']).shift(-5)
            df['&-s_price_position_5'] = ((df['close'] - df['low'].rolling(20).min()) / (df['high'].rolling(20).max() - df['low'].rolling(20).min())).shift(-5)
            
            # Advanced volume analysis targets
            df['&-s_volume_trend_5'] = (df['volume'].rolling(10).mean() / df['volume'].rolling(50).mean()).shift(-5)
            df['&-s_volume_volatility_5'] = (df['volume'].rolling(10).std() / df['volume'].rolling(10).mean()).shift(-5)
            df['&-s_volume_price_correlation_5'] = (df['volume'].rolling(20).corr(df['close'])).shift(-5)
            
            # Advanced momentum analysis targets
            df['&-s_momentum_divergence_5'] = ((df['close'].pct_change() - df['close'].pct_change().rolling(10).mean())).shift(-5)
            df['&-s_momentum_regime_5'] = (((df['close'].pct_change() > 0).astype(int) - (df['close'].pct_change() < 0).astype(int)).rolling(5).mean()).shift(-5)
            
        except Exception as e:
            logger.warning(f"Error in CX Smart Money specialized FreqAI targets: {e}")

    def populate_any_indicators(self, pair: str, df: DataFrame, tf: str) -> DataFrame:
        """
        Enhanced populate any indicators for FreqAI
        """
        try:
            # Core features (existing)
            df['%-pct-change'] = df['close'].pct_change()
            df['%-rsi'] = ta.RSI(df, timeperiod=14)
            df['%-sma-15'] = ta.SMA(df, timeperiod=15)
            df['%-cti'] = ta.CCI(df, timeperiod=20)
            df['%-rsi_fast'] = ta.RSI(df, timeperiod=4)
            df['%-rsi_slow'] = ta.RSI(df, timeperiod=20)

            # Stochastic (existing)
            stoch_fast = ta.STOCHF(df, 5, 3, 0, 3, 0)
            df['%-fastk'] = stoch_fast['fastk']
            df['%-fastd'] = stoch_fast['fastd']
            
            # NEW: Missing indicators from populate_indicators
            df['%-ema_20'] = ta.EMA(df, timeperiod=20)
            df['%-volume_ma'] = ta.SMA(df['volume'], timeperiod=20)
            df['%-atr'] = ta.ATR(df, timeperiod=14)
            
            # NEW: Basic indicators
            df['%-macd'] = ta.MACD(df)['macd']
            df['%-adx'] = ta.ADX(df)
            df['%-cci'] = ta.CCI(df)
            
            # NEW: EMA difference (used in strategy)
            df['%-ema_diff'] = (df['close'] - df['%-ema_20']) / df['%-ema_20']
            
            # NEW: VWAP
            try:
                # Custom VWAP implementation using pandas
                typical_price = (df['high'] + df['low'] + df['close']) / 3
                df['%-vwap'] = (typical_price * df['volume']).rolling(window=20).sum() / df['volume'].rolling(window=20).sum()
                df['%-vwap'] = df['%-vwap'].fillna(df['close'])
            except Exception:
                df['%-vwap'] = df['close']

            return df
            
        except Exception as e:
            logger.warning(f"Error in populate_any_indicators: {e}")
            return df

    # Enhanced protections
    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 5
            },
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": 48,
                "trade_limit": 20,
                "stop_duration_candles": 4,
                "max_allowed_drawdown": 0.2
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": 2,
                "only_per_pair": False
            }
        ]

    # Optimal hyperopt ranges (from historical optimization)
    @property
    def buy_params(self):
        return {
            "buy_rsi_fast_32": 26,
            "buy_rsi_32": 46,
            "buy_sma15_32": 1.0016,
            "buy_cti_32": -0.615,
            "buy_volume_32": 0.881,
            "buy_ema_diff_32": -0.004,
            "dca_multiplier": 0.587,
            "dca_threshold": -0.023,
            "profit_take_threshold": 0.047,
        }

    @property
    def sell_params(self):
        return {
            "exit_fastk_threshold": 89,
            "exit_rsi_threshold": 77,
            "exit_cti_threshold": 0.407,
            "exit_profit_threshold": 0.012,
            "trailing_stop_positive": 0.198,
            "trailing_stop_positive_offset": 0.212
        } 