""" 缠论综合分析器:整合所有核心模块进行完整的缠论分析 """ import pandas as pd import numpy as np from typing import Dict, List, Optional, Tuple import logging from .kline import KLine from .fractal import Fractal, FractalPoint from .stroke import Stroke, StrokeElement from .segment import Segment, SegmentElement from .central_bank import CentralBank, CentralBankElement from .trading_signal import TradingSignal, TradingPoint logger = logging.getLogger(__name__) class ChanAnalyzer: """缠论综合分析器""" def __init__(self, kline_data: pd.DataFrame): """ 初始化缠论分析器 Args: kline_data: 原始K线数据 """ self.original_data = kline_data.copy() self.processed_data = None # 各模块实例 self.kline_processor = None self.fractal_detector = None self.stroke_detector = None self.segment_detector = None self.central_bank_detector = None self.trading_signal_detector = None # 分析结果 self.fractals = [] self.strokes = [] self.segments = [] self.central_banks = [] self.trading_points = [] # 分析状态 self.is_analyzed = False def run_full_analysis(self, fractal_strength: int = 1) -> Dict: """ 运行完整的缠论分析 Args: fractal_strength: 分型强度要求 Returns: 分析结果摘要 """ logger.info("开始完整缠论分析...") try: # 1. 处理K线包含关系 self._process_klines() # 2. 识别分型 self._detect_fractals(fractal_strength) # 3. 生成笔 self._detect_strokes() # 4. 生成线段 self._detect_segments() # 5. 识别中枢 self._detect_central_banks() # 6. 识别买卖点 self._detect_trading_signals() self.is_analyzed = True # 生成分析摘要 summary = self._generate_analysis_summary() logger.info("缠论分析完成") return summary except Exception as e: logger.error(f"缠论分析失败: {e}") raise def _process_klines(self): """处理K线包含关系""" logger.info("处理K线包含关系...") self.kline_processor = KLine(self.original_data) self.processed_data = self.kline_processor.get_processed_data() logger.info(f"K线处理完成:{len(self.original_data)} -> {len(self.processed_data)}") def _detect_fractals(self, strength: int = 1): """识别分型""" logger.info("识别分型...") self.fractal_detector = Fractal(self.processed_data, min_strength=strength) self.fractals = self.fractal_detector.detect_fractals() logger.info(f"分型识别完成:共 {len(self.fractals)} 个") def _detect_strokes(self): """生成笔""" logger.info("生成笔...") if not self.fractals: logger.warning("没有分型,无法生成笔") return self.stroke_detector = Stroke(self.fractals, self.processed_data) self.strokes = self.stroke_detector.detect_strokes() logger.info(f"笔生成完成:共 {len(self.strokes)} 个") def _detect_segments(self): """生成线段""" logger.info("生成线段...") if not self.strokes: logger.warning("没有笔,无法生成线段") return self.segment_detector = Segment(self.strokes) self.segments = self.segment_detector.detect_segments() logger.info(f"线段生成完成:共 {len(self.segments)} 个") def _detect_central_banks(self): """识别中枢""" logger.info("识别中枢...") if not self.segments: logger.warning("没有线段,无法识别中枢") return self.central_bank_detector = CentralBank(self.segments) self.central_banks = self.central_bank_detector.detect_central_banks() logger.info(f"中枢识别完成:共 {len(self.central_banks)} 个") def _detect_trading_signals(self): """识别买卖点""" logger.info("识别买卖点...") self.trading_signal_detector = TradingSignal( self.central_banks, self.segments, self.strokes ) # 检测中枢相关的买卖点 central_bank_signals = [] if self.central_banks: central_bank_signals = self.trading_signal_detector.detect_all_trading_points() # 如果中枢数量不足,增加基于分型的买卖点识别 fractal_signals = [] if len(self.central_banks) < 2 and self.fractals: logger.info("中枢数量不足,启用分型买卖点识别") fractal_signals = self.trading_signal_detector.detect_fractal_based_signals( self.fractals, self.processed_data ) # 合并所有信号 all_signals = central_bank_signals + fractal_signals # 去重和排序 unique_signals = [] seen_keys = set() for signal in sorted(all_signals, key=lambda x: x.timestamp): # 创建唯一键:时间+类型+类别 key = f"{signal.timestamp.strftime('%Y%m%d%H%M')}_{signal.signal_type}_{signal.point_class}" if key not in seen_keys: unique_signals.append(signal) seen_keys.add(key) self.trading_points = unique_signals # 统计信号 central_count = len(central_bank_signals) fractal_count = len(fractal_signals) total_count = len(unique_signals) class_counts = {'first': 0, 'second': 0, 'third': 0} for signal in unique_signals: class_counts[signal.point_class] += 1 logger.info(f"买卖点识别完成:中枢相关 {central_count} 个,分型相关 {fractal_count} 个," f"一类 {class_counts['first']} 个,二类 {class_counts['second']} 个," f"三类 {class_counts['third']} 个,总计 {total_count} 个") def _generate_analysis_summary(self) -> Dict: """生成分析摘要""" summary = { 'data_info': { 'original_klines': len(self.original_data), 'processed_klines': len(self.processed_data) if self.processed_data is not None else 0, 'date_range': { 'start': self.original_data.index.min(), 'end': self.original_data.index.max() } }, 'fractal_info': { 'total': len(self.fractals), 'top': len([f for f in self.fractals if f.fractal_type == 'top']), 'bottom': len([f for f in self.fractals if f.fractal_type == 'bottom']) }, 'stroke_info': { 'total': len(self.strokes), 'up': len([s for s in self.strokes if s.direction == 1]), 'down': len([s for s in self.strokes if s.direction == -1]) }, 'segment_info': { 'total': len(self.segments), 'up': len([s for s in self.segments if s.direction == 1]), 'down': len([s for s in self.segments if s.direction == -1]) }, 'central_bank_info': { 'total': len(self.central_banks), 'levels': self._get_central_bank_levels() }, 'trading_signal_info': { 'total': len(self.trading_points), 'buy_points': len([p for p in self.trading_points if p.signal_type == 'buy']), 'sell_points': len([p for p in self.trading_points if p.signal_type == 'sell']), 'by_class': self._get_signal_class_distribution() } } return summary def _get_central_bank_levels(self) -> Dict: """获取中枢级别分布""" levels = {} for cb in self.central_banks: levels[cb.level] = levels.get(cb.level, 0) + 1 return levels def _get_signal_class_distribution(self) -> Dict: """获取买卖点类别分布""" distribution = {} for point in self.trading_points: key = f"{point.point_class}_class" distribution[key] = distribution.get(key, 0) + 1 return distribution def get_latest_signals(self, hours: int = 24) -> List[TradingPoint]: """ 获取最近的买卖点信号 Args: hours: 最近多少小时 Returns: 最近的信号列表 """ if not self.is_analyzed or not self.trading_points: return [] latest_time = self.processed_data.index[-1] cutoff_time = latest_time - pd.Timedelta(hours=hours) return [p for p in self.trading_points if p.timestamp >= cutoff_time] def get_current_market_structure(self) -> Dict: """ 获取当前市场结构 Returns: 当前市场结构信息 """ if not self.is_analyzed: return {} current_price = self.processed_data['close'].iloc[-1] current_time = self.processed_data.index[-1] # 最近的中枢 recent_central_banks = [cb for cb in self.central_banks if (current_time - cb.end_time).total_seconds() < 7*24*3600] # 7天内 # 最近的线段趋势 recent_segments = [seg for seg in self.segments if (current_time - seg.end_time).total_seconds() < 3*24*3600] # 3天内 # 当前趋势方向 current_trend = self._determine_current_trend(recent_segments) # 支撑阻力位 support_resistance = self._calculate_support_resistance(recent_central_banks) return { 'current_price': current_price, 'current_time': current_time, 'trend': current_trend, 'recent_central_banks': len(recent_central_banks), 'support_resistance': support_resistance, 'market_phase': self._determine_market_phase() } def _determine_current_trend(self, recent_segments: List[SegmentElement]) -> str: """确定当前趋势""" if not recent_segments: return "unclear" # 按时间排序取最近3个线段 recent_segments = sorted(recent_segments, key=lambda x: x.end_time)[-3:] up_count = sum(1 for seg in recent_segments if seg.direction == 1) down_count = sum(1 for seg in recent_segments if seg.direction == -1) if up_count > down_count: return "upward" elif down_count > up_count: return "downward" else: return "sideways" def _calculate_support_resistance(self, central_banks: List[CentralBankElement]) -> Dict: """计算支撑阻力位""" if not central_banks: return {} # 按强度排序,取最强的几个中枢 strong_cbs = sorted(central_banks, key=lambda x: x.strength, reverse=True)[:3] supports = [] resistances = [] for cb in strong_cbs: supports.append(cb.low_price) resistances.append(cb.high_price) return { 'support_levels': sorted(supports), 'resistance_levels': sorted(resistances, reverse=True) } def _determine_market_phase(self) -> str: """确定市场阶段""" if not self.central_banks: return "unknown" # 最近的中枢 latest_cb = self.central_banks[-1] if self.central_banks else None if not latest_cb: return "trending" current_time = self.processed_data.index[-1] time_since_cb = (current_time - latest_cb.end_time).total_seconds() / 3600 # 小时 if time_since_cb < 24: return "consolidation" # 盘整 else: return "trending" # 趋势 def export_results(self) -> Dict[str, pd.DataFrame]: """ 导出所有分析结果 Returns: 包含各种分析结果的DataFrame字典 """ if not self.is_analyzed: raise ValueError("尚未进行分析,请先调用 run_full_analysis()") results = {} # 处理后的K线数据 if self.processed_data is not None: results['klines'] = self.processed_data # 分型数据 if self.fractal_detector: results['fractals'] = self.fractal_detector.to_dataframe() # 笔数据 if self.stroke_detector: results['strokes'] = self.stroke_detector.to_dataframe() # 线段数据 if self.segment_detector: results['segments'] = self.segment_detector.to_dataframe() # 中枢数据 if self.central_bank_detector: results['central_banks'] = self.central_bank_detector.to_dataframe() # 买卖点数据 if self.trading_signal_detector: results['trading_signals'] = self.trading_signal_detector.to_dataframe() return results def get_visualization_data(self) -> Dict: """ 获取可视化所需的数据 Returns: 可视化数据字典 """ if not self.is_analyzed: return {} return { 'klines': self.processed_data, 'fractals': self.fractals, 'strokes': self.strokes, 'segments': self.segments, 'central_banks': self.central_banks, 'trading_points': self.trading_points }