# source: https://raw.githubusercontent.com/vigoferrel/qbtc-unified/ef7ffc8f45cc7ab041884cd0c08a2043acc1f0cb/freqtrade_qbtc/strategies/QBTCMarkovFeynman.py
"""
Github_vigoferrel_qbtc_unified__QBTCMarkovFeynman__20251009_202533 - Estrategia Macro con Transformaciones Matemáticas
====================================================================

FILOSOFÍA MATEMÁTICA:
- Transformación Prima → Markov: Estados discretos probabilísticos
- Integrales de Feynman: Suma de todos los caminos posibles del precio
- Frecuencias Bajas: 1H+ para capturar señales macro reales
- Visión de Largo Plazo: Tendencias estructurales, no ruido

FUNDAMENTOS TEÓRICOS:
1. Estados de Markov: {ACCUMULATION, MARKUP, DISTRIBUTION, MARKDOWN}
2. Integrales de Camino: Probabilidad de transición entre estados
3. Transformadas Primas: Descomposición espectral del precio
4. Análisis Macro: Ciclos económicos y estructurales

Target: >70% win rate macro, >15% profit trimestral

Creado: 2025-09-10
Autor: QBTC Trading System - Markov-Feynman Implementation
"""

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
from scipy import stats
from scipy.fft import fft, fftfreq
import math

