Files
sanguo_quant_live/zhaoyun-data/strategies/pure-breakout-20260327/backtest

纯突破策略回测系统目录

🏗️ 回测系统架构

1. 系统整体架构

纯突破策略回测系统
├── 数据层 (Data Layer)
│   ├── 历史数据加载 (HistoricalDataLoader)
│   ├── 实时数据模拟 (RealtimeDataSimulator)
│   └── 数据质量验证 (DataQualityValidator)
├── 策略层 (Strategy Layer)
│   ├── 突破信号检测 (BreakoutSignalDetector)
│   ├── 买卖规则执行 (TradingRuleExecutor)
│   ├── 仓位管理 (PositionManager)
│   └── 风险控制 (RiskController)
├── 执行层 (Execution Layer)
│   ├── 交易模拟 (TradeSimulator)
│   ├── 成本计算 (CostCalculator)
│   └── 滑点模拟 (SlippageSimulator)
├── 分析层 (Analysis Layer)
│   ├── 绩效分析 (PerformanceAnalyzer)
│   ├── 风险分析 (RiskAnalyzer)
│   ├── 交易分析 (TradeAnalyzer)
│   └── 归因分析 (AttributionAnalyzer)
└── 报告层 (Report Layer)
    ├── 报告生成 (ReportGenerator)
    ├── 可视化 (Visualization)
    └── 结果存储 (ResultStorage)

2. 回测引擎实现

2.1 回测引擎基类

# backtest/engine/base_backtester.py
from abc import ABC, abstractmethod
import pandas as pd
from typing import Dict, List, Optional
from dataclasses import dataclass

@dataclass
class TradeRecord:
    """交易记录"""
    date: str
    stock_code: str
    action: str  # 'buy' or 'sell'
    price: float
    quantity: int
    amount: float
    commission: float
    reason: str  # 交易原因

@dataclass
class Position:
    """持仓信息"""
    stock_code: str
    buy_date: str
    buy_price: float
    quantity: int
    current_price: float
    highest_price: float  # 用于移动止损
    holding_days: int

class BaseBacktester(ABC):
    """回测引擎基类"""
    
    def __init__(self, config: Dict):
        self.config = config
        self.initial_capital = config.get('initial_capital', 10000000)
        self.current_capital = self.initial_capital
        self.positions: Dict[str, Position] = {}
        self.trade_records: List[TradeRecord] = []
        self.portfolio_values: List[Dict] = []
        self.daily_returns: List[float] = []
        
    @abstractmethod
    def run(self) -> Dict:
        """运行回测"""
        pass
    
    @abstractmethod
    def detect_signals(self, date: str) -> List[Dict]:
        """检测交易信号"""
        pass
    
    @abstractmethod
    def execute_trades(self, date: str, signals: List[Dict]) -> None:
        """执行交易"""
        pass
    
    def calculate_portfolio_value(self, date: str) -> float:
        """计算组合价值"""
        stock_value = sum(
            position.quantity * position.current_price 
            for position in self.positions.values()
        )
        return self.current_capital + stock_value
    
    def record_portfolio_value(self, date: str) -> None:
        """记录组合价值"""
        portfolio_value = self.calculate_portfolio_value(date)
        self.portfolio_values.append({
            'date': date,
            'value': portfolio_value,
            'cash': self.current_capital,
            'stock_value': portfolio_value - self.current_capital,
            'positions_count': len(self.positions)
        })

2.2 突破策略回测器

# backtest/engine/breakout_backtester.py
from .base_backtester import BaseBacktester, TradeRecord, Position
import pandas as pd

