import pandas as pd import talib from typing import Dict, List, Tuple, Optional import logging from dataclasses import dataclass # 配置日志输出到控制台 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(), # 输出到控制台 logging.FileHandler('technical_analysis.log') # 输出到文件 ], force=True # 强制重新配置日志 ) @dataclass class CoinSignal: symbol: str score: float reason: str entry_price: float stop_loss: float take_profit: float timeframe: str confidence: str strategy_type: str # 短线/中线/长线 holding_period: int # 预期持仓周期(天) risk_reward_ratio: float # 风险回报比 expiry_hours: int # 选币信号有效期(小时) action_suggestion: str # 操作建议 signal_type: str = "LONG" # 新增:信号类型 LONG/SHORT direction: str = "BUY" # 新增:操作方向 BUY/SELL @dataclass class StrategyConfig: name: str primary_timeframe: str confirm_timeframe: str holding_period_days: int expiry_hours: int risk_reward_min: float risk_reward_max: float rsi_period: int macd_fast: int macd_slow: int macd_signal: int class TechnicalAnalyzer: def __init__(self): self.min_score = 60 # 提高最低选币分数,注重质量 self.max_selections = 15 # 适中的选币数量,注重质量而非数量 # 策略配置 - 重新设计时间周期 self.strategies = { '超短线': StrategyConfig( name='超短线', primary_timeframe='5m', confirm_timeframe='1m', holding_period_days=1, expiry_hours=24, risk_reward_min=1.2, risk_reward_max=1.8, rsi_period=5, macd_fast=3, macd_slow=8, macd_signal=2 ), '短线': StrategyConfig( name='短线', primary_timeframe='15m', confirm_timeframe='5m', holding_period_days=3, expiry_hours=72, risk_reward_min=1.5, risk_reward_max=2.5, rsi_period=7, macd_fast=5, macd_slow=13, macd_signal=3 ), '中线': StrategyConfig( name='中线', primary_timeframe='1h', confirm_timeframe='15m', holding_period_days=7, expiry_hours=168, # 7天 risk_reward_min=2.0, risk_reward_max=3.5, rsi_period=14, macd_fast=12, macd_slow=26, macd_signal=9 ), '波段': StrategyConfig( name='波段', primary_timeframe='4h', confirm_timeframe='1h', holding_period_days=15, expiry_hours=360, # 15天 risk_reward_min=2.5, risk_reward_max=4.0, rsi_period=14, macd_fast=12, macd_slow=26, macd_signal=9 ), '长线': StrategyConfig( name='长线', primary_timeframe='1d', confirm_timeframe='4h', holding_period_days=30, expiry_hours=720, # 30天 risk_reward_min=3.0, risk_reward_max=6.0, rsi_period=21, macd_fast=26, macd_slow=50, macd_signal=12 ), '趋势': StrategyConfig( name='趋势', primary_timeframe='1w', confirm_timeframe='1d', holding_period_days=60, expiry_hours=1440, # 60天 risk_reward_min=4.0, risk_reward_max=8.0, rsi_period=21, macd_fast=26, macd_slow=50, macd_signal=12 ) } def get_required_timeframes(self) -> Dict[str, List[str]]: """获取每个策略需要的时间周期""" return { '超短线': ['1m', '5m', '15m'], # 需要更短周期确认 '短线': ['5m', '15m', '1h'], # 短线需要分钟级别 '中线': ['15m', '1h', '4h'], # 中线需要小时级别 '波段': ['1h', '4h', '1d'], # 波段需要日内到日线 '长线': ['4h', '1d', '3d'], # 长线需要日线级别 '趋势': ['1d', '3d', '1w'] # 趋势需要周线级别 } def get_optimal_timeframes_for_analysis(self, market_conditions: Dict = None) -> List[str]: """根据市场条件动态选择最优时间周期组合""" # 基础时间周期组合 - 包含所有策略需要的时间周期 base_timeframes = ['1m', '5m', '15m', '1h', '4h', '1d', '3d', '1w'] # 如果有市场条件信息,可以进一步优化 if market_conditions: volatility = market_conditions.get('volatility', 'medium') trend_strength = market_conditions.get('trend_strength', 'medium') if volatility == 'high': # 高波动市场,增加短周期权重 return ['1m', '5m', '15m', '1h', '4h', '1d'] elif volatility == 'low': # 低波动市场,增加长周期权重 return ['1h', '4h', '1d', '3d', '1w'] return base_timeframes def determine_best_strategy(self, df: pd.DataFrame) -> str: """根据币种特性确定最佳策略 - 增强版""" try: if len(df) < 50: logging.info("数据不足50条,使用默认中线策略") return '中线' # 默认策略 recent_data = df.tail(20) # 1. 计算波动率 volatility = recent_data['close'].std() / recent_data['close'].mean() # 2. 计算价格变化速度 price_change_5d = (df.iloc[-1]['close'] - df.iloc[-5]['close']) / df.iloc[-5]['close'] # 3. 成交量特性 volume_recent = recent_data['volume'].mean() volume_avg = df['volume'].mean() volume_ratio = volume_recent / volume_avg if volume_avg > 0 else 1 logging.info(f"策略选择指标: 波动率={volatility:.3f}, 5日价格变化={price_change_5d:.3f}, 成交量比率={volume_ratio:.2f}") # 添加详细的策略选择调试信息 logging.info(f"策略选择条件判断:") logging.info(f" 超短线: volatility({volatility:.3f}) > 0.20? {volatility > 0.20}, abs_change({abs(price_change_5d):.3f}) > 0.10? {abs(price_change_5d) > 0.10}") logging.info(f" 短线: volatility({volatility:.3f}) > 0.10? {volatility > 0.10}, abs_change({abs(price_change_5d):.3f}) > 0.05? {abs(price_change_5d) > 0.05}") logging.info(f" 中线: volatility({volatility:.3f}) > 0.06? {volatility > 0.06}, volume_ratio({volume_ratio:.2f}) > 1.1? {volume_ratio > 1.1}") logging.info(f" 波段: 0.03 < volatility({volatility:.3f}) <= 0.08? {0.03 < volatility <= 0.08}") # 策略选择逻辑 - 修复条件,确保所有策略都能被选中 if volatility > 0.20 and abs(price_change_5d) > 0.10: # 极高波动,快速变化 → 超短线策略 logging.info("选择超短线策略: 极高波动且快速变化") return '超短线' elif volatility > 0.08 and abs(price_change_5d) > 0.03: # 高波动,较快变化 → 短线策略(进一步降低门槛) logging.info("选择短线策略: 高波动且较快变化") return '短线' elif volatility > 0.06 and volume_ratio > 1.1: # 中等波动,有资金关注 → 中线策略 logging.info("选择中线策略: 中等波动且有资金关注") return '中线' elif volatility > 0.03 and volatility <= 0.08: # 中低波动,适合波段操作 → 波段策略 logging.info("选择波段策略: 中低波动适合波段操作") return '波段' elif volatility <= 0.04 and volume_ratio < 1.0: # 低波动,适合长期持有 → 长线策略 logging.info("选择长线策略: 低波动适合长期持有") return '长线' elif volatility <= 0.02: # 极低波动,趋势跟踪 → 趋势策略 logging.info("选择趋势策略: 极低波动适合趋势跟踪") return '趋势' else: # 根据波动率范围选择策略 if volatility <= 0.03: logging.info("选择趋势策略: 基于波动率范围") return '趋势' elif volatility <= 0.06: logging.info("选择长线策略: 基于波动率范围") return '长线' elif volatility <= 0.10: logging.info("选择波段策略: 基于波动率范围") return '波段' else: logging.info("选择中线策略: 默认选择") return '中线' except Exception as e: logging.warning(f"策略选择失败,使用默认中线策略: {e}") return '中线' def calculate_technical_indicators(self, df: pd.DataFrame, strategy: str = '中线') -> pd.DataFrame: """计算技术指标""" if df.empty or len(df) < 50: return df config = self.strategies[strategy] # 移动平均线 df['ma20'] = talib.SMA(df['close'].values, timeperiod=20) df['ma50'] = talib.SMA(df['close'].values, timeperiod=50) df['ma200'] = talib.SMA(df['close'].values, timeperiod=200) # 根据策略使用不同参数的RSI df['rsi'] = talib.RSI(df['close'].values, timeperiod=config.rsi_period) # 根据策略使用不同参数的MACD df['macd'], df['macd_signal'], df['macd_hist'] = talib.MACD( df['close'].values, fastperiod=config.macd_fast, slowperiod=config.macd_slow, signalperiod=config.macd_signal ) # 布林带 df['bb_upper'], df['bb_middle'], df['bb_lower'] = talib.BBANDS( df['close'].values, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0 ) # 成交量移动平均 df['volume_ma'] = talib.SMA(df['volume'].values, timeperiod=20) # ATR (平均真实波动范围) df['atr'] = talib.ATR(df['high'].values, df['low'].values, df['close'].values, timeperiod=14) return df def calculate_fibonacci_levels(self, df: pd.DataFrame, lookback=50) -> Dict[str, float]: """计算斐波那契回调位""" if len(df) < lookback: return {} recent_data = df.tail(lookback) high = recent_data['high'].max() low = recent_data['low'].min() diff = high - low return { 'fib_0': high, 'fib_236': high - 0.236 * diff, 'fib_382': high - 0.382 * diff, 'fib_500': high - 0.500 * diff, 'fib_618': high - 0.618 * diff, 'fib_786': high - 0.786 * diff, 'fib_100': low } def find_support_resistance(self, df: pd.DataFrame, window=20) -> Tuple[float, float]: """寻找支撑阻力位""" if len(df) < window * 2: return 0, 0 # 寻找局部高点和低点 recent_data = df.tail(window) # 获取最近的支撑和阻力 resistance = recent_data['high'].max() support = recent_data['low'].min() return support, resistance def simple_long_analysis(self, df: pd.DataFrame) -> float: """简化的多头分析 - 只看核心指标""" if len(df) < 10: return 0 score = 0 current = df.iloc[-1] recent_data = df.tail(5) # 1. 价格趋势 (30分) - 最简单直接 price_changes = recent_data['close'].pct_change().dropna() positive_days = (price_changes > 0).sum() recent_return = (current['close'] - df.iloc[-5]['close']) / df.iloc[-5]['close'] if positive_days >= 3: # 5天中3天上涨 score += 15 if 0.02 <= recent_return <= 0.15: # 5日涨幅2%-15% score += 15 # 2. 量能确认 (20分) - 简化量价分析 if 'volume' in df.columns: recent_volume = recent_data['volume'].mean() prev_volume = df.iloc[-10:-5]['volume'].mean() if len(df) >= 10 else recent_volume if recent_volume > prev_volume * 1.2: # 量能放大 score += 20 # 3. 相对位置 (20分) - 避免高位追高 if len(df) >= 20: high_20 = df.tail(20)['high'].max() low_20 = df.tail(20)['low'].min() position = (current['close'] - low_20) / (high_20 - low_20) if high_20 != low_20 else 0.5 if 0.2 <= position <= 0.7: # 中低位置 score += 20 elif position > 0.85: # 过高位置 score -= 10 # 4. 动量指标 (10分) - 只看简单RSI if 'rsi' in df.columns and not df['rsi'].isna().all(): rsi = current.get('rsi', 50) if 40 <= rsi <= 65: # RSI健康区间 score += 10 elif rsi > 75: # 过热 score -= 5 return min(max(score, 0), 70) # 限制区间 def simple_short_analysis(self, df: pd.DataFrame) -> float: """简化的空头分析 - 只看核心指标""" if len(df) < 10: return 0 score = 0 current = df.iloc[-1] recent_data = df.tail(5) # 1. 价格趋势 (30分) - 直接看下跌 price_changes = recent_data['close'].pct_change().dropna() negative_days = (price_changes < 0).sum() recent_return = (current['close'] - df.iloc[-5]['close']) / df.iloc[-5]['close'] if negative_days >= 3: # 5天中3天下跌 score += 15 if -0.15 <= recent_return <= -0.02: # 5日跌幅2%-15% score += 15 # 2. 量能确认 (20分) - 价跌量增 if 'volume' in df.columns: recent_volume = recent_data['volume'].mean() prev_volume = df.iloc[-10:-5]['volume'].mean() if len(df) >= 10 else recent_volume if recent_volume > prev_volume * 1.2: # 量能放大 score += 20 # 3. 相对位置 (20分) - 高位做空 if len(df) >= 20: high_20 = df.tail(20)['high'].max() low_20 = df.tail(20)['low'].min() position = (current['close'] - low_20) / (high_20 - low_20) if high_20 != low_20 else 0.5 if 0.6 <= position <= 0.95: # 高位区间 score += 20 elif position < 0.3: # 过低位置 score -= 10 # 4. 动量指标 (10分) - 只看RSI if 'rsi' in df.columns and not df['rsi'].isna().all(): rsi = current.get('rsi', 50) if 35 <= rsi <= 60: # RSI适中区间 score += 10 elif rsi < 25: # 过度超卖 score -= 5 return min(max(score, 0), 70) # 限制区间 def _analyze_consecutive_moves(self, df: pd.DataFrame) -> float: """分析连续上涨动量""" if len(df) < 10: return 0 score = 0 recent_closes = df['close'].tail(10).values # 计算连续上涨天数 consecutive_up = 0 for i in range(1, len(recent_closes)): if recent_closes[i] > recent_closes[i-1]: consecutive_up += 1 else: break # 计算最近3日涨幅 recent_gain = (recent_closes[-1] - recent_closes[-4]) / recent_closes[-4] if len(recent_closes) >= 4 else 0 # 连续上涨但涨幅适中得高分 if consecutive_up >= 3 and 0.03 <= recent_gain <= 0.12: # 3%-12%涨幅 score += 8 elif consecutive_up >= 2 and 0.02 <= recent_gain <= 0.08: score += 5 elif consecutive_up >= 4: # 连续上涨但可能过热 score += 3 # 价格加速上涨警告 if recent_gain > 0.20: # 超过20%涨幅减分 score -= 5 return max(score, 0) def _analyze_price_breakthrough(self, df: pd.DataFrame) -> float: """分析价格突破情况""" if len(df) < 50: return 0 score = 0 current_price = df.iloc[-1]['close'] # 1. 突破早期高点 (10分) # 计算过去20-50日的高点 historical_data = df.iloc[-50:-10] # 排除最近10天 if len(historical_data) > 0: resistance_levels = [] # 寻找局部高点 for i in range(5, len(historical_data)-5): local_high = historical_data.iloc[i]['high'] is_peak = True for j in range(max(0, i-5), min(len(historical_data), i+6)): if j != i and historical_data.iloc[j]['high'] > local_high: is_peak = False break if is_peak: resistance_levels.append(local_high) # 检查是否突破这些阻力位 for resistance in resistance_levels: if current_price > resistance * 1.01: # 突破且有一定幅度 # 检查突破的时间和幅度 breakthrough_ratio = (current_price - resistance) / resistance if breakthrough_ratio <= 0.05: # 刚刚突破,没有过度追高 score += 8 elif breakthrough_ratio <= 0.10: score += 5 break # 2. 突破近期高点 (5分) recent_high = df.tail(10)['high'].max() if current_price > recent_high * 1.005: # 突破近期高点 score += 5 return min(score, 15) def _analyze_wave_structure(self, df: pd.DataFrame) -> float: """分析波动结构 - 寻找低点抬高模式""" if len(df) < 30: return 0 score = 0 recent_data = df.tail(30) # 寻找近30天的低点 lows = [] highs = [] for i in range(3, len(recent_data)-3): current_low = recent_data.iloc[i]['low'] current_high = recent_data.iloc[i]['high'] # 判断是否为局部低点 is_local_low = True is_local_high = True for j in range(i-3, i+4): if j != i: if recent_data.iloc[j]['low'] < current_low: is_local_low = False if recent_data.iloc[j]['high'] > current_high: is_local_high = False if is_local_low: lows.append((i, current_low)) if is_local_high: highs.append((i, current_high)) # 分析低点抬高趋势 if len(lows) >= 2: # 检查最近两个低点是否抬高 latest_lows = sorted(lows, key=lambda x: x[0])[-2:] if latest_lows[1][1] > latest_lows[0][1]: # 低点抬高 score += 5 # 分析高点突破趋势 if len(highs) >= 2: latest_highs = sorted(highs, key=lambda x: x[0])[-2:] if latest_highs[1][1] > latest_highs[0][1]: # 高点突破 score += 5 return min(score, 10) def analyze_volume_price_relationship(self, df: pd.DataFrame) -> float: """分析量价关系 - 识别资金流入模式 (最高30分)""" if len(df) < 20: return 0 score = 0 # 1. 价涨量增模式分析 (15分) price_volume_score = self._analyze_price_volume_trend(df) score += price_volume_score # 2. 量能突破分析 (10分) volume_breakthrough_score = self._analyze_volume_breakthrough(df) score += volume_breakthrough_score # 3. 资金流入模式 (5分) accumulation_score = self._analyze_accumulation_pattern(df) score += accumulation_score return min(score, 30) def _analyze_price_volume_trend(self, df: pd.DataFrame) -> float: """分析价涨量增模式""" if len(df) < 15: return 0 score = 0 recent_data = df.tail(15) # 计算价格和成交量的相关性 price_changes = recent_data['close'].pct_change().dropna() volume_changes = recent_data['volume'].pct_change().dropna() if len(price_changes) >= 10 and len(volume_changes) >= 10: # 只分析上涨日的量价关系 up_days = price_changes > 0 up_price_changes = price_changes[up_days] up_volume_changes = volume_changes[up_days] if len(up_price_changes) >= 5: # 计算上涨日的量价相关性 correlation = up_price_changes.corr(up_volume_changes) if correlation > 0.5: # 强正相关 score += 10 elif correlation > 0.3: score += 6 elif correlation > 0.1: score += 3 # 分析最近5天的量价配合 recent_5 = df.tail(5) up_days_recent = (recent_5['close'].diff() > 0).sum() avg_volume_recent = recent_5['volume'].mean() avg_volume_before = df.iloc[-20:-5]['volume'].mean() if len(df) >= 20 else avg_volume_recent volume_ratio = avg_volume_recent / avg_volume_before if avg_volume_before > 0 else 1 # 上涨日多且成交量放大 if up_days_recent >= 3 and volume_ratio > 1.2: score += 5 return min(score, 15) def _analyze_volume_breakthrough(self, df: pd.DataFrame) -> float: """分析量能突破""" if len(df) < 30: return 0 score = 0 current_volume = df.iloc[-1]['volume'] avg_volume_30 = df.tail(30)['volume'].mean() avg_volume_10 = df.tail(10)['volume'].mean() # 1. 近期量能突破 volume_ratio_current = current_volume / avg_volume_30 if avg_volume_30 > 0 else 1 volume_ratio_recent = avg_volume_10 / avg_volume_30 if avg_volume_30 > 0 else 1 if volume_ratio_current > 2.0: # 当日爆量 # 检查是否伴随价格上涨 price_change = (df.iloc[-1]['close'] - df.iloc[-2]['close']) / df.iloc[-2]['close'] if price_change > 0.02: # 价涨量增 score += 6 elif price_change > 0: # 价涨但幅度不大 score += 3 if 1.3 <= volume_ratio_recent <= 2.5: # 温和持续放量 score += 4 return min(score, 10) def _analyze_accumulation_pattern(self, df: pd.DataFrame) -> float: """分析资金积累模式""" if len(df) < 20: return 0 score = 0 recent_data = df.tail(20) # 分析OBV(能量潮)趋势 # 简化版OBV计算 obv = [] obv_value = 0 for i in range(len(recent_data)): if i == 0: obv.append(obv_value) continue price_change = recent_data.iloc[i]['close'] - recent_data.iloc[i-1]['close'] volume = recent_data.iloc[i]['volume'] if price_change > 0: obv_value += volume elif price_change < 0: obv_value -= volume obv.append(obv_value) # 分析OBV趋势 if len(obv) >= 10: obv_recent = obv[-5:] # 最近5天 obv_before = obv[-10:-5] # 之前5天 if sum(obv_recent) > sum(obv_before): # OBV上升 score += 3 # 检查价格横盘但量能放大的情况(积累) price_volatility = recent_data['close'].std() / recent_data['close'].mean() volume_avg_recent = recent_data.tail(10)['volume'].mean() volume_avg_before = recent_data.head(10)['volume'].mean() if (price_volatility < 0.08 and # 价格相对稳定 volume_avg_recent > volume_avg_before * 1.2): # 但量能放大 score += 2 return min(score, 5) def analyze_technical_patterns(self, df: pd.DataFrame) -> float: """分析技术形态 - 综合K线形态和价格结构 (最高25分)""" if len(df) < 20: return 0 score = 0 # 1. K线形态识别 (15分) candlestick_score = self._analyze_enhanced_candlestick_patterns(df) score += candlestick_score # 2. 价格结构分析 (10分) structure_score = self._analyze_price_structure(df) score += structure_score return min(score, 25) def _analyze_enhanced_candlestick_patterns(self, df: pd.DataFrame) -> float: """增强型K线形态分析""" if len(df) < 10: return 0 score = 0 # 使用talib的K线形态识别 patterns = { 'hammer': talib.CDLHAMMER(df['open'], df['high'], df['low'], df['close']), 'doji': talib.CDLDOJI(df['open'], df['high'], df['low'], df['close']), 'engulfing': talib.CDLENGULFING(df['open'], df['high'], df['low'], df['close']), 'morning_star': talib.CDLMORNINGSTAR(df['open'], df['high'], df['low'], df['close']), 'three_white_soldiers': talib.CDL3WHITESOLDIERS(df['open'], df['high'], df['low'], df['close']), 'piercing': talib.CDLPIERCING(df['open'], df['high'], df['low'], df['close']), 'harami_bullish': talib.CDLHARAMI(df['open'], df['high'], df['low'], df['close']) } # 检查最近3天的K线形态 recent_signals = 0 for pattern_name, pattern_data in patterns.items(): if len(pattern_data) > 3: # 检查最近3天是否有信号 for i in range(-3, 0): if pattern_data.iloc[i] > 0: # 看涨信号 recent_signals += 1 if pattern_name in ['morning_star', 'three_white_soldiers', 'piercing']: score += 4 # 强看涨形态 elif pattern_name in ['hammer', 'engulfing']: score += 3 # 中度看涨形态 else: score += 2 # 弱看涨形态 break # 手动分析一些简单形态 manual_score = self._analyze_manual_patterns(df.tail(10)) score += manual_score return min(score, 15) def _analyze_manual_patterns(self, df: pd.DataFrame) -> float: """手动分析一些简单形态""" if len(df) < 5: return 0 score = 0 # 分析最近5天的走势 last_5 = df.tail(5) # 1. 阶段性低点上移模式 lows = last_5['low'].tolist() if len(lows) >= 3: # 检查是否有低点逐步抬高的趋势 ascending_lows = True for i in range(1, len(lows)): if lows[i] < lows[i-1] * 0.98: # 允许小幅波动 ascending_lows = False break if ascending_lows: score += 3 # 2. 突破前高点模式 current_high = df.iloc[-1]['high'] prev_highs = df.iloc[-5:-1]['high'].tolist() if current_high > max(prev_highs) * 1.01: # 突破前高 score += 2 return min(score, 5) def _analyze_price_structure(self, df: pd.DataFrame) -> float: """分析价格结构""" if len(df) < 30: return 0 score = 0 # 1. 分析关键支撑位突破 (6分) support_score = self._analyze_support_breakthrough(df) score += support_score # 2. 分析价格区间突破 (4分) range_score = self._analyze_range_breakthrough(df) score += range_score return min(score, 10) def _analyze_support_breakthrough(self, df: pd.DataFrame) -> float: """分析支撑位突破""" if len(df) < 30: return 0 score = 0 current_price = df.iloc[-1]['close'] # 寻找近30天内的重要支撑位 recent_30 = df.tail(30) # 计算支撑位(多次触及的低点) support_levels = [] for i in range(5, len(recent_30)-5): low_price = recent_30.iloc[i]['low'] # 检查这个低点是否被多次测试 test_count = 0 for j in range(len(recent_30)): if abs(recent_30.iloc[j]['low'] - low_price) / low_price < 0.02: # 2%范围内 test_count += 1 if test_count >= 2: # 至少被测试2次 support_levels.append(low_price) # 检查是否突破了这些支撑位 for support in support_levels: if current_price > support * 1.03: # 突破支撑位3%以上 score += 3 break return min(score, 6) def _analyze_range_breakthrough(self, df: pd.DataFrame) -> float: """分析区间突破""" if len(df) < 20: return 0 score = 0 recent_20 = df.tail(20) current_price = df.iloc[-1]['close'] # 计算近20天的价格区间 price_high = recent_20['high'].max() price_low = recent_20['low'].min() price_range = price_high - price_low # 检查是否在盘整后突破 if price_range > 0: # 检查是否经历了盘整阶段 middle_period = recent_20.iloc[5:15] # 中间一段 consolidation_range = middle_period['high'].max() - middle_period['low'].min() # 如果中间阶段波动较小,说明有盘整 if consolidation_range < price_range * 0.6: # 检查是否突破了区间高点 if current_price > price_high * 0.995: # 接近或突破高点 score += 4 return min(score, 4) def analyze_price_behavior(self, df: pd.DataFrame) -> float: """分析价格行为 - 核心指标 (最高35分)""" if len(df) < 30: return 0 score = 0 recent_data = df.tail(20) # 1. 连续上涨动量分析 (12分) consecutive_score = self._analyze_consecutive_moves(df) score += consecutive_score # 2. 价格突破分析 (15分) breakthrough_score = self._analyze_price_breakthrough(df) score += breakthrough_score # 3. 波动结构分析 (8分) wave_score = self._analyze_wave_structure(df) score += wave_score return min(score, 35) def analyze_breakout_potential(self, df: pd.DataFrame) -> float: """分析突破潜力 - 辅助指标 (最高20分)""" if len(df) < 30: return 0 score = 0 current = df.iloc[-1] recent_data = df.tail(20) # 1. 价格位置分析 - 寻找埋伏位置 (8分) recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() price_range = recent_high - recent_low current_position = (current['close'] - recent_low) / price_range if price_range > 0 else 0 # 偏好在区间中下部的币种 if 0.2 <= current_position <= 0.5: # 理想埋伏位置 score += 6 elif 0.5 < current_position <= 0.7: # 次优位置 score += 3 elif current_position > 0.8: # 已经在高位,减分 score -= 5 # 2. 整理形态分析 (6分) volatility = recent_data['close'].std() / recent_data['close'].mean() if 0.05 <= volatility <= 0.12: # 适度整理,蓄势待发 score += 5 elif volatility < 0.03: # 过度整理,缺乏动力 score += 1 elif volatility > 0.20: # 波动过大,风险较高 score -= 3 # 3. 量能配合 (6分) volume_ratio = recent_data['volume'] / recent_data['volume'].rolling(10).mean() moderate_volume_days = ((volume_ratio >= 1.1) & (volume_ratio <= 1.8)).sum() explosive_volume_days = (volume_ratio > 2.5).sum() if moderate_volume_days >= 3: # 持续温和放量 score += 4 if explosive_volume_days <= 1: # 没有过度爆量 score += 2 return max(min(score, 20), 0) def analyze_short_signals(self, df: pd.DataFrame, strategy: str = '中线') -> Optional[CoinSignal]: """分析做空信号 - 识别下跌趋势币种""" if df.empty or len(df) < 50: return None try: df = self.calculate_technical_indicators(df, strategy) config = self.strategies[strategy] total_score = 0 reasons = [] # === 做空信号评分体系 === # 1. 空头价格行为分析 (35分) bear_price_score = self.analyze_bearish_price_behavior(df) if bear_price_score > 0: total_score += bear_price_score if bear_price_score >= 25: reasons.append(f"强势下跌信号({bear_price_score}分)") elif bear_price_score >= 15: reasons.append(f"下跌信号({bear_price_score}分)") # 2. 空头量价关系 (30分) bear_volume_score = self.analyze_bearish_volume_price(df) if bear_volume_score > 0: total_score += bear_volume_score if bear_volume_score >= 20: reasons.append(f"理想空头量价({bear_volume_score}分)") elif bear_volume_score >= 10: reasons.append(f"空头量价({bear_volume_score}分)") # 3. 空头技术形态 (25分) bear_pattern_score = self.analyze_bearish_patterns(df) if bear_pattern_score > 0: total_score += bear_pattern_score if bear_pattern_score >= 15: reasons.append(f"强空头形态({bear_pattern_score}分)") elif bear_pattern_score >= 8: reasons.append(f"空头形态({bear_pattern_score}分)") # 4. 下跌突破潜力 (20分) breakdown_score = self.analyze_breakdown_potential(df) if breakdown_score > 0: total_score += breakdown_score if breakdown_score >= 15: reasons.append(f"高下跌潜力({breakdown_score}分)") elif breakdown_score >= 8: reasons.append(f"下跌潜力({breakdown_score}分)") # 5. 均线空头系统 (10分) bear_ma_score = self.analyze_bearish_moving_average(df) if bear_ma_score > 0: total_score += bear_ma_score if bear_ma_score >= 6: reasons.append(f"均线空头({int(bear_ma_score)}分)") # 过滤低分币种 if total_score < 65: # 做空也需要足够的信号强度 return None # 确定信心等级 if total_score >= 80: confidence = "高" elif total_score >= 65: confidence = "中" else: confidence = "低" # 计算空头入场和出场位 entry_price, stop_loss, take_profit, risk_reward = self.calculate_short_entry_exit_levels(df, strategy) # 生成空头操作建议 current_price = df.iloc[-1]['close'] action_suggestion = self.generate_short_action_suggestion(df, entry_price, current_price, total_score) return CoinSignal( symbol=None, # 将在调用时设置 score=total_score, reason=" | ".join(reasons), entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=strategy, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="SHORT", direction="SELL" ) except Exception as e: logging.error(f"分析空头信号失败: {e}") return None def analyze_bearish_price_behavior(self, df: pd.DataFrame) -> float: """分析空头价格行为 - 核心指标 (35分)""" if len(df) < 30: return 0 score = 0 recent_data = df.tail(20) # 1. 连续下跌动量 (10分) consecutive_down = 0 recent_closes = recent_data['close'].tail(10).values for i in range(1, len(recent_closes)): if recent_closes[i] < recent_closes[i-1]: consecutive_down += 1 else: break recent_decline = (recent_closes[-1] - recent_closes[-4]) / recent_closes[-4] if len(recent_closes) >= 4 else 0 if consecutive_down >= 3 and -0.12 <= recent_decline <= -0.03: # 3%-12%下跌 score += 8 elif consecutive_down >= 2 and -0.08 <= recent_decline <= -0.02: score += 5 # 2. 价格跌破分析 (15分) current_price = df.iloc[-1]['close'] # 跌破支撑位 historical_data = df.iloc[-50:-10] if len(historical_data) > 0: support_levels = [] for i in range(5, len(historical_data)-5): local_low = historical_data.iloc[i]['low'] is_valley = True for j in range(max(0, i-5), min(len(historical_data), i+6)): if j != i and historical_data.iloc[j]['low'] < local_low: is_valley = False break if is_valley: support_levels.append(local_low) for support in support_levels: if current_price < support * 0.97: # 跌破支撑位3%以上 breakdown_ratio = (support - current_price) / support if breakdown_ratio <= 0.05: # 刚刚跌破 score += 10 elif breakdown_ratio <= 0.10: score += 6 break # 3. 高点逐步下移模式 (10分) recent_highs = [] for i in range(3, len(recent_data)-3): current_high = recent_data.iloc[i]['high'] is_local_high = True for j in range(i-3, i+4): if j != i and recent_data.iloc[j]['high'] > current_high: is_local_high = False break if is_local_high: recent_highs.append((i, current_high)) if len(recent_highs) >= 2: latest_highs = sorted(recent_highs, key=lambda x: x[0])[-2:] if latest_highs[1][1] < latest_highs[0][1]: # 高点下移 score += 8 return min(score, 35) def _comprehensive_long_analysis(self, main_df: pd.DataFrame, timeframe_data: Dict, strategy: str) -> float: """综合多头分析 - 优化策略本身而非降低分数""" if len(main_df) < 30: return 0 total_score = 0 score_details = {} # 用于记录各项得分 # 1. 价格行为分析 (35分) price_score = self.analyze_price_behavior(main_df) total_score += price_score score_details['价格行为'] = price_score # 2. 量价关系 (30分) volume_score = self.analyze_volume_price_relationship(main_df) total_score += volume_score score_details['量价关系'] = volume_score # 3. 技术形态 (25分) pattern_score = self.analyze_technical_patterns(main_df) total_score += pattern_score score_details['技术形态'] = pattern_score # 4. 突破潜力 (20分) breakout_score = self.analyze_breakout_potential(main_df) total_score += breakout_score score_details['突破潜力'] = breakout_score # 5. 多时间框架确认 (15分) - 新增 multi_tf_score = self._analyze_multi_timeframe_confirmation(timeframe_data, strategy, 'LONG') total_score += multi_tf_score score_details['多时间框架确认'] = multi_tf_score # 6. 风险评估调整 (-30到+10分) - 新增 risk_adjustment = self._analyze_risk_factors(main_df, 'LONG') total_score += risk_adjustment score_details['风险评估调整'] = risk_adjustment # 记录详细评分 - 改为100分制 final_score = min(total_score, 100) logging.info(f"多头分析详细评分: 价格行为({price_score:.1f}) + 量价关系({volume_score:.1f}) + " f"技术形态({pattern_score:.1f}) + 突破潜力({breakout_score:.1f}) + " f"多时间框架({multi_tf_score:.1f}) + 风险调整({risk_adjustment:.1f}) = {final_score:.1f}") return final_score def _comprehensive_short_analysis(self, main_df: pd.DataFrame, timeframe_data: Dict, strategy: str) -> float: """综合空头分析 - 优化策略本身而非降低分数""" if len(main_df) < 30: return 0 total_score = 0 score_details = {} # 用于记录各项得分 # 1. 空头价格行为 (35分) bear_price_score = self.analyze_bearish_price_behavior(main_df) total_score += bear_price_score score_details['空头价格行为'] = bear_price_score # 2. 空头量价关系 (30分) bear_volume_score = self.analyze_bearish_volume_price(main_df) total_score += bear_volume_score score_details['空头量价关系'] = bear_volume_score # 3. 空头技术形态 (25分) bear_pattern_score = self.analyze_bearish_patterns(main_df) total_score += bear_pattern_score score_details['空头技术形态'] = bear_pattern_score # 4. 下跌突破潜力 (20分) breakdown_score = self.analyze_breakdown_potential(main_df) total_score += breakdown_score score_details['下跌突破潜力'] = breakdown_score # 5. 多时间框架确认 (15分) - 新增 multi_tf_score = self._analyze_multi_timeframe_confirmation(timeframe_data, strategy, 'SHORT') total_score += multi_tf_score score_details['多时间框架确认'] = multi_tf_score # 6. 风险评估调整 (-30到+10分) - 新增 risk_adjustment = self._analyze_risk_factors(main_df, 'SHORT') total_score += risk_adjustment score_details['风险评估调整'] = risk_adjustment # 记录详细评分 - 改为100分制 final_score = min(total_score, 100) logging.info(f"空头分析详细评分: 空头价格行为({bear_price_score:.1f}) + 空头量价关系({bear_volume_score:.1f}) + " f"空头技术形态({bear_pattern_score:.1f}) + 下跌突破潜力({breakdown_score:.1f}) + " f"多时间框架({multi_tf_score:.1f}) + 风险调整({risk_adjustment:.1f}) = {final_score:.1f}") return final_score def _analyze_multi_timeframe_confirmation(self, timeframe_data: Dict, strategy: str, signal_type: str) -> float: """多时间框架确认分析""" score = 0 config = self.strategies[strategy] # 获取确认时间框架数据 confirm_df = timeframe_data.get(config.confirm_timeframe) if confirm_df is None or len(confirm_df) < 20: return 0 confirm_df = self.calculate_technical_indicators(confirm_df, strategy) if signal_type == 'LONG': # 确认时间框架的多头信号 confirm_price_score = self.simple_long_analysis(confirm_df) if confirm_price_score >= 30: score += 15 elif confirm_price_score >= 20: score += 10 elif confirm_price_score >= 15: score += 5 else: # SHORT # 确认时间框架的空头信号 confirm_price_score = self.simple_short_analysis(confirm_df) if confirm_price_score >= 40: score += 15 elif confirm_price_score >= 30: score += 10 elif confirm_price_score >= 20: score += 5 return score def _analyze_risk_factors(self, df: pd.DataFrame, signal_type: str) -> float: """风险因素分析""" if len(df) < 20: return 0 score = 0 current = df.iloc[-1] recent_data = df.tail(20) # 1. RSI过热/过冷检查 if hasattr(current, 'rsi'): rsi = current['rsi'] if signal_type == 'LONG': if rsi > 80: # 严重超买 score -= 15 elif rsi > 70: # 超买 score -= 8 elif 40 <= rsi <= 65: # 健康区间 score += 5 else: # SHORT if rsi < 20: # 严重超卖 score -= 15 elif rsi < 30: # 超卖 score -= 8 elif 35 <= rsi <= 60: # 健康区间 score += 5 # 2. 价格位置风险 recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() price_range = recent_high - recent_low current_position = (current['close'] - recent_low) / price_range if price_range > 0 else 0.5 if signal_type == 'LONG': if current_position > 0.9: # 极高位置 score -= 20 elif current_position > 0.8: # 高位置 score -= 10 elif 0.2 <= current_position <= 0.6: # 理想位置 score += 5 else: # SHORT if current_position < 0.1: # 极低位置 score -= 20 elif current_position < 0.2: # 低位置 score -= 10 elif 0.4 <= current_position <= 0.8: # 理想位置 score += 5 # 3. 成交量异常检查 if hasattr(current, 'volume') and hasattr(current, 'volume_ma'): volume_ratio = current['volume'] / current['volume_ma'] if current['volume_ma'] > 0 else 1 if volume_ratio > 5: # 异常爆量 score -= 10 elif volume_ratio < 0.3: # 成交量萎缩 score -= 5 return max(min(score, 10), -30) def analyze_volume_accumulation(self, df: pd.DataFrame) -> float: """分析成交量积累模式""" if len(df) < 20: return 0 score = 0 recent_data = df.tail(10) # 寻找温和放量而非暴涨放量 volume_ratio = recent_data['volume'] / recent_data['volume_ma'] # 温和持续放量(1.2-2倍)比突然暴涨放量更好 moderate_volume_days = ((volume_ratio >= 1.2) & (volume_ratio <= 2.0)).sum() explosive_volume_days = (volume_ratio > 3.0).sum() if moderate_volume_days >= 3: # 持续温和放量 score += 15 if explosive_volume_days >= 2: # 已经暴涨放量,减分 score -= 10 return min(score, 20) def check_early_trend_signals(self, df: pd.DataFrame) -> float: """检查早期趋势信号""" if len(df) < 50: return 0 score = 0 current = df.iloc[-1] prev = df.iloc[-2] # 1. 均线金叉但涨幅不大 if (prev['ma20'] <= prev['ma50'] and current['ma20'] > current['ma50']): # 刚刚金叉,还未大涨 recent_gain = (current['close'] - df.iloc[-5]['close']) / df.iloc[-5]['close'] if recent_gain < 0.10: # 5日涨幅小于10% score += 20 elif recent_gain > 0.25: # 已经涨幅过大 score -= 15 # 2. RSI从超卖区域回升但未超买 if 35 <= current['rsi'] <= 55: # 从底部回升但未过热 score += 10 elif current['rsi'] > 70: # 已经超买 score -= 20 # 3. MACD即将金叉或刚刚金叉 if current['macd'] > current['macd_signal']: # 检查金叉时间 macd_cross_days = 0 for i in range(1, min(6, len(df))): if df.iloc[-i]['macd'] <= df.iloc[-i]['macd_signal']: macd_cross_days = i - 1 break if macd_cross_days <= 2: # 刚刚金叉2天内 score += 15 elif macd_cross_days >= 10: # 金叉很久了 score -= 10 return min(score, 25) def analyze_candlestick_patterns(self, df: pd.DataFrame) -> float: """分析K线形态""" if len(df) < 20: return 0 score = 0 # 使用talib的K线形态识别 patterns = { 'hammer': talib.CDLHAMMER(df['open'], df['high'], df['low'], df['close']), 'doji': talib.CDLDOJI(df['open'], df['high'], df['low'], df['close']), 'engulfing': talib.CDLENGULFING(df['open'], df['high'], df['low'], df['close']), 'morning_star': talib.CDLMORNINGSTAR(df['open'], df['high'], df['low'], df['close']), 'three_white_soldiers': talib.CDL3WHITESOLDIERS(df['open'], df['high'], df['low'], df['close']) } # 检查最近的K线形态 recent_signals = 0 for pattern_name, pattern_data in patterns.items(): if len(pattern_data) > 0 and pattern_data.iloc[-1] > 0: recent_signals += 1 if pattern_name in ['morning_star', 'three_white_soldiers']: score += 15 elif pattern_name in ['hammer', 'engulfing']: score += 10 else: score += 5 return min(score, 20) def analyze_moving_average_trend(self, df: pd.DataFrame) -> float: """分析均线系统""" if len(df) < 50: return 0 score = 0 current = df.iloc[-1] # 均线多头排列 if current['close'] > current['ma20'] > current['ma50']: score += 15 # 价格突破关键均线 prev = df.iloc[-2] if prev['close'] <= prev['ma20'] and current['close'] > current['ma20']: score += 10 # 均线斜率向上 ma20_slope = (current['ma20'] - df.iloc[-5]['ma20']) / 5 if ma20_slope > 0: score += 5 return min(score, 25) def analyze_momentum_indicators(self, df: pd.DataFrame) -> float: """分析动量指标""" if len(df) < 20: return 0 score = 0 current = df.iloc[-1] # RSI分析 if 30 <= current['rsi'] <= 50: # RSI从超卖区域回升 score += 10 elif 50 <= current['rsi'] <= 70: # RSI强势但未超买 score += 5 # MACD分析 if current['macd'] > current['macd_signal'] and current['macd_hist'] > 0: score += 10 # MACD金叉 prev = df.iloc[-2] if prev['macd'] <= prev['macd_signal'] and current['macd'] > current['macd_signal']: score += 15 return min(score, 25) def calculate_entry_exit_levels(self, df: pd.DataFrame, fib_levels: Dict, strategy: str) -> Tuple[float, float, float]: """计算入场、止损、止盈位""" current_price = df.iloc[-1]['close'] atr = df.iloc[-1]['atr'] support, resistance = self.find_support_resistance(df) config = self.strategies[strategy] # 入场价策略 - 不使用当前市价,而是基于技术分析 ma20 = df.iloc[-1]['ma20'] ma50 = df.iloc[-1]['ma50'] # 策略1: 均线回踩入场 if current_price > ma20 > ma50: # 多头趋势 # 等待回踩MA20附近入场,给出5%的缓冲 entry_price = ma20 * 1.02 # MA20上方2% else: # 策略2: 突破确认入场 # 等待突破近期阻力位 recent_high = df.tail(10)['high'].max() if current_price >= recent_high * 0.98: # 接近突破 entry_price = recent_high * 1.005 # 突破确认价位 else: # 策略3: 斐波那契回调入场 if fib_levels and 'fib_618' in fib_levels: entry_price = max(fib_levels['fib_618'], current_price * 0.98) else: # 策略4: 当前价格适当下方等待 entry_price = current_price * 0.995 # 当前价下方0.5% # 确保入场价不会过低(距离当前价不超过5%) if entry_price < current_price * 0.95: entry_price = current_price * 0.98 # 止损位: 支撑位下方或ATR的1.5倍 stop_loss_atr = entry_price - (atr * 1.5) stop_loss_support = support * 0.98 if support > 0 else entry_price * 0.92 stop_loss = max(stop_loss_atr, stop_loss_support) # 根据策略动态设置风险回报比 risk = entry_price - stop_loss target_ratio = (config.risk_reward_min + config.risk_reward_max) / 2 take_profit_ratio = entry_price + (risk * target_ratio) # 如果有阻力位,取较小值 if resistance > entry_price: take_profit_resistance = resistance * 0.98 take_profit = min(take_profit_ratio, take_profit_resistance) else: take_profit = take_profit_ratio # 计算实际风险回报比 actual_risk_reward = (take_profit - entry_price) / risk if risk > 0 else target_ratio return entry_price, stop_loss, take_profit, actual_risk_reward def generate_action_suggestion(self, df: pd.DataFrame, signal: CoinSignal, current_price: float) -> str: """根据评分和价格位置生成操作建议""" try: # 计算价格差异百分比 entry_diff = (current_price - signal.entry_price) / signal.entry_price * 100 # 获取技术指标状态 current = df.iloc[-1] recent_data = df.tail(10) # 计算价格在最近区间的位置 recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() price_range = recent_high - recent_low current_position = (current_price - recent_low) / price_range if price_range > 0 else 0.5 # 基于评分等级的基础建议 if signal.score >= 85: # 高分 if entry_diff <= 1: # 接近建议价位 if current_position <= 0.4: # 在低位 return "立即买入" elif current_position <= 0.6: return "现价买入" else: return "等待回调买入" elif entry_diff <= 3: # 稍高于建议价位 if signal.strategy_type == "短线": return "现价买入" else: return "等待回调买入" else: # 明显高于建议价位 return "等待大幅回调" elif signal.score >= 70: # 中等分数 if entry_diff <= -2: # 低于建议价位 return "现价买入" elif entry_diff <= 1: # 接近建议价位 if current_position <= 0.5: return "现价买入" else: return "等待回调买入" elif entry_diff <= 5: # 高于建议价位 return "等待回调买入" else: return "暂时观望" else: # 较低分数 (60-70) if entry_diff <= -3: # 明显低于建议价位 return "分批买入" elif entry_diff <= 0: # 低于或等于建议价位 if current_position <= 0.3: return "小仓位试探" else: return "等待回调买入" elif entry_diff <= 3: return "等待回调买入" else: return "暂时观望" return "等待回调买入" # 默认建议 except Exception as e: logging.error(f"生成操作建议时出错: {e}") return "谨慎观望" def analyze_single_coin(self, symbol: str, timeframe_data: Dict[str, pd.DataFrame], volume_24h_usd: float = 0) -> List[CoinSignal]: """分析单个币种 - 优化策略""" try: logging.info(f"\n=== 开始分析 {symbol} ===") logging.info(f"24小时交易量: ${volume_24h_usd:,.0f}") # 先执行基础分析,即使交易量不够也要显示评分 basic_analysis_executed = False # 24小时交易量过滤 - 但仍然显示评分 if volume_24h_usd < 10_000_000: # 降低到1000万美金进行调试 logging.info(f"{symbol} 交易量不足1000万美金,但仍显示评分") # 继续执行分析以显示评分,但最后返回空列表 basic_analysis_executed = True signals = [] # 首先使用4h数据确定最适合的策略 initial_df = timeframe_data.get('4h') if initial_df is None or len(initial_df) < 20: logging.info(f"{symbol} 4h数据不足,跳过分析") return [] # 确定最佳策略 best_strategy = self.determine_best_strategy(initial_df) config = self.strategies[best_strategy] logging.info(f"{symbol} 选择策略: {best_strategy} (主时间周期: {config.primary_timeframe}, 确认时间周期: {config.confirm_timeframe})") # 检查可用的时间周期数据 available_timeframes = list(timeframe_data.keys()) logging.info(f"{symbol} 可用时间周期: {available_timeframes}") # 获取策略对应的主要时间周期数据 main_df = timeframe_data.get(config.primary_timeframe) if main_df is None or len(main_df) < 20: # 尝试使用该策略的确认时间周期 confirm_df = timeframe_data.get(config.confirm_timeframe) if confirm_df is not None and len(confirm_df) >= 20: main_df = confirm_df logging.info(f"{symbol} 使用确认时间周期{config.confirm_timeframe}替代主时间周期{config.primary_timeframe}") else: # 最后才回退到初始数据和中线策略 main_df = initial_df config = self.strategies['中线'] best_strategy = '中线' logging.info(f"{symbol} 数据不足,回退到中线策略") # 使用策略相应的参数计算技术指标 main_df = self.calculate_technical_indicators(main_df, best_strategy) # === 综合多头信号分析 === logging.info(f"\n--- {symbol} 多头分析 ---") long_score = self._comprehensive_long_analysis(main_df, timeframe_data, best_strategy) # 记录多头分析结果(不管是否通过筛选) logging.info(f"{symbol} 多头分析结果: {long_score:.1f}/100分 (门槛: 70分)") if long_score >= 70: # 70分入选门槛 logging.info(f"✓ {symbol} 多头信号通过筛选") # 计算入场出场位 entry_price, stop_loss, take_profit, risk_reward = self.calculate_entry_exit_levels( main_df, {}, best_strategy ) # 确定信心等级 - 基于100分制 if long_score >= 85: confidence = "高" elif long_score >= 75: confidence = "中" else: confidence = "低" # 生成操作建议 - 基于综合分析 current_price = main_df.iloc[-1]['close'] action_suggestion = "现价买入" if long_score >= 85 else "等待回调买入" logging.info(f"{symbol} 多头信号详情: 入场${entry_price:.4f}, 止损${stop_loss:.4f}, 止盈${take_profit:.4f}, 风险回报比1:{risk_reward:.2f}") long_signal = CoinSignal( symbol=symbol, score=long_score, reason=f"综合多头分析: 高质量信号({long_score}分)", entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=best_strategy, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="LONG", direction="BUY" ) signals.append(long_signal) else: logging.info(f"✗ {symbol} 多头信号未通过筛选 (差距: {70 - long_score:.1f}分)") # === 综合空头信号分析 === logging.info(f"\n--- {symbol} 空头分析 ---") short_score = self._comprehensive_short_analysis(main_df, timeframe_data, best_strategy) # 记录空头分析结果(不管是否通过筛选) logging.info(f"{symbol} 空头分析结果: {short_score:.1f}/100分 (门槛: 70分)") if short_score >= 70: # 与多头门槛保持一致 logging.info(f"✓ {symbol} 空头信号通过筛选") # 计算入场出场位 entry_price, stop_loss, take_profit, risk_reward = self.calculate_short_entry_exit_levels( main_df, best_strategy ) # 确定信心等级 - 基于100分制 if short_score >= 85: confidence = "高" elif short_score >= 75: confidence = "中" else: confidence = "低" # 生成操作建议 - 基于综合分析 current_price = main_df.iloc[-1]['close'] action_suggestion = "现价做空" if short_score >= 85 else "等待反弹做空" logging.info(f"{symbol} 空头信号详情: 入场${entry_price:.4f}, 止损${stop_loss:.4f}, 止盈${take_profit:.4f}, 风险回报比1:{risk_reward:.2f}") short_signal = CoinSignal( symbol=symbol, score=short_score, reason=f"综合空头分析: 高质量信号({short_score}分)", entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=best_strategy, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="SHORT", direction="SELL" ) signals.append(short_signal) else: logging.info(f"✗ {symbol} 空头信号未通过筛选 (差距: {70 - short_score:.1f}分)") # 总结该币种分析结果 if signals: signal_types = [s.signal_type for s in signals] logging.info(f"{symbol} 分析完成 - 生成{len(signals)}个信号: {', '.join(signal_types)}") else: logging.info(f"{symbol} 分析完成 - 无符合条件的信号 (多头:{long_score:.1f}, 空头:{short_score:.1f})") # 如果是因为交易量不足而跳过,返回空列表 if basic_analysis_executed: logging.info(f"{symbol} 因交易量不足,不生成实际交易信号") return [] return signals except Exception as e: logging.error(f"分析{symbol}时出错: {e}") return [] def analyze_single_coin_with_strategy(self, symbol: str, timeframe_data: Dict[str, pd.DataFrame], volume_24h_usd: float, strategy_name: str) -> List[CoinSignal]: """使用指定策略分析单个币种""" try: # 24小时交易量过滤 if volume_24h_usd < 50_000_000: return [] # 验证策略是否存在 if strategy_name not in self.strategies: logging.error(f"未知策略: {strategy_name}") return [] config = self.strategies[strategy_name] # 获取策略对应的主要时间周期数据 main_df = timeframe_data.get(config.primary_timeframe) if main_df is None or len(main_df) < 20: return [] # 使用策略相应的参数计算技术指标 main_df = self.calculate_technical_indicators(main_df, strategy_name) signals = [] # 综合多头信号分析 long_score = self._comprehensive_long_analysis(main_df, timeframe_data, strategy_name) if long_score >= 80: # 生成多头信号 entry_price, stop_loss, take_profit, risk_reward = self.calculate_entry_exit_levels( main_df, {}, strategy_name ) confidence = "高" if long_score >= 85 else "中" if long_score >= 75 else "低" action_suggestion = "现价买入" if long_score >= 85 else "等待回调买入" long_signal = CoinSignal( symbol=symbol, score=long_score, reason=f"{strategy_name}策略多头信号({long_score}分)", entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=strategy_name, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="LONG", direction="BUY" ) signals.append(long_signal) # 综合空头信号分析 short_score = self._comprehensive_short_analysis(main_df, timeframe_data, strategy_name) if short_score >= 90: # 生成空头信号 entry_price, stop_loss, take_profit, risk_reward = self.calculate_short_entry_exit_levels( main_df, strategy_name ) confidence = "高" if short_score >= 85 else "中" if short_score >= 75 else "低" action_suggestion = "现价做空" if short_score >= 85 else "等待反弹做空" short_signal = CoinSignal( symbol=symbol, score=short_score, reason=f"{strategy_name}策略空头信号({short_score}分)", entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=strategy_name, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="SHORT", direction="SELL" ) signals.append(short_signal) return signals except Exception as e: logging.error(f"使用{strategy_name}策略分析{symbol}时出错: {e}") return [] def _analyze_long_signal(self, symbol: str, main_df: pd.DataFrame, timeframe_data: Dict, config: StrategyConfig, best_strategy: str) -> Optional[CoinSignal]: """分析多头信号 - 原有逻辑""" total_score = 0 reasons = [] # === 核心评分体系:以价格行为和技术形态为主导 === # 1. 价格行为分析 - 最重要 (最高35分) price_behavior_score = self.analyze_price_behavior(main_df) if price_behavior_score > 0: total_score += price_behavior_score if price_behavior_score >= 25: reasons.append(f"强势价格行为({price_behavior_score}分)") elif price_behavior_score >= 15: reasons.append(f"积极价格行为({price_behavior_score}分)") # 2. 量价关系分析 - 核心指标 (最高30分) volume_price_score = self.analyze_volume_price_relationship(main_df) if volume_price_score > 0: total_score += volume_price_score if volume_price_score >= 20: reasons.append(f"理想量价配合({volume_price_score}分)") elif volume_price_score >= 10: reasons.append(f"量价配合({volume_price_score}分)") # 3. 技术形态确认 - 重要指标 (最高25分) pattern_score = self.analyze_technical_patterns(main_df) if pattern_score > 0: total_score += pattern_score if pattern_score >= 15: reasons.append(f"强势技术形态({pattern_score}分)") elif pattern_score >= 8: reasons.append(f"技术形态({pattern_score}分)") # 4. 突破潜力分析 - 寻找爆发机会 (最高20分) breakout_score = self.analyze_breakout_potential(main_df) if breakout_score > 0: total_score += breakout_score if breakout_score >= 15: reasons.append(f"高突破潜力({breakout_score}分)") elif breakout_score >= 8: reasons.append(f"突破潜力({breakout_score}分)") # 5. 均线系统 - 辅助确认 (最高10分,权重降低) ma_score = self.analyze_moving_average_trend(main_df) if ma_score > 0: ma_score = min(ma_score * 0.4, 10) # 大幅降低权重 total_score += ma_score if ma_score >= 6: reasons.append(f"均线支撑({int(ma_score)}分)") # 6. 确认时间周期验证 - 多周期确认 (最高5分) confirm_df = timeframe_data.get(config.confirm_timeframe) if confirm_df is not None and len(confirm_df) > 20: confirm_df = self.calculate_technical_indicators(confirm_df, best_strategy) confirm_score = self.analyze_price_behavior(confirm_df) * 0.2 # 降低权重 if confirm_score > 3: total_score += min(confirm_score, 5) reasons.append(f"{config.confirm_timeframe}确认") # 过滤低分币种 - 适度放宽条件 if price_behavior_score < 5 and volume_price_score < 5: # 降低要求 return None # 适度放宽的分数过滤 min_total_score = 50 # 降低最低门槛 if total_score < min_total_score: return None # 计算新波那契回调位 fib_levels = self.calculate_fibonacci_levels(main_df) # 计算入场和出场位 - 使用对应策略 entry_price, stop_loss, take_profit, risk_reward = self.calculate_entry_exit_levels( main_df, fib_levels, best_strategy ) # 确定信心等级 - 适度放宽标准 if total_score >= 75: # 降低高信心阈值 confidence = "高" elif total_score >= 55: # 降低中等信心阈值 confidence = "中" else: confidence = "低" # 生成操作建议 current_price = main_df.iloc[-1]['close'] temp_signal = CoinSignal( symbol=symbol, score=total_score, reason=" | ".join(reasons), entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=best_strategy, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion="", # 临时占位 signal_type="LONG", direction="BUY" ) # 生成操作建议 action_suggestion = self.generate_action_suggestion(main_df, temp_signal, current_price) return CoinSignal( symbol=symbol, score=total_score, reason=" | ".join(reasons), entry_price=entry_price, stop_loss=stop_loss, take_profit=take_profit, timeframe=config.primary_timeframe, confidence=confidence, strategy_type=best_strategy, holding_period=config.holding_period_days, risk_reward_ratio=risk_reward, expiry_hours=config.expiry_hours, action_suggestion=action_suggestion, signal_type="LONG", direction="BUY" ) def select_coins(self, market_data: Dict[str, Dict]) -> Dict[str, List[CoinSignal]]: """批量选币 - 使用优化策略""" logging.info(f"\n{'='*60}") logging.info(f"开始批量选币分析,共{len(market_data)}个币种") logging.info(f"{'='*60}") long_signals = [] short_signals = [] filtered_count = 0 low_volume_count = 0 strategy_stats = {} # 统计各策略使用次数 all_scores = [] # 记录所有币种的评分 for i, (symbol, data) in enumerate(market_data.items(), 1): logging.info(f"\n进度: {i}/{len(market_data)} - 分析{symbol}") timeframe_data = data.get('timeframes', {}) volume_24h_usd = data.get('volume_24h_usd', 0) # 24小时交易量过滤统计 if volume_24h_usd < 10_000_000: # 降低到1000万进行调试 low_volume_count += 1 logging.info(f"{symbol} 交易量过滤: ${volume_24h_usd:,.0f} < $10,000,000") continue signals = self.analyze_single_coin(symbol, timeframe_data, volume_24h_usd) # 获取该币种的评分信息(用于统计) try: # 重新计算评分用于统计(避免重复计算,这里简化处理) initial_df = timeframe_data.get('4h') if initial_df is not None and len(initial_df) >= 20: best_strategy = self.determine_best_strategy(initial_df) config = self.strategies[best_strategy] main_df = timeframe_data.get(config.primary_timeframe, initial_df) if len(main_df) >= 20: main_df = self.calculate_technical_indicators(main_df, best_strategy) temp_long_score = self._comprehensive_long_analysis(main_df, timeframe_data, best_strategy) temp_short_score = self._comprehensive_short_analysis(main_df, timeframe_data, best_strategy) all_scores.append({ 'symbol': symbol, 'strategy': best_strategy, 'long_score': temp_long_score, 'short_score': temp_short_score, 'volume_24h': volume_24h_usd }) except Exception as e: logging.debug(f"获取{symbol}评分统计信息失败: {e}") for signal in signals: if signal: # 统计策略使用情况 strategy_key = signal.strategy_type if strategy_key not in strategy_stats: strategy_stats[strategy_key] = {'long': 0, 'short': 0, 'total': 0} # 使用统一的70分门槛 if signal.score >= 70: # 统一70分入选门槛 if signal.signal_type == "LONG": long_signals.append(signal) strategy_stats[strategy_key]['long'] += 1 strategy_stats[strategy_key]['total'] += 1 logging.info(f"✓ {symbol} 多头信号入选: {signal.score:.1f}分 ({signal.strategy_type})") elif signal.signal_type == "SHORT": short_signals.append(signal) strategy_stats[strategy_key]['short'] += 1 strategy_stats[strategy_key]['total'] += 1 logging.info(f"✓ {symbol} 空头信号入选: {signal.score:.1f}分 ({signal.strategy_type})") else: filtered_count += 1 logging.info(f"✗ {symbol} {signal.signal_type}信号过滤: {signal.score:.1f}分 < 80分") # 按分数排序 long_signals.sort(key=lambda x: x.score, reverse=True) short_signals.sort(key=lambda x: x.score, reverse=True) # 选择最优信号 - 统一70分门槛 def filter_quality_signals(signals): quality_signals = [] for signal in signals: # 只选择符合70分门槛的信号 if signal.score >= 80: # 优质信号优先 quality_signals.append(signal) elif len(quality_signals) < self.max_selections and signal.score >= 70: # 补充达标信号 quality_signals.append(signal) return quality_signals[:self.max_selections] selected_long_signals = filter_quality_signals(long_signals) selected_short_signals = filter_quality_signals(short_signals) # 详细统计信息 logging.info(f"\n{'='*60}") logging.info("批量选币分析完成 - 详细统计") logging.info(f"{'='*60}") logging.info(f"总币种数量: {len(market_data)}") logging.info(f"交易量过滤: {low_volume_count}个") logging.info(f"分数过滤: {filtered_count}个") logging.info(f"原始信号: 多头{len(long_signals)}个, 空头{len(short_signals)}个") logging.info(f"最终选择: 多头{len(selected_long_signals)}个, 空头{len(selected_short_signals)}个") # 策略分布统计 if strategy_stats: logging.info(f"\n策略使用分布:") for strategy, stats in sorted(strategy_stats.items(), key=lambda x: x[1]['total'], reverse=True): logging.info(f" {strategy}: {stats['total']}个信号 (多头{stats['long']}, 空头{stats['short']})") # 评分分布统计 if all_scores: logging.info(f"\n全部币种评分分布:") long_scores = [item['long_score'] for item in all_scores] short_scores = [item['short_score'] for item in all_scores] # 多头评分统计 long_high = len([s for s in long_scores if s >= 80]) long_medium = len([s for s in long_scores if 60 <= s < 80]) long_low = len([s for s in long_scores if 40 <= s < 60]) long_very_low = len([s for s in long_scores if s < 40]) logging.info(f" 多头评分分布: ≥80分({long_high}个), 60-79分({long_medium}个), 40-59分({long_low}个), <40分({long_very_low}个)") # 空头评分统计 short_high = len([s for s in short_scores if s >= 90]) short_medium = len([s for s in short_scores if 70 <= s < 90]) short_low = len([s for s in short_scores if 50 <= s < 70]) short_very_low = len([s for s in short_scores if s < 50]) logging.info(f" 空头评分分布: ≥90分({short_high}个), 70-89分({short_medium}个), 50-69分({short_low}个), <50分({short_very_low}个)") # 显示前10名多头和空头候选 top_long_candidates = sorted(all_scores, key=lambda x: x['long_score'], reverse=True)[:10] top_short_candidates = sorted(all_scores, key=lambda x: x['short_score'], reverse=True)[:10] logging.info(f"\n前10名多头候选:") for i, item in enumerate(top_long_candidates, 1): status = "✓入选" if any(s.symbol == item['symbol'] and s.signal_type == "LONG" for s in selected_long_signals) else "未选中" logging.info(f" {i:2d}. {item['symbol']:12s}: {item['long_score']:5.1f}分 ({item['strategy']}) - {status}") logging.info(f"\n前10名空头候选:") for i, item in enumerate(top_short_candidates, 1): status = "✓入选" if any(s.symbol == item['symbol'] and s.signal_type == "SHORT" for s in selected_short_signals) else "未选中" logging.info(f" {i:2d}. {item['symbol']:12s}: {item['short_score']:5.1f}分 ({item['strategy']}) - {status}") # 最终信号详情 if selected_long_signals: logging.info(f"\n最终多头信号详情:") for i, signal in enumerate(selected_long_signals, 1): logging.info(f" {i}. {signal.symbol}: {signal.score:.1f}分 ({signal.strategy_type}-{signal.confidence})") if selected_short_signals: logging.info(f"\n最终空头信号详情:") for i, signal in enumerate(selected_short_signals, 1): logging.info(f" {i}. {signal.symbol}: {signal.score:.1f}分 ({signal.strategy_type}-{signal.confidence})") return { 'long': selected_long_signals, 'short': selected_short_signals, 'all': selected_long_signals + selected_short_signals } # === 空头分析方法 === def analyze_bearish_volume_price(self, df: pd.DataFrame) -> float: """分析空头量价关系 (30分)""" if len(df) < 20: return 0 score = 0 recent_data = df.tail(15) # 计算价格和成交量的相关性 price_changes = recent_data['close'].pct_change().dropna() volume_changes = recent_data['volume'].pct_change().dropna() if len(price_changes) >= 10 and len(volume_changes) >= 10: # 分析下跌日的量价关系 down_days = price_changes < 0 down_price_changes = price_changes[down_days] down_volume_changes = volume_changes[down_days] if len(down_price_changes) >= 5: # 计算下跌日的量价相关性 correlation = down_price_changes.corr(down_volume_changes) if correlation < -0.5: # 强负相关(价跌量增) score += 15 elif correlation < -0.3: score += 10 elif correlation < -0.1: score += 5 # 分析最近5天的量价配合 recent_5 = df.tail(5) down_days_recent = (recent_5['close'].diff() < 0).sum() avg_volume_recent = recent_5['volume'].mean() avg_volume_before = df.iloc[-20:-5]['volume'].mean() if len(df) >= 20 else avg_volume_recent volume_ratio = avg_volume_recent / avg_volume_before if avg_volume_before > 0 else 1 # 下跌日多且成交量放大 if down_days_recent >= 3 and volume_ratio > 1.2: score += 15 return min(score, 30) def analyze_bearish_patterns(self, df: pd.DataFrame) -> float: """分析空头技术形态 (25分)""" if len(df) < 20: return 0 score = 0 # 使用talib的K线形态识别(空头形态) patterns = { 'hanging_man': talib.CDLHANGINGMAN(df['open'], df['high'], df['low'], df['close']), 'shooting_star': talib.CDLSHOOTINGSTAR(df['open'], df['high'], df['low'], df['close']), 'dark_cloud': talib.CDLDARKCLOUDCOVER(df['open'], df['high'], df['low'], df['close']), 'evening_star': talib.CDLEVENINGSTAR(df['open'], df['high'], df['low'], df['close']), 'three_black_crows': talib.CDL3BLACKCROWS(df['open'], df['high'], df['low'], df['close']), 'bearish_engulfing': talib.CDLENGULFING(df['open'], df['high'], df['low'], df['close']) } # 检查最近3天的K线形态 for pattern_name, pattern_data in patterns.items(): if len(pattern_data) > 3: # 检查最近3天是否有信号 for i in range(-3, 0): if pattern_data.iloc[i] < 0: # 看跌信号 if pattern_name in ['evening_star', 'three_black_crows', 'dark_cloud']: score += 6 # 强看跌形态 elif pattern_name in ['hanging_man', 'shooting_star']: score += 4 # 中度看跌形态 else: score += 3 # 弱看跌形态 break # 手动分析一些简单空头形态 manual_score = self._analyze_manual_bearish_patterns(df.tail(10)) score += manual_score return min(score, 25) def _analyze_manual_bearish_patterns(self, df: pd.DataFrame) -> float: """手动分析空头形态""" if len(df) < 5: return 0 score = 0 # 分析最近5天的走势 last_5 = df.tail(5) # 1. 阶段性高点下移模式 highs = last_5['high'].tolist() if len(highs) >= 3: # 检查是否有高点逐步下移的趋势 descending_highs = True for i in range(1, len(highs)): if highs[i] > highs[i-1] * 1.02: # 允许小幅波动 descending_highs = False break if descending_highs: score += 4 # 2. 跌破前低点模式 current_low = df.iloc[-1]['low'] prev_lows = df.iloc[-5:-1]['low'].tolist() if current_low < min(prev_lows) * 0.99: # 跌破前低 score += 3 return min(score, 7) def analyze_breakdown_potential(self, df: pd.DataFrame) -> float: """分析下跌突破潜力 (20分)""" if len(df) < 30: return 0 score = 0 current = df.iloc[-1] recent_data = df.tail(20) # 1. 价格位置分析 - 寻找做空机会 (8分) recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() price_range = recent_high - recent_low current_position = (current['close'] - recent_low) / price_range if price_range > 0 else 0 # 偏好在高位的币种 if 0.7 <= current_position <= 0.9: # 高位做空机会 score += 6 elif 0.5 <= current_position < 0.7: score += 3 elif current_position < 0.3: # 已经低位,做空机会不大 score -= 5 # 2. 顶部形态分析 (6分) volatility = recent_data['close'].std() / recent_data['close'].mean() if 0.08 <= volatility <= 0.15: # 高位整理,可能形成顶部 score += 5 elif volatility > 0.20: # 高波动,可能已经开始下跌 score += 3 # 3. 量能衰竭 (6分) volume_ratio = recent_data['volume'] / recent_data['volume'].rolling(10).mean() weak_volume_days = ((volume_ratio < 0.8)).sum() # 量能萱缩 if weak_volume_days >= 3: # 量能持续萱缩 score += 4 return max(min(score, 20), 0) def analyze_bearish_moving_average(self, df: pd.DataFrame) -> float: """分析空头均线系统 (10分)""" if len(df) < 50: return 0 score = 0 current = df.iloc[-1] # 1. 均线空头排列 if current['close'] < current['ma20'] < current['ma50']: score += 6 # 2. 价格跌破关键均线 prev = df.iloc[-2] if prev['close'] >= prev['ma20'] and current['close'] < current['ma20']: score += 3 # 3. 均线斜率向下 ma20_slope = (current['ma20'] - df.iloc[-5]['ma20']) / 5 if ma20_slope < 0: score += 1 return min(score, 10) def calculate_short_entry_exit_levels(self, df: pd.DataFrame, strategy: str) -> Tuple[float, float, float, float]: """计算空头入场、止损、止盈位""" current_price = df.iloc[-1]['close'] atr = df.iloc[-1]['atr'] support, resistance = self.find_support_resistance(df) config = self.strategies[strategy] # 空头入场价策略 ma20 = df.iloc[-1]['ma20'] ma50 = df.iloc[-1]['ma50'] # 策略1: 均线反弹入场 if current_price < ma20 < ma50: # 空头趋势 # 等待反弹至MA20附近做空 entry_price = ma20 * 0.98 # MA20下方2% else: # 策略2: 跌破确认入场 recent_low = df.tail(10)['low'].min() if current_price <= recent_low * 1.02: # 接近跌破 entry_price = recent_low * 0.995 # 跌破确认价位 else: # 策略3: 当前价格适当上方等待 entry_price = current_price * 1.005 # 当前价上方0.5% # 确保入场价不会过高(距离当前价不超过5%) if entry_price > current_price * 1.05: entry_price = current_price * 1.02 # 止损位: 阻力位上方或ATR的1.5倍 stop_loss_atr = entry_price + (atr * 1.5) stop_loss_resistance = resistance * 1.02 if resistance > 0 else entry_price * 1.08 stop_loss = min(stop_loss_atr, stop_loss_resistance) # 根据策略动态设置风险回报比 risk = stop_loss - entry_price target_ratio = (config.risk_reward_min + config.risk_reward_max) / 2 take_profit_ratio = entry_price - (risk * target_ratio) # 如果有支撑位,取较大值 if support > 0 and support < entry_price: take_profit_support = support * 1.02 take_profit = max(take_profit_ratio, take_profit_support) else: take_profit = take_profit_ratio # 计算实际风险回报比 actual_risk_reward = (entry_price - take_profit) / risk if risk > 0 else target_ratio return entry_price, stop_loss, take_profit, actual_risk_reward def generate_short_action_suggestion(self, df: pd.DataFrame, entry_price: float, current_price: float, score: float) -> str: """生成空头操作建议""" try: # 计算价格差异百分比 entry_diff = (current_price - entry_price) / entry_price * 100 # 获取技术指标状态 current = df.iloc[-1] recent_data = df.tail(10) # 计算价格在最近区间的位置 recent_high = recent_data['high'].max() recent_low = recent_data['low'].min() price_range = recent_high - recent_low current_position = (current_price - recent_low) / price_range if price_range > 0 else 0.5 # 基于评分等级的基础建议 if score >= 80: # 高分 if entry_diff >= -1: # 接近或高于建议价位 if current_position >= 0.7: # 在高位 return "立即做空" elif current_position >= 0.5: return "现价做空" else: return "等待反弹做空" elif entry_diff >= -3: # 稍低于建议价位 return "等待反弹做空" else: # 明显低于建议价位 return "等待大幅反弹" elif score >= 65: # 中等分数 if entry_diff <= 2: # 高于建议价位 return "现价做空" elif entry_diff <= -1: # 接近建议价位 if current_position >= 0.6: return "现价做空" else: return "等待反弹做空" elif entry_diff <= -5: # 低于建议价位 return "等待反弹做空" else: return "暂时观望" else: # 较低分数 if entry_diff <= 3: # 明显高于建议价位 return "小仓位做空" elif entry_diff <= 0: if current_position >= 0.8: return "小仓位试探" else: return "等待反弹做空" else: return "暂时观望" return "等待反弹做空" # 默认建议 except Exception as e: logging.error(f"生成空头操作建议时出错: {e}") return "谨慎观望" def test_strategy_distribution(self, market_data: Dict[str, Dict]) -> Dict[str, int]: """测试策略分布,确保所有策略都能被选中""" strategy_counts = {name: 0 for name in self.strategies.keys()} for symbol, data in list(market_data.items())[:20]: # 只测试前20个 timeframe_data = data.get('timeframes', {}) initial_df = timeframe_data.get('4h') if initial_df is not None and len(initial_df) >= 20: strategy = self.determine_best_strategy(initial_df) strategy_counts[strategy] += 1 logging.info(f"测试策略分布: {symbol} -> {strategy}") logging.info(f"策略分布测试结果: {strategy_counts}") return strategy_counts