# 资金监控模块
import pandas as pd
import numpy as np
from typing import Dict, Optional, List
from qihuo_analyzer.core.models import StrategyConfig


class FundFlowMonitor:
    """资金流向监控器"""
    
    def __init__(self, config: Optional[StrategyConfig] = None):
        self.config = config or StrategyConfig()
    
    def analyze_fund_flow(self, data: pd.DataFrame) -> Dict:
        """分析资金流向"""
        result = {}
        
        # 分析持仓量变化
        oi_analysis = self._analyze_open_interest(data)
        result.update(oi_analysis)
        
        # 分析量价关系
        volume_price_analysis = self._analyze_volume_price_relationship(data)
        result.update(volume_price_analysis)
        
        # 分析资金流向强度
        fund_flow_strength = self._calculate_fund_flow_strength(data)
        result['fund_flow_strength'] = fund_flow_strength
        
        # 分析资金集中度
        fund_concentration = self._analyze_fund_concentration(data)
        result.update(fund_concentration)
        
        # 综合资金面信号
        fund_signal = self._generate_fund_signal(result)
        result['fund_signal'] = fund_signal
        
        return result
    
    def _analyze_open_interest(self, data: pd.DataFrame) -> Dict:
        """分析持仓量变化"""
        # 计算持仓量变化
        data['oi_change'] = data['open_interest'].diff()
        data['oi_change_pct'] = data['oi_change'] / data['open_interest'].shift(1) * 100
        
        # 最近N天持仓量变化
        recent_oi_change = data['oi_change'].tail(5).sum()
        recent_oi_change_pct = data['oi_change_pct'].tail(5).mean()
        
        # 持仓量趋势
        oi_trend = self._judge_oi_trend(data['open_interest'])
        
        # 持仓量与价格关系
        oi_price_relationship = self._judge_oi_price_relationship(data)
        
        return {
            'recent_oi_change': recent_oi_change,
            'recent_oi_change_pct': recent_oi_change_pct,
            'oi_trend': oi_trend,
            'oi_price_relationship': oi_price_relationship
        }
    
    def _analyze_volume_price_relationship(self, data: pd.DataFrame) -> Dict:
        """分析量价关系"""
        # 计算价格变化
        data['price_change'] = data['close'].diff()
        data['price_change_pct'] = data['price_change'] / data['close'].shift(1) * 100
        
        # 计算成交量变化
        data['volume_change'] = data['volume'].diff()
        data['volume_change_pct'] = data['volume_change'] / data['volume'].shift(1) * 100
        
        # 量价配合度
        volume_price_fit = self._calculate_volume_price_fit(data)
        
        # 量价背离检测
        divergence = self._detect_volume_price_divergence(data)
        
        # 成交量趋势
        volume_trend = self._judge_volume_trend(data['volume'])
        
        return {
            'volume_price_fit': volume_price_fit,
            'divergence': divergence,
            'volume_trend': volume_trend
        }
    
    def _calculate_fund_flow_strength(self, data: pd.DataFrame) -> float:
        """计算资金流向强度"""
        # 计算资金流向
        # 简化计算：(收盘价 - 开盘价) * 成交量
        fund_flow = ((data['close'] - data['open']) * data['volume']).tail(20).sum()
        
        # 归一化到-100到100
        if fund_flow > 0:
            strength = min(100, (fund_flow / data['volume'].tail(20).sum()) * 1000)
        else:
            strength = max(-100, (fund_flow / data['volume'].tail(20).sum()) * 1000)
        
        return strength
    
    def _analyze_fund_concentration(self, data: pd.DataFrame) -> Dict:
        """分析资金集中度"""
        # 计算成交量集中度（前5天成交量占比）
        recent_volume = data['volume'].tail(5).sum()
        total_volume = data['volume'].tail(30).sum()
        volume_concentration = recent_volume / total_volume if total_volume > 0 else 0
        
        # 计算持仓量集中度（最近持仓量变化占比）
        recent_oi_change = abs(data['oi_change'].tail(5).sum())
        total_oi = data['open_interest'].iloc[-1]
        oi_concentration = recent_oi_change / total_oi if total_oi > 0 else 0
        
        return {
            'volume_concentration': volume_concentration,
            'oi_concentration': oi_concentration
        }
    
    def _judge_oi_trend(self, oi_series: pd.Series) -> str:
        """判断持仓量趋势"""
        # 使用简单移动平均线判断趋势
        ma5 = oi_series.rolling(window=5).mean().iloc[-1]
        ma20 = oi_series.rolling(window=20).mean().iloc[-1]
        
        if ma5 > ma20 * 1.02:
            return 'strong_increasing'
        elif ma5 > ma20:
            return 'increasing'
        elif ma5 < ma20 * 0.98:
            return 'strong_decreasing'
        elif ma5 < ma20:
            return 'decreasing'
        else:
            return 'stable'
    
    def _judge_oi_price_relationship(self, data: pd.DataFrame) -> Dict:
        """判断持仓量与价格关系"""
        recent_data = data.tail(10)
        
        # 计算价格变化
        if 'price_change' not in recent_data.columns:
            recent_data['price_change'] = recent_data['close'].diff()
        
        # 计算持仓量变化
        if 'oi_change' not in recent_data.columns:
            recent_data['oi_change'] = recent_data['open_interest'].diff()
        
        # 计算平均价格变化和平均持仓量变化
        avg_price_change = recent_data['price_change'].mean()
        avg_oi_change = recent_data['oi_change'].mean()
        
        if avg_price_change > 0 and avg_oi_change > 0:
            return 'price_up_oi_up'  # 价涨量增
        elif avg_price_change > 0 and avg_oi_change < 0:
            return 'price_up_oi_down'  # 价涨量减
        elif avg_price_change < 0 and avg_oi_change > 0:
            return 'price_down_oi_up'  # 价跌量增
        elif avg_price_change < 0 and avg_oi_change < 0:
            return 'price_down_oi_down'  # 价跌量减
        else:
            return 'stable'
    
    def _calculate_volume_price_fit(self, data: pd.DataFrame) -> float:
        """计算量价配合度"""
        recent_data = data.tail(20)
        
        # 计算量价配合的次数
        fit_count = 0
        total_count = len(recent_data) - 1
        
        for i in range(1, len(recent_data)):
            price_change = recent_data['price_change'].iloc[i]
            volume_change = recent_data['volume_change'].iloc[i]
            
            # 量价配合：价格上涨成交量增加，价格下跌成交量减少
            if (price_change > 0 and volume_change > 0) or (price_change < 0 and volume_change < 0):
                fit_count += 1
        
        fit_ratio = fit_count / total_count if total_count > 0 else 0
        return fit_ratio * 100
    
    def _detect_volume_price_divergence(self, data: pd.DataFrame) -> str:
        """检测量价背离"""
        recent_data = data.tail(10)
        
        # 计算价格趋势（斜率）
        price_slope = np.polyfit(range(len(recent_data)), recent_data['close'], 1)[0]
        
        # 计算成交量趋势（斜率）
        volume_slope = np.polyfit(range(len(recent_data)), recent_data['volume'], 1)[0]
        
        # 判断背离
        if price_slope > 0 and volume_slope < 0:
            return 'bearish_divergence'  # 价格上涨，成交量下降，看跌背离
        elif price_slope < 0 and volume_slope > 0:
            return 'bullish_divergence'  # 价格下降，成交量上升，看涨背离
        else:
            return 'no_divergence'
    
    def _judge_volume_trend(self, volume_series: pd.Series) -> str:
        """判断成交量趋势"""
        ma5 = volume_series.rolling(window=5).mean().iloc[-1]
        ma20 = volume_series.rolling(window=20).mean().iloc[-1]
        
        if ma5 > ma20 * 1.1:
            return 'strong_increasing'
        elif ma5 > ma20:
            return 'increasing'
        elif ma5 < ma20 * 0.9:
            return 'strong_decreasing'
        elif ma5 < ma20:
            return 'decreasing'
        else:
            return 'stable'
    
    def _generate_fund_signal(self, fund_analysis: Dict) -> str:
        """生成资金面信号"""
        signals = []
        
        # 持仓量信号
        if fund_analysis.get('oi_trend') in ['strong_increasing', 'increasing']:
            if fund_analysis.get('oi_price_relationship') == 'price_up_oi_up':
                signals.append('bullish')
            elif fund_analysis.get('oi_price_relationship') == 'price_down_oi_up':
                signals.append('bearish')
        
        # 量价关系信号
        if fund_analysis.get('volume_price_fit') > 60:
            if fund_analysis.get('volume_trend') in ['strong_increasing', 'increasing']:
                signals.append('bullish')
        
        # 量价背离信号
        if fund_analysis.get('divergence') == 'bullish_divergence':
            signals.append('bullish')
        elif fund_analysis.get('divergence') == 'bearish_divergence':
            signals.append('bearish')
        
        # 资金流向强度信号
        fund_flow_strength = fund_analysis.get('fund_flow_strength', 0)
        if fund_flow_strength > 30:
            signals.append('bullish')
        elif fund_flow_strength < -30:
            signals.append('bearish')
        
        # 综合信号
        if signals.count('bullish') > signals.count('bearish'):
            return 'bullish'
        elif signals.count('bearish') > signals.count('bullish'):
            return 'bearish'
        else:
            return 'neutral'
    
    def detect_volume_spikes(self, data: pd.DataFrame, threshold: float = 2.0) -> List[int]:
        """检测成交量异动"""
        # 计算成交量移动平均线和标准差
        data['volume_ma'] = data['volume'].rolling(window=20).mean()
        data['volume_std'] = data['volume'].rolling(window=20).std()
        
        # 计算成交量偏离度
        data['volume_zscore'] = (data['volume'] - data['volume_ma']) / data['volume_std']
        
        # 找出成交量异动的位置
        spikes = data[data['volume_zscore'] > threshold].index
        
        return list(spikes)
    
    def analyze_institutional_activity(self, data: pd.DataFrame) -> Dict:
        """分析机构活动"""
        # 基于持仓量和成交量的变化分析机构活动
        # 机构通常会引起较大的持仓量变化
        
        # 计算大资金活动指标
        data['institutional_activity'] = data['oi_change'] * abs(data['price_change'])
        
        # 最近机构活动强度
        recent_institutional_activity = data['institutional_activity'].tail(5).sum()
        
        # 机构活动趋势
        institutional_trend = 'increasing' if recent_institutional_activity > 0 else 'decreasing'
        
        return {
            'recent_institutional_activity': recent_institutional_activity,
            'institutional_trend': institutional_trend
        }