class BreakoutBacktester(BaseBacktester):
    """突破策略回测器"""
    
    def __init__(self, config: Dict):
        super().__init__(config)
        self.breakout_detector = BreakoutDetector(config['breakout'])
        self.buy_rules = BuyRules(config['buy'])
        self.sell_rules = SellRules(config['sell'])
        self.position_rules = PositionRules(config['position'])
        
    def run(self) -> Dict:
        """运行突破策略回测"""
        results = {
            'portfolio_values': [],
            'trade_records': [],
            'performance_metrics': {},
            'risk_metrics': {},
            'trade_statistics': {}
        }
        
        # 获取回测日期范围
        dates = self.get_trading_dates(
            self.config['start_date'],
            self.config['end_date']
        )
        
        print(f"开始回测: {self.config['start_date']}{self.config['end_date']}")
        print(f"回测天数: {len(dates)}")
        print(f"初始资金: {self.initial_capital:,.0f}元")
        
        for i, date in enumerate(dates):
            if i % 100 == 0:
                print(f"进度: {i}/{len(dates)} ({i/len(dates)*100:.1f}%)")
            
            # 1. 更新持仓价格
            self._update_positions(date)
            
            # 2. 检测买入信号
            buy_signals = self._detect_buy_signals(date)
            
            # 3. 执行买入交易
            if buy_signals:
                self._execute_buy_trades(date, buy_signals)
            
            # 4. 检测卖出信号
            sell_signals = self._detect_sell_signals(date)
            
            # 5. 执行卖出交易
            if sell_signals:
                self._execute_sell_trades(date, sell_signals)
            
            # 6. 记录组合价值
            self.record_portfolio_value(date)
        
        # 7. 计算绩效指标
        results = self._calculate_performance()
        
        return results
    
    def _detect_buy_signals(self, date: str) -> List[Dict]:
        """检测买入信号"""
        buy_signals = []
        
        # 获取当日市场数据
        market_data = self.data_loader.get_market_data(date)
        
        for stock_data in market_data:
            # 检测突破信号
            breakout_signal = self.breakout_detector.detect(stock_data)
            
            if breakout_signal:
                # 生成买入信号
                buy_signal = self.buy_rules.generate_signal(
                    breakout_signal, stock_data
                )
                
                if buy_signal:
                    # 检查仓位限制
                    if self.position_rules.can_open_position(
                        self.positions, buy_signal
                    ):
                        buy_signals.append(buy_signal)
        
        return buy_signals
    
    def _detect_sell_signals(self, date: str) -> List[Dict]:
        """检测卖出信号"""
        sell_signals = []
        
        for stock_code, position in self.positions.items():
            # 获取当前价格
            current_price = self.data_loader.get_current_price(stock_code, date)
            
            # 检查止盈条件
            if self.sell_rules.check_take_profit(position, current_price):
                sell_signals.append({
                    'stock_code': stock_code,
                    'action': 'sell',
                    'reason': 'take_profit',
                    'price': current_price
                })
            
            # 检查止损条件
            elif self.sell_rules.check_stop_loss(position, current_price):
                sell_signals.append({
                    'stock_code': stock_code,
                    'action': 'sell',
                    'reason': 'stop_loss',
                    'price': current_price
                })
            
            # 检查强制卖出条件
            elif self.sell_rules.check_force_sell(position, current_price, date):
                sell_signals.append({
                    'stock_code': stock_code,
                    'action': 'sell',
                    'reason': 'force_sell',
                    'price': current_price
                })
        
        return sell_signals
    
    def _execute_buy_trades(self, date: str, buy_signals: List[Dict]) -> None:
        """执行买入交易"""
        for signal in buy_signals:
            # 计算买入金额
            buy_amount = self._calculate_buy_amount(signal)
            
            if buy_amount <= self.current_capital:
                # 计算买入价格(考虑滑点)
                buy_price = self._calculate_buy_price(signal)
                
                # 计算交易数量
                quantity = int(buy_amount / buy_price / 100) * 100  # 整手交易
                
                # 计算交易成本
                commission = self.cost_calculator.calculate_commission(
                    buy_amount, 'buy'
                )
                
                # 执行买入
                self._execute_buy(
                    date=date,
                    stock_code=signal['stock_code'],
                    price=buy_price,
                    quantity=quantity,
                    commission=commission,
                    reason=signal['reason']
                )
    
    def _execute_sell_trades(self, date: str, sell_signals: List[Dict]) -> None:
        """执行卖出交易"""
        for signal in sell_signals:
            stock_code = signal['stock_code']
            
            if stock_code in self.positions:
                position = self.positions[stock_code]
                
                # 计算卖出价格(考虑滑点)
                sell_price = self._calculate_sell_price(signal)
                
                # 计算交易成本(包括印花税)
                sell_amount = position.quantity * sell_price
                commission = self.cost_calculator.calculate_commission(
                    sell_amount, 'sell'
                )
                
                # 执行卖出
                self._execute_sell(
                    date=date,
                    stock_code=stock_code,
                    price=sell_price,
                    quantity=position.quantity,
                    commission=commission,
                    reason=signal['reason']
                )
    
    def _calculate_performance(self) -> Dict:
        """计算绩效指标"""
        performance_analyzer = PerformanceAnalyzer()
        
        # 计算收益指标
        returns = performance_analyzer.calculate_returns(self.portfolio_values)
        
        # 计算风险指标
        risk = performance_analyzer.calculate_risk(self.portfolio_values)
        
        # 计算交易统计
        trade_stats = performance_analyzer.analyze_trades(self.trade_records)
        
        # 计算基准对比
        benchmark_comparison = performance_analyzer.compare_with_benchmark(
            self.portfolio_values, self.config['benchmark']
        )
        
        return {
            'returns': returns,
            'risk': risk,
            'trade_statistics': trade_stats,
            'benchmark_comparison': benchmark_comparison
        }

