""" 行情策略管理模块 - 支持多种策略 """ import logging import pandas as pd import numpy as np import pandas as pd from quote_manager import QuoteManager, DataSource from logger_utils_new import log_info, log_warning, log_error, log_trigger, log_debug, setup_logger, LOG_STYLES from abc import ABC, abstractmethod from enum import Enum, auto class StrategyType(Enum): TU_STRATEGY = auto() # 土策略 BREAKOUT_STRATEGY = auto() # 突破策略 MEAN_REVERSION_STRATEGY = auto() # 均值回归策略 class TradingStrategy(ABC): def __init__(self, quote_manager): self.quote_manager = quote_manager self.history_data = {} self.STOP_LOSS = 0.03 self.COMMISSION = 0.0003 self.MIN_TRADE_AMOUNT = 1e7 @abstractmethod def _analyze_signal(self, quote_data): """分析交易信号""" pass class TuStrategy(TradingStrategy): """土策略实现""" def analyze_signal(self, quote_data): # 现有的土策略分析逻辑 # ... 保留原有代码 ... signal = { 'code': quote_data['TS_CODE'], 'signal': 'buy' if quote_data['PRICE'] < quote_data['OPEN'] else 'sell', 'price': quote_data['PRICE'], 'volume': quote_data['VOLUME'], 'timestamp': pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S') } return signal class BreakoutStrategy(TradingStrategy): """突破策略实现""" def analyze_signal(self, quote_data): # 实现突破策略逻辑 # ... 新增代码 ... signal = { 'code': quote_data['TS_CODE'], 'signal': 'buy' if quote_data['PRICE'] > quote_data['OPEN'] else'sell', 'price': quote_data['PRICE'], 'volume': quote_data['VOLUME'], 'timestamp': pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S') } return signal class StrategyManager: def __init__(self, quote_manager): self.quote_manager = quote_manager self.strategies = { StrategyType.TU_STRATEGY: TuStrategy(quote_manager), StrategyType.BREAKOUT_STRATEGY: BreakoutStrategy(quote_manager) } self.current_strategy = StrategyType.TU_STRATEGY # 默认策略 def set_strategy(self, strategy_type): """设置当前使用的策略""" if strategy_type in self.strategies: self.current_strategy = strategy_type return True return False def monitor_stocks(self, stock_codes): """使用当前策略监控股票""" strategy = self.strategies[self.current_strategy] return strategy.monitor_stocks(stock_codes) class TradingStrategy(ABC): def __init__(self, quote_manager): self.quote_manager = QuoteManager() def monitor_stocks(self, stock_codes): """监控股票行情""" try: quotes = self.quote_manager.get_realtime_quotes(stock_codes) log_info(f"行情更新: {pd.Timestamp.now()}") signals = [] for code, data in quotes.items(): signal = self._analyze_signal(data) log_info(f"{code}: 最新价 {data['PRICE']} 成交量 {data['VOLUME']}") signals.append({ 'code': code, 'signal': signal, 'price': data['PRICE'], 'volume': data['VOLUME'], 'timestamp': pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S') }) return signals except Exception as e: log_error(f"获取行情失败: {str(e)}") return [] def __init__(self, quote_manager): self.quote_manager = quote_manager self.history_data = {} self.STOP_LOSS = 0.03 # 止损比例 self.COMMISSION = 0.0003 # 单边佣金 self.MIN_TRADE_AMOUNT = 1e7 # 最小成交金额 def _calculate_slope(self, x): """计算斜率""" if len(x) < 2: return np.nan n = len(x) sum_x = (n - 1) * n / 2 sum_xx = (n - 1) * n * (2 * n - 1) / 6 sum_y = np.sum(x) sum_xy = np.sum(np.arange(n) * x) denom = n * sum_xx - sum_x * sum_x if denom == 0: return np.nan return (n * sum_xy - sum_x * sum_y) / denom def _update_history_data(self, code, data): """更新历史数据""" if code not in self.history_data: self.history_data[code] = [] self.history_data[code].append(data) # 只保留最近30天数据 if len(self.history_data[code]) > 30: self.history_data[code] = self.history_data[code][-30:] return pd.DataFrame(self.history_data[code]) def _analyze_signal(self, quote_data): """基于土策略分析交易信号""" code = quote_data['TS_CODE'] df = self._update_history_data(code, quote_data) if len(df) < 25: # 确保有足够数据计算指标 return 'HOLD' # 计算技术指标 df = df.sort_values('TRADE_DATE') df['X_1'] = df['LOW'].rolling(10, min_periods=5).min() df['X_2'] = df['HIGH'].rolling(25, min_periods=10).max() df['X_6'] = ((df['CLOSE'] - df['X_1']) / (df['X_2'].replace(0, np.nan) - df['X_1']) * 4) df['X_6'] = df['X_6'].ewm(span=4, adjust=False).mean().shift(1) # 信号过滤条件 df['X_7'] = df['X_6'].rolling(5).apply( lambda x: 0 if (np.diff(x > 3.5) == 1).any() else 1, raw=True ).fillna(1) # 动量计算 df['X_10'] = df['CLOSE'].pct_change(2).shift(1) * 100 df['X_43'] = df['X_10'].rolling(2).sum() * df['X_7'] # 复合指标 ema_open_12 = df['OPEN'].ewm(span=12, adjust=False).mean() df['X_15'] = df['X_7'] * (df['OPEN'] - ema_open_12) / ema_open_12 * 200 # 斜率计算 df['X_41'] = df['X_15'].rolling(2).apply(self._calculate_slope) df['X_42'] = df['X_6'].rolling(2).apply(self._calculate_slope) # 最终土值计算 df['tu_value'] = (df['X_41'] * 0.02 - df['X_42'] * df['X_7']) * df['X_7'] # 过滤条件 current = df.iloc[-1] if (current['X_43'] > 8 and not current['CODE'].startswith(('313', '314', '315', '688')) and current['AMOUNT'] > self.MIN_TRADE_AMOUNT and not np.isnan(current['tu_value'])): return 'BUY' if current['tu_value'] > 0 else 'SELL' return 'HOLD'