class Github_vigoferrel_qbtc_unified__QBTCMarkovFeynman__20251009_202533(IStrategy):
    
    # Metadatos para análisis macro
    INTERFACE_VERSION = 3
    timeframe = '1h'  # FREQUENCY TRANSFORMATION: Macro timeframe
    can_short = False
    stoploss = -0.08  # 8% - Wide stop for macro moves
    
    # ROI macro - Hold for structural moves
    minimal_roi = {
        "0": 0.25,      # 25% for parabolic moves
        "720": 0.15,    # 15% after 12 hours (macro confirmation)
        "1440": 0.08,   # 8% after 24 hours
        "4320": 0.05,   # 5% after 3 days
        "10080": 0.02   # 2% after 1 week
    }
    
    # Configuración macro
    max_open_trades = 2  # Focus on quality macro setups
    stake_currency = 'USDT'
    stake_amount = 100
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = True  # Hold during macro trends
    
    # Orders for macro execution
    order_types = {
        'entry': 'limit',  # Better fills for macro positions
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': True
    }
    
    # MARKOV STATE PARAMETERS
    accumulation_lookback = IntParameter(168, 336, default=240, space="buy")  # 10-14 days
    markup_strength = DecimalParameter(0.05, 0.15, default=0.08, space="buy")  # 8% move
    volume_regime = DecimalParameter(0.8, 2.0, default=1.2, space="buy")
    
    # FEYNMAN PATH INTEGRATION PARAMETERS
    path_integral_periods = IntParameter(50, 200, default=100, space="buy")
    spectral_threshold = DecimalParameter(0.02, 0.08, default=0.04, space="buy")
    
    # MACRO EXIT PARAMETERS
    distribution_signal = DecimalParameter(0.15, 0.30, default=0.20, space="sell")
    markdown_confirmation = IntParameter(12, 48, default=24, space="sell")
    
    def __init__(self, config: dict) -> None:
        super().__init__(config)
        self.logger = logging.getLogger(__name__)
        
        # Markov State Tracking
        self._current_state = 'UNDEFINED'
        self._state_duration = 0
        self._state_confidence = 0.0
        
        # Feynman Path Integration
        self._price_paths = []
        self._path_probabilities = []
        
        # Prime Transformation Cache
        self._spectral_components = {}
        self._harmonic_analysis = {}
        
        # Macro Cycle Tracking
        self._cycle_phase = 'UNKNOWN'
        self._macro_momentum = 0.0
        
        self.logger.info("🔬 MARKOV-FEYNMAN STRATEGY INITIALIZED")
        self.logger.info("📊 Frequency Domain: 1H macro analysis")
        self.logger.info("🎯 Target: Structural market transitions")
        
    def informative_pairs(self):
        return []
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        MARKOV-FEYNMAN MATHEMATICAL TRANSFORMATION
        1. Prime Transformation → Spectral Analysis
        2. Markov Chain State Detection
        3. Feynman Path Integration
        """
        
        pair = metadata['pair']
        self.logger.info(f"🔬 Applying Markov-Feynman transformation to {pair}")
        
        # === BASIC PRICE ANALYSIS ===
        dataframe['returns'] = dataframe['close'].pct_change()
        dataframe['log_returns'] = np.log(dataframe['close'] / dataframe['close'].shift(1))
        dataframe['cumulative_returns'] = (1 + dataframe['returns']).cumprod()
        
        # === VOLUME REGIME ANALYSIS ===
        dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=48)  # 2 days
        dataframe['volume_regime'] = dataframe['volume'] / dataframe['volume_sma']
        dataframe['volume_trend'] = ta.EMA(dataframe['volume_regime'], timeperiod=24)
        
        # === PRIME TRANSFORMATION → SPECTRAL ANALYSIS ===
        self._apply_prime_transformation(dataframe)
        
        # === MARKOV CHAIN STATE DETECTION ===
        self._detect_markov_states(dataframe)
        
        # === FEYNMAN PATH INTEGRATION ===
        self._calculate_path_integrals(dataframe)
        
        # === MACRO STRUCTURE ANALYSIS ===
        dataframe['price_level'] = dataframe['close'] / dataframe['close'].rolling(window=self.accumulation_lookback.value).mean()
        dataframe['volatility_regime'] = dataframe['returns'].rolling(window=48).std()
        
        # Higher timeframe EMAs for macro structure
        dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50)   # ~2 days
        dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) # ~8 days  
        dataframe['ema_500'] = ta.EMA(dataframe, timeperiod=500) # ~3 weeks
        
        # Macro momentum
        dataframe['macro_momentum'] = (dataframe['close'] - dataframe['close'].shift(168)) / dataframe['close'].shift(168)  # 1 week
        
        return dataframe
    
    def _apply_prime_transformation(self, dataframe: DataFrame):
        """
        PRIME TRANSFORMATION → FOURIER SPECTRAL ANALYSIS
        Decompose price series into harmonic components
        """
        
        if len(dataframe) < 100:
            return
            
        # Get price series
        prices = dataframe['close'].values[-self.path_integral_periods.value:]
        
        # Apply FFT (Prime → Frequency domain)
        fft_values = fft(prices)
        frequencies = fftfreq(len(prices))
        
        # Calculate spectral power
        spectral_power = np.abs(fft_values) ** 2
        
        # Find dominant frequencies
        dominant_indices = np.argsort(spectral_power)[-5:]  # Top 5 harmonics
        
        # Store spectral components
        dataframe.loc[dataframe.index[-len(prices):], 'spectral_power'] = spectral_power[:len(prices)]
        dataframe.loc[dataframe.index[-len(prices):], 'dominant_frequency'] = frequencies[dominant_indices[0]] if len(dominant_indices) > 0 else 0
        
        # Calculate spectral centroid (center of spectral mass)
        if np.sum(spectral_power) > 0:
            spectral_centroid = np.sum(frequencies * spectral_power) / np.sum(spectral_power)
            dataframe.loc[dataframe.index[-1], 'spectral_centroid'] = abs(spectral_centroid)
        
        # Store in cache for analysis
        self._spectral_components = {
            'power': spectral_power,
            'frequencies': frequencies,
            'dominant': dominant_indices
        }
    
    def _detect_markov_states(self, dataframe: DataFrame):
        """
        MARKOV CHAIN STATE DETECTION
        States: ACCUMULATION → MARKUP → DISTRIBUTION → MARKDOWN
        """
        
        if len(dataframe) < 50:
            return
            
        # Calculate state indicators
        price_velocity = dataframe['close'].diff(12)  # 12h price change
        price_acceleration = price_velocity.diff(6)   # 6h acceleration change
        volume_surge = dataframe['volume_regime'] > self.volume_regime.value
        
        # Initialize state columns
        dataframe['markov_state'] = 'UNDEFINED'
        dataframe['state_confidence'] = 0.0
        dataframe['state_transition_prob'] = 0.0
        
        for i in range(50, len(dataframe)):
            current_idx = dataframe.index[i]
            
            # Get recent data window
            window = dataframe.iloc[i-24:i]  # 24h window
            
            price_change = (dataframe.loc[current_idx, 'close'] - dataframe.iloc[i-24]['close']) / dataframe.iloc[i-24]['close']
            volatility = window['returns'].std()
            avg_volume = window['volume_regime'].mean()
            
            # STATE DETECTION LOGIC
            
            # ACCUMULATION: Low volatility, sideways price, below average volume
            if (abs(price_change) < 0.05 and 
                volatility < dataframe['volatility_regime'].quantile(0.3) and
                avg_volume < 1.0):
                state = 'ACCUMULATION'
                confidence = 0.8
                
            # MARKUP: Strong upward move, increasing volume
            elif (price_change > self.markup_strength.value and
                  avg_volume > self.volume_regime.value and
                  price_velocity.iloc[i] > 0):
                state = 'MARKUP'
                confidence = 0.9
                
            # DISTRIBUTION: High prices, high volatility, decreasing momentum
            elif (dataframe.loc[current_idx, 'price_level'] > 1.15 and
                  volatility > dataframe['volatility_regime'].quantile(0.7) and
                  price_acceleration.iloc[i] < 0):
                state = 'DISTRIBUTION'
                confidence = 0.85
                
            # MARKDOWN: Strong downward move, panic volume
            elif (price_change < -0.08 and
                  avg_volume > 1.5 and
                  price_velocity.iloc[i] < 0):
                state = 'MARKDOWN'
                confidence = 0.9
                
            else:
                state = 'TRANSITION'
                confidence = 0.3
            
            dataframe.loc[current_idx, 'markov_state'] = state
            dataframe.loc[current_idx, 'state_confidence'] = confidence
            
            # Calculate transition probability using Bayesian inference
            if i > 50:
                prev_state = dataframe.iloc[i-1]['markov_state']
                transition_prob = self._calculate_transition_probability(prev_state, state)
                dataframe.loc[current_idx, 'state_transition_prob'] = transition_prob
    
    def _calculate_transition_probability(self, prev_state: str, current_state: str) -> float:
        """
        Calculate Markov transition probabilities
        """
        
        # Empirical transition matrix (simplified)
        transitions = {
            ('ACCUMULATION', 'MARKUP'): 0.7,
            ('ACCUMULATION', 'ACCUMULATION'): 0.25,
            ('MARKUP', 'DISTRIBUTION'): 0.6,
            ('MARKUP', 'MARKUP'): 0.3,
            ('DISTRIBUTION', 'MARKDOWN'): 0.5,
            ('DISTRIBUTION', 'ACCUMULATION'): 0.3,
            ('MARKDOWN', 'ACCUMULATION'): 0.8,
            ('MARKDOWN', 'MARKDOWN'): 0.15
        }
        
        return transitions.get((prev_state, current_state), 0.1)
    
    def _calculate_path_integrals(self, dataframe: DataFrame):
        """
        FEYNMAN PATH INTEGRATION
        Calculate probability amplitude for different price paths
        """
        
        if len(dataframe) < self.path_integral_periods.value:
            return
            
        # Get recent price path
        recent_prices = dataframe['close'].values[-self.path_integral_periods.value:]
        
        # Calculate path variations (different routes price could have taken)
        path_variations = []
        
        for i in range(1, len(recent_prices)):
            # Direct path (straight line)
            direct_path = np.linspace(recent_prices[0], recent_prices[i], i+1)
            
            # Calculate "action" (deviation from direct path)
            actual_path = recent_prices[:i+1]
            path_deviation = np.sum((actual_path - direct_path) ** 2)
            
            # Path probability amplitude (quantum mechanical analogy)
            path_amplitude = np.exp(-path_deviation / (2 * np.var(recent_prices)))
            path_variations.append(path_amplitude)
        
        # Store path integral result
        if len(path_variations) > 0:
            dataframe.loc[dataframe.index[-1], 'path_integral'] = np.mean(path_variations)
            dataframe.loc[dataframe.index[-1], 'path_coherence'] = np.std(path_variations)
        
        # Calculate forward path probabilities
        self._calculate_forward_paths(dataframe, recent_prices)
    
    def _calculate_forward_paths(self, dataframe: DataFrame, recent_prices):
        """
        Calculate forward path probabilities for different scenarios
        """
        
        current_price = recent_prices[-1]
        volatility = np.std(recent_prices[-48:])  # 48h volatility
        
        # Define potential future paths
        scenarios = {
            'bullish': current_price * 1.15,    # +15%
            'neutral': current_price * 1.02,    # +2%
            'bearish': current_price * 0.90     # -10%
        }
        
        # Calculate path probabilities based on current market state
        probabilities = {}
        
        for scenario, target_price in scenarios.items():
            # Distance from current price
            distance = abs(np.log(target_price / current_price))
            
            # Probability based on volatility and market state
            prob = np.exp(-distance**2 / (2 * volatility**2))
            probabilities[scenario] = prob
        
        # Normalize probabilities
        total_prob = sum(probabilities.values())
        if total_prob > 0:
            for scenario in probabilities:
                probabilities[scenario] /= total_prob
        
        # Store forward path probabilities
        dataframe.loc[dataframe.index[-1], 'bull_path_prob'] = probabilities.get('bullish', 0.33)
        dataframe.loc[dataframe.index[-1], 'neutral_path_prob'] = probabilities.get('neutral', 0.33)
        dataframe.loc[dataframe.index[-1], 'bear_path_prob'] = probabilities.get('bearish', 0.33)
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        MARKOV-FEYNMAN ENTRY LOGIC
        Enter only on high-probability state transitions
        """
        
        pair = metadata['pair']
        
        # Initialize
        dataframe.loc[:, 'enter_long'] = 0
        dataframe.loc[:, 'enter_tag'] = ''
        
        # ENTRY CONDITION 1: ACCUMULATION → MARKUP TRANSITION
        accumulation_to_markup = (
            (dataframe['markov_state'].shift(1) == 'ACCUMULATION') &
            (dataframe['markov_state'] == 'MARKUP') &
            (dataframe['state_confidence'] > 0.8) &
            (dataframe['state_transition_prob'] > 0.6) &
            (dataframe['volume_regime'] > self.volume_regime.value) &
            (dataframe['path_integral'] > 0.3) &  # Strong path coherence
            (dataframe['bull_path_prob'] > 0.5)   # Bullish forward probability
        )
        
        dataframe.loc[accumulation_to_markup, 'enter_long'] = 1
        dataframe.loc[accumulation_to_markup, 'enter_tag'] = 'markov_markup'
        
        # ENTRY CONDITION 2: MARKDOWN → ACCUMULATION TRANSITION (REVERSAL)
        markdown_reversal = (
            (dataframe['markov_state'].shift(2) == 'MARKDOWN') &
            (dataframe['markov_state'] == 'ACCUMULATION') &
            (dataframe['state_confidence'] > 0.75) &
            (dataframe['price_level'] < 0.85) &  # Deep discount
            (dataframe['volatility_regime'] > dataframe['volatility_regime'].quantile(0.8)) &  # High volatility (capitulation)
            (dataframe['volume_regime'] > 1.5) &  # Panic volume
            (dataframe['path_integral'] > 0.4)    # Strong reversal probability
        )
        
        # Don't overwrite markup signals
        reversal_mask = markdown_reversal & (dataframe['enter_long'] == 0)
        dataframe.loc[reversal_mask, 'enter_long'] = 1
        dataframe.loc[reversal_mask, 'enter_tag'] = 'markov_reversal'
        
        # ENTRY CONDITION 3: SPECTRAL HARMONIC CONFLUENCE
        spectral_entry = (
            (dataframe['spectral_centroid'] < self.spectral_threshold.value) &  # Low frequency dominance
            (dataframe['dominant_frequency'] > 0.01) &  # Significant harmonic
            (dataframe['path_coherence'] < 0.3) &  # Low path deviation
            (dataframe['close'] > dataframe['ema_200']) &  # Above macro trend
            (dataframe['macro_momentum'] > 0.02) &  # Positive macro momentum
            (dataframe['bull_path_prob'] > 0.6)  # High bullish probability
        )
        
        # Don't overwrite other signals
        spectral_mask = spectral_entry & (dataframe['enter_long'] == 0)
        dataframe.loc[spectral_mask, 'enter_long'] = 1
        dataframe.loc[spectral_mask, 'enter_tag'] = 'spectral_harmonic'
        
        # Logging
        if accumulation_to_markup.any():
            self.logger.info(f"🔬 MARKOV MARKUP: {pair} | State: ACCUMULATION→MARKUP | Confidence: {dataframe['state_confidence'].iloc[-1]:.2f}")
            
        if reversal_mask.any():
            self.logger.info(f"🔄 MARKOV REVERSAL: {pair} | State: MARKDOWN→ACCUMULATION | Price Level: {dataframe['price_level'].iloc[-1]:.2f}")
            
        if spectral_mask.any():
            self.logger.info(f"🎵 SPECTRAL HARMONIC: {pair} | Frequency: {dataframe['dominant_frequency'].iloc[-1]:.4f} | Bull Prob: {dataframe['bull_path_prob'].iloc[-1]:.2f}")
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        MACRO EXIT SYSTEM
        Exit on state transitions and spectral divergence
        """
        
        dataframe.loc[:, 'exit_long'] = 0
        dataframe.loc[:, 'exit_tag'] = ''
        
        # EXIT 1: MARKUP → DISTRIBUTION TRANSITION
        distribution_exit = (
            (dataframe['markov_state'] == 'DISTRIBUTION') &
            (dataframe['state_confidence'] > 0.7) &
            (dataframe['price_level'] > 1.15) &
            (dataframe['bear_path_prob'] > 0.4)
        )
        
        dataframe.loc[distribution_exit, 'exit_long'] = 1
        dataframe.loc[distribution_exit, 'exit_tag'] = 'distribution_phase'
        
        # EXIT 2: SPECTRAL DIVERGENCE (High frequency dominance)
        spectral_exit = (
            (dataframe['spectral_centroid'] > self.spectral_threshold.value * 3) &
            (dataframe['path_coherence'] > 0.6) &  # High path deviation
            (dataframe['bear_path_prob'] > 0.5)
        )
        
        spectral_mask = spectral_exit & (dataframe['exit_long'] == 0)
        dataframe.loc[spectral_mask, 'exit_long'] = 1
        dataframe.loc[spectral_mask, 'exit_tag'] = 'spectral_divergence'
        
        # EXIT 3: MACRO MOMENTUM BREAKDOWN
        macro_breakdown = (
            (dataframe['macro_momentum'] < -0.05) &
            (dataframe['close'] < dataframe['ema_200']) &
            (dataframe['volatility_regime'] > dataframe['volatility_regime'].quantile(0.8))
        )
        
        breakdown_mask = macro_breakdown & (dataframe['exit_long'] == 0)
        dataframe.loc[breakdown_mask, 'exit_long'] = 1
        dataframe.loc[breakdown_mask, 'exit_tag'] = 'macro_breakdown'
        
        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:
        """
        FINAL MARKOV-FEYNMAN VALIDATION
        """
        
        self.logger.info(f"🔬 MARKOV-FEYNMAN ENTRY: {pair} | Tag: {entry_tag} | Rate: ${rate:.4f}")
        self.logger.info(f"📊 Mathematical Foundation: Prime→Markov→Feynman transformation confirmed")
        
        return True