3. 绩效分析模块

3.1 绩效计算器

# backtest/analysis/performance_analyzer.py
import numpy as np
import pandas as pd
from typing import List, Dict

class PerformanceAnalyzer:
    """绩效分析器"""
    
    def calculate_returns(self, portfolio_values: List[Dict]) -> Dict:
        """计算收益指标"""
        values = [pv['value'] for pv in portfolio_values]
        dates = [pv['date'] for pv in portfolio_values]
        
        # 计算收益率序列
        returns = []
        for i in range(1, len(values)):
            daily_return = (values[i] - values[i-1]) / values[i-1]
            returns.append(daily_return)
        
        # 计算累计收益率
        cumulative_return = (values[-1] - values[0]) / values[0]
        
        # 计算年化收益率
        total_days = len(dates)
        years = total_days / 252  # 假设一年252个交易日
        annual_return = (1 + cumulative_return) ** (1/years) - 1
        
        # 计算日收益率统计
        daily_returns = pd.Series(returns)
        
        return {
            'cumulative_return': cumulative_return,
            'annual_return': annual_return,
            'daily_returns_mean': daily_returns.mean(),
            'daily_returns_std': daily_returns.std(),
            'positive_days': (daily_returns > 0).sum(),
            'negative_days': (daily_returns < 0).sum(),
            'max_single_day_gain': daily_returns.max(),
            'max_single_day_loss': daily_returns.min()
        }
    
    def calculate_risk(self, portfolio_values: List[Dict]) -> Dict:
        """计算风险指标"""
        values = [pv['value'] for pv in portfolio_values]
        
        # 计算最大回撤
        max_drawdown = self._calculate_max_drawdown(values)
        
        # 计算波动率
        returns = []
        for i in range(1, len(values)):
            daily_return = (values[i] - values[i-1]) / values[i-1]
            returns.append(daily_return)
        
        annual_volatility = np.std(returns) * np.sqrt(252)
        
        # 计算夏普比率(假设无风险利率3%
        risk_free_rate = 0.03
        annual_return = self.calculate_returns(portfolio_values)['annual_return']
        sharpe_ratio = (annual_return - risk_free_rate) / annual_volatility
        
        # 计算Calmar比率
        calmar_ratio = annual_return / max_drawdown if max_drawdown > 0 else 0
        
        return {
            'max_drawdown': max_drawdown,
            'annual_volatility': annual_volatility,
            'sharpe_ratio': sharpe_ratio,
            'calmar_ratio': calmar_ratio,
            'value_at_risk_95': np.percentile(returns, 5),
            'expected_shortfall_95': np.mean([r for r in returns if r <= np.percentile(returns, 5)])
        }
    
    def _calculate_max_drawdown(self, values: List[float]) -> float:
        """计算最大回撤"""
        peak = values[0]
        max_dd = 0
        
        for value in values:
            if value > peak:
                peak = value
            dd = (peak - value) / peak
            if dd > max_dd:
                max_dd = dd
        
        return max_dd
    
    def analyze_trades(self, trade_records: List[TradeRecord]) -> Dict:
        """分析交易统计"""
        if not trade_records:
            return {}
        
        # 分离买入和卖出记录
        buy_trades = [t for t in trade_records if t.action == 'buy']
        sell_trades = [t for t in trade_records if t.action == 'sell']
        
        # 计算交易统计
        total_trades = len(buy_trades) + len(sell_trades)
        
        # 计算胜率
        winning_trades = sum(1 for t in sell_trades if t.amount > 0)
        win_rate = winning_trades / len(sell_trades) if sell_trades else 0
        
        # 计算平均盈亏
        if sell_trades:
            avg_profit = np.mean([t.amount for t in sell_trades])
            avg_win = np.mean([t.amount for t in sell_trades if t.amount > 0])
            avg_loss = np.mean([t.amount for t in sell_trades if t.amount < 0])
        else:
            avg_profit = avg_win = avg_loss = 0
        
        # 计算盈亏比
        profit_factor = abs(avg_win / avg_loss) if avg_loss != 0 else 0
        
        return {
            'total_trades': total_trades,
            'buy_trades': len(buy_trades),
            'sell_trades': len(sell_trades),
            'win_rate': win_rate,
            'avg_profit_per_trade': avg_profit,
            'avg_winning_trade': avg_win,
            'avg_losing_trade': avg_loss,
            'profit_factor': profit_factor,
            'max_consecutive_wins': self._calculate_max_consecutive_wins(sell_trades),
            'max_consecutive_losses': self._calculate_max_consecutive_losses(sell_trades)
        }
    
    def compare_with_benchmark(self, portfolio_values: List[Dict], 
                              benchmark_config: Dict) -> Dict:
        """与基准对比"""
        # 获取基准数据
        benchmark_values = self._get_benchmark_values(benchmark_config)
        
        # 计算超额收益
        portfolio_returns = self._calculate_portfolio_returns(portfolio_values)
        benchmark_returns = self._calculate_benchmark_returns(benchmark_values)
        
        # 计算信息比率
        excess_returns = portfolio_returns - benchmark_returns
        information_ratio = np.mean(excess_returns) / np.std(excess_returns)
        
        # 计算跟踪误差
        tracking_error = np.std(excess_returns)
        
        # 计算Beta系数
        covariance = np.cov(portfolio_returns, benchmark_returns)[0, 1]
        benchmark_variance = np.var(benchmark_returns)
        beta = covariance / benchmark_variance if benchmark_variance > 0 else 0
        
        # 计算Alpha
        alpha = np.mean(portfolio_returns) - beta * np.mean(benchmark_returns)
        
        return {
            'information_ratio': information_ratio,
            'tracking_error': tracking_error,
            'beta': beta,
            'alpha': alpha,
            'excess_return': np.mean(excess_returns),
            'up_capture': self._calculate_up_capture(portfolio_returns, benchmark_returns),
            'down_capture': self._calculate_down_capture(portfolio_returns, benchmark_returns)
        }

