Files
real_view/strategy.py
2025-07-28 12:15:45 +08:00

187 lines
6.4 KiB
Python

"""
行情策略管理模块 - 支持多种策略
"""
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'