4. 可视化模块

4.1 绩效可视化

# backtest/visualization/performance_charts.py
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Dict, List

class PerformanceCharts:
    """绩效图表"""
    
    def plot_equity_curve(self, portfolio_values: List[Dict], 
                         benchmark_values: List[Dict] = None) -> None:
        """绘制净值曲线"""
        dates = [pv['date'] for pv in portfolio_values]
        values = [pv['value'] for pv in portfolio_values]
        
        plt.figure(figsize=(12, 6))
        plt.plot(dates, values, label='策略净值', linewidth=2)
        
        if benchmark_values:
            benchmark_dates = [bv['date'] for bv in benchmark_values]
            benchmark_vals = [bv['value'] for bv in benchmark_values]
            plt.plot(benchmark_dates, benchmark_vals, label='基准净值', 
                    linewidth=1, alpha=0.7)
        
        plt.title('净值曲线对比')
        plt.xlabel('日期')
        plt.ylabel('净值')
        plt.legend()
        plt.grid(True, alpha=0.3)
        plt.show()
    
    def plot_drawdown(self, portfolio_values: List[Dict]) -> None:
        """绘制回撤曲线"""
        values = [pv['value'] for pv in portfolio_values]
        dates = [pv['date'] for pv in portfolio_values]
        
        # 计算回撤
        drawdowns = []
        peak = values[0]
        
        for value in values:
            if value > peak:
                peak = value
            drawdown = (peak - value) / peak
            drawdowns.append(drawdown)
        
        plt.figure(figsize=(12, 4))
        plt.fill_between(dates, 0, drawdowns, color='red', alpha=0.3)
        plt.plot(dates, drawdowns, color='red', linewidth=1)
        plt.title('回撤曲线')
        plt.xlabel('日期')
        plt.ylabel('回撤')
        plt.grid(True, alpha=0.3)
        plt.show()
    
    def plot_monthly_returns(self, portfolio_values: List[Dict]) -> None:
        """绘制月度收益热力图"""
        # 计算月度收益
        monthly_returns = self._calculate_monthly_returns(portfolio_values)
        
        # 创建热力图数据
        years = sorted(set([mr['year'] for mr in monthly_returns]))
        months = list(range(1, 13))
        
        heatmap_data = []
        for year in years:
            year_data = []
            for month in months:
                monthly_return = next(
                    (mr['return'] for mr in monthly_returns 
                     if mr['year'] == year and mr['month'] == month), 0
                )
                year_data.append(monthly_return)
            heatmap_data.append(year_data)
        
        # 绘制热力图
        plt.figure(figsize=(10, 6))
        sns.heatmap(heatmap_data, annot=True, fmt='.1%', 
                   xticklabels=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
                   yticklabels=years, cmap='RdYlGn', center=0)
        plt.title('月度收益热力图 (%)')
        plt.show()

5. 目录结构

backtest/
├── README.md                      # 本说明文件
├── engine/                        # 回测引擎
│   ├── __init__.py
│   ├── base_backtester.py         # 回测基类
│   ├── breakout_backtester.py     # 突破策略回测器
│   ├── signal_detector.py         # 信号检测器
│   └── trade_executor.py          # 交易执行器
├── analysis/                      # 绩效分析
│   ├── __init__.py
│   ├── performance_analyzer.py    # 绩效分析器
│   ├── risk_analyzer.py           # 风险分析器
│   ├── trade_analyzer.py          # 交易分析器
│   └── attribution_analyzer.py    # 归因分析器
├── visualization/                 # 可视化
│   ├── __init__.py
│   ├── performance_charts.py      # 绩效图表
│   ├── risk_charts.py             # 风险图表
│   └── trade_charts.py            # 交易图表
├── data/                          # 回测数据
│   ├── market_data/
│   ├── benchmark_data/
│   └── processed_data/
├── configs/                       # 回测配置
│   ├── backtest_config.yaml       # 回测参数配置
│   └── strategy_config.yaml       # 策略参数配置
├── results/                       # 回测结果
│   ├── performance_reports/
│   ├── trade_records/
│   └── visualization_results/
└── tests/                         # 测试
    ├── test_backtester.py
    ├── test_analyzer.py
    └── test_visualization.py

6. 使用指南

6.1 运行回测

# backtest/run_backtest.py
from backtest.engine.breakout_backtester import BreakoutBacktester
from backtest.analysis.performance_analyzer import PerformanceAnalyzer
from backtest.visualization.performance_charts import PerformanceCharts

# 1. 加载配置
import yaml
with open('configs/backtest_config.yaml', 'r') as f:
    config = yaml.safe_load(f)

# 2. 创建回测器
backtester = BreakoutBacktester(config)

# 3. 运行回测
results = backtester.run()

# 4. 分析绩效
analyzer = PerformanceAnalyzer()
performance_report = analyzer.analyze_results(results)

# 5. 可视化结果
charts = PerformanceCharts()
charts.plot_equity_curve(results['portfolio_values'])
charts.plot_drawdown(results['portfolio_values'])
charts.plot_monthly_returns(results['portfolio_values'])

# 6. 保存结果
backtester.save_results(results, 'results/backtest_results.json')

6.2 参数优化

# backtest/optimization/parameter_optimizer.py
class ParameterOptimizer:
    """参数优化器"""
    
    def optimize_breakout_period(self, config: Dict) -> Dict:
        """优化突破周期参数"""
        # 定义参数空间
        period_range = range(20, 121, 5)  # 20-120天,步长5天
        
        best_period = None
        best_sharpe = -float('inf')
        
        for period in period_range:
            # 更新配置
            config['breakout']['period'] = period
            
            # 运行回测
            backtester = BreakoutBacktester(config)
            results = backtester.run()
            
            # 评估绩效
            sharpe = results['performance_metrics']['sharpe_ratio']
            
            if sharpe > best_sharpe:
                best_sharpe = sharpe
                best_period = period
        
        return {
            'best_period': best_period,
            'best_sharpe': best_sharpe
        }

7. 当前状态

已完成

  • 回测系统架构设计
  • 回测引擎框架实现
  • 绩效分析模块设计

🔄 进行中

  • 突破信号检测器实现
  • 交易执行模块开发
  • 可视化模块开发

待开始

  • 参数优化工具开发
  • 多进程回测支持
  • 实时监控系统

8. 联系人

回测开发负责人: 待定(开发团队)
数据支持: 赵云(数据工程将军)
策略验证: 待定(量化研究团队)

开发状态: 回测系统设计完成,开始技术实现
预计完成: 基础回测框架本周内完成