Skip to content

量化回测教程 ​

🧪 回测 = 用历史数据验证你的策略 —— 没有经过回测的策略都是"盲猜"。

🎯 为什么需要回测? ​

痛点回测的作用
"我以为这个策略能赚钱"历史数据验证
"我以为均线金叉能涨"看胜率几何
"我以为我比市场聪明"数据让你清醒
"我以为回撤小"真实回测数据

📋 教程大纲 ​

阶段内容时长
1. 环境搭建Python + Backtrader 安装30 分钟
2. 第一个策略MA 金叉买入1 小时
3. 回测结果分析收益率 / 最大回撤 / 夏普30 分钟
4. 优化策略加入止损 / 仓位管理2 小时
5. 完整策略多因子 + 风险管理半天

🛠️ 1. 环境搭建 ​

1.1 安装 Python ​

bash
# 推荐 Python 3.10+
python --version

# 如果没装,去官网下载:https://www.python.org/downloads/
# 或用 Anaconda:https://www.anaconda.com/

1.2 创建虚拟环境 ​

bash
# macOS / Linux
python3 -m venv ~/backtest-env
source ~/backtest-env/bin/activate

# Windows
python -m venv C:\backtest-env
C:\backtest-env\Scripts\activate

1.3 安装依赖 ​

bash
pip install backtrader
pip install akshare            # A 股数据源
pip install matplotlib          # 画图
pip install pandas numpy        # 数据处理
pip install jupyter            # 可选:Jupyter Notebook

1.4 安装 Ta-Lib(可选) ​

Ta-Lib 是技术分析库,Backtrader 支持它作为指标源。

bash
# macOS
brew install ta-lib
pip install TA-Lib

# Ubuntu
sudo apt-get install ta-lib
pip install TA-Lib

# Windows
# 1. 下载 wheel 文件:https://github.com/cgohlke/talib-build/releases
# 2. pip install TA_Lib‑0.4.xx‑cp3x‑cp3xm‑win_amd64.whl

🎯 2. 第一个策略 ​

2.1 完整代码 ​

python
"""
策略:MA 金叉买入,死叉卖出
标的:贵州茅台(600519)
时间:2020-01-01 至 2024-12-31
"""
import backtrader as bt
import akshare as ak
import datetime
import pandas as pd

# ============ 1. 获取数据 ============
def get_data(symbol='600519', start='20200101', end='20241231'):
    """从 akshare 获取 A 股数据,转为 Backtrader 格式"""
    df = ak.stock_zh_a_hist(
        symbol=symbol,
        period='daily',
        start_date=start,
        end_date=end,
        adjust='qfq'  # 前复权
    )
    
    # 标准化列名
    df = df.rename(columns={
        '日期': 'date',
        '开盘': 'open',
        '最高': 'high',
        '最低': 'low',
        '收盘': 'close',
        '成交量': 'volume'
    })
    
    df['date'] = pd.to_datetime(df['date'])
    df.set_index('date', inplace=True)
    
    return df

# ============ 2. 定义策略 ============
class MaCrossStrategy(bt.Strategy):
    """MA 金叉死叉策略"""
    
    # 参数
    params = (
        ('fast_period', 5),     # 短期均线周期
        ('slow_period', 20),    # 长期均线周期
        ('printlog', True),     # 是否打印日志
    )
    
    def __init__(self):
        # 计算均线
        self.fast_ma = bt.indicators.SMA(period=self.params.fast_period)
        self.slow_ma = bt.indicators.SMA(period=self.params.slow_period)
        
        # 金叉死叉信号
        self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)
        
        # 订单
        self.order = None
    
    def next(self):
        # 有未完成订单,跳过
        if self.order:
            return
        
        # 账户没仓位,金叉 → 买入
        if not self.position:
            if self.crossover > 0:  # 金叉
                self.order = self.buy()
                if self.params.printlog:
                    self.log(f'金叉买入: 价格 {self.data.close[0]:.2f}')
        
        # 账户有仓位,死叉 → 卖出
        else:
            if self.crossover < 0:  # 死叉
                self.order = self.sell()
                if self.params.printlog:
                    self.log(f'死叉卖出: 价格 {self.data.close[0]:.2f}')
    
    def log(self, txt, dt=None):
        """日志"""
        dt = dt or self.datas[0].datetime.date(0)
        print(f'[{dt}] {txt}')
    
    def notify_order(self, order):
        """订单状态变化"""
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'买入成交: 价 {order.executed.price:.2f} 手续费 {order.executed.comm:.2f}')
            else:
                self.log(f'卖出成交: 价 {order.executed.price:.2f} 手续费 {order.executed.comm:.2f}')
        self.order = None

# ============ 3. 运行回测 ============
if __name__ == '__main__':
    # 创建引擎
    cerebro = bt.Cerebro()
    
    # 添加策略
    cerebro.addstrategy(MaCrossStrategy)
    
    # 设置初始资金
    cerebro.broker.setcash(1000000)  # 100 万
    
    # 设置手续费
    cerebro.broker.setcommission(
        commission=0.0003,        # 佣金 0.03%
        stamp_duty=0.001,        # 印花税 0.1%(卖出)
        stocklike=True
    )
    
    # 设置数据
    df = get_data('600519', '20200101', '20241231')
    data = bt.feeds.PandasData(dataname=df)
    cerebro.adddata(data)
    
    # 设置分析器
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', riskfreerate=0.025)
    cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
    cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
    
    # 打印初始状态
    print('初始资金: %.2f' % cerebro.broker.getvalue())
    
    # 运行
    results = cerebro.run()
    
    # 打印最终状态
    print('最终资金: %.2f' % cerebro.broker.getvalue())
    
    # 分析结果
    strat = results[0]
    print(f'夏普比率: {strat.analyzers.sharpe.get_analysis()["sharperatio"]:.2f}')
    print(f'最大回撤: {strat.analyzers.drawdown.get_analysis().max.drawdown:.2f}%')
    
    # 画图
    cerebro.plot(style='candlestick')

2.2 运行结果示例 ​

初始资金: 1000000.00
[2020-04-15] 金叉买入: 价格 128.50
[2020-04-15] 买入成交: 价 128.50 手续费 38.55
[2020-09-22] 死叉卖出: 价格 175.30
[2020-09-22] 卖出成交: 价 175.30 手续费 17.53
...
[2024-12-30] 死叉卖出: 价格 1520.00
最终资金: 2350000.00

夏普比率: 1.85
最大回撤: -18.50%

📊 3. 回测结果分析 ​

3.1 关键指标 ​

指标含义优秀值
年化收益平均年化回报> 15%
最大回撤期间最大亏损< 20%
夏普比率单位风险收益> 1.5
卡玛比率收益 / 回撤> 2.0
胜率盈利笔数比例> 50%
盈亏比平均盈利 / 平均亏损> 2.0
交易次数完整买卖次数10-100 / 年
持仓时间平均持仓天数视策略

3.2 分析器(Analyzers) ​

python
# 添加更多分析器
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', riskfreerate=0.025)
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
cerebro.addanalyzer(bt.analyzers.SQN, _name='sqn')  # 系统质量
cerebro.addanalyzer(bt.analyzers.VWR, _name='vwr')  # 波动率加权

# 运行后分析
results = cerebro.run()
strat = results[0]

# 获取详细分析
print('夏普:', strat.analyzers.sharpe.get_analysis())
print('回撤:', strat.analyzers.drawdown.get_analysis())
print('交易:', strat.analyzers.trades.get_analysis())

🛠️ 4. 优化策略 ​

4.1 加入止损 ​

python
class MaCrossWithStop(bt.Strategy):
    params = (
        ('fast_period', 5),
        ('slow_period', 20),
        ('stop_loss', 0.08),     # 8% 止损
    )
    
    def __init__(self):
        self.fast_ma = bt.indicators.SMA(period=self.params.fast_period)
        self.slow_ma = bt.indicators.SMA(period=self.params.slow_period)
        self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)
        self.order = None
        self.buy_price = None
    
    def next(self):
        if self.order:
            return
        
        if not self.position:
            if self.crossover > 0:
                self.order = self.buy()
                self.buy_price = self.data.close[0]
        else:
            current_price = self.data.close[0]
            # 止损
            if self.buy_price and current_price < self.buy_price * (1 - self.params.stop_loss):
                self.order = self.sell()
                self.log(f'止损卖出: {current_price:.2f}')
            # 死叉卖出
            elif self.crossover < 0:
                self.order = self.sell()
                self.buy_price = None

4.2 仓位管理 ​

python
class PositionSizing(bt.Strategy):
    """固定金额仓位管理"""
    
    def next(self):
        if not self.position:
            # 只用 20% 资金买入
            size = int(self.broker.getcash() * 0.2 / self.data.close[0])
            if size > 0:
                self.buy(size=size)

4.3 参数优化 ​

python
# 用 Backtrader 的优化器
cerebro.optstrategy(
    MaCrossStrategy,
    fast_period=range(3, 15, 2),     # 测试 3-15 步长 2
    slow_period=range(15, 60, 5)    # 测试 15-60 步长 5
)

# 运行优化
results = cerebro.run()

# 找最优参数
best_sharpe = -999
best_params = None
for result in results:
    sharpe = result[0].analyzers.sharpe.get_analysis()['sharperatio']
    if sharpe > best_sharpe:
        best_sharpe = sharpe
        best_params = result[0].params

print(f'最优参数: {best_params}, 夏普: {best_sharpe:.2f}')

⚠️ 过拟合警告:参数优化很容易找到"历史最优"但在未来失效。建议用:

  • 样本内 / 样本外分割:70% 数据优化,30% 数据验证
  • Walk Forward:滚动窗口优化
  • 多标的测试:用 10 只股票测试,避免单只股票过拟合

🧪 5. 完整策略示例 ​

python
"""多因子选股 + 风险管理完整策略"""
class CompleteStrategy(bt.Strategy):
    params = (
        ('fast_ma', 5),
        ('slow_ma', 20),
        ('rsi_period', 14),
        ('rsi_buy', 30),          # RSI < 30 抄底
        ('rsi_sell', 70),         # RSI > 70 减仓
        ('stop_loss', 0.10),      # 10% 止损
        ('position_pct', 0.3),    # 30% 仓位
    )
    
    def __init__(self):
        # 指标
        self.fast_ma = bt.indicators.SMA(period=self.params.fast_ma)
        self.slow_ma = bt.indicators.SMA(period=self.params.slow_ma)
        self.rsi = bt.indicators.RSI(period=self.params.rsi_period)
        self.atr = bt.indicators.ATR(period=14)  # 波动率
        
        # 订单
        self.order = None
        self.buy_price = None
    
    def next(self):
        if self.order:
            return
        
        price = self.data.close[0]
        
        if not self.position:
            # 多重信号共振
            ma_bullish = self.fast_ma[0] > self.slow_ma[0]
            ma_crossover = self.fast_ma[-1] <= self.slow_ma[-1] and self.fast_ma[0] > self.slow_ma[0]
            rsi_oversold = self.rsi[0] < self.params.rsi_buy
            volatility_ok = self.atr[0] / price < 0.05  # 波动率 < 5%
            
            if (ma_crossover or ma_bullish) and rsi_oversold and volatility_ok:
                # 仓位管理:账户 30%
                size = int(self.broker.getvalue() * self.params.position_pct / price)
                if size > 0:
                    self.order = self.buy(size=size)
        else:
            # 持仓管理
            if self.buy_price:
                # 止损
                if price < self.buy_price * (1 - self.params.stop_loss):
                    self.order = self.sell()
                # RSI 超买卖出
                elif self.rsi[0] > self.params.rsi_sell:
                    self.order = self.sell()
                # 死叉卖出
                elif self.fast_ma[0] < self.slow_ma[0]:
                    self.order = self.sell()

📊 6. 回测结果判断 ​

6.1 好策略的特征 ​

指标优秀策略一般策略
年化收益> 20%10-20%
最大回撤< 15%15-30%
夏普比率> 1.50.8-1.5
胜率> 50%40-50%
盈亏比> 21-2

6.2 危险信号 ​

信号含义
回撤 > 30%策略可能失效
夏普 < 0.5风险收益比差
胜率 < 30%策略不适用
收益全靠 1-2 笔不可持续

6.3 常见误区 ​

误区真相
"回测好 = 实盘好"70% 回测好的策略实盘失效
"参数越多越好"越简单越稳健
"高收益 = 好策略"高收益往往伴随高回撤
"夏普 2 = 完美"可能是过拟合

🛠️ 7. 进阶工具 ​

7.1 qlib(微软 AI 量化平台) ​

bash
pip install pyqlib
  • 内置 Alpha 因子库
  • AI 预测模型
  • 适合机器学习量化

7.2 Zipline(Quantopian 开源) ​

bash
pip install zipline-reloaded
  • 老牌回测框架
  • 美股数据支持

7.3 vnpy(国内最流行) ​

bash
pip install vnpy
  • 国内量化交易框架
  • 支持实盘
  • 适合专业量化

📊 实战建议 ​

入门路径 ​

第 1 月:
  - 学习 Python 基础
  - 跑通 Backtrader 第一个策略
  
第 2 月:
  - 学习多因子
  - 优化策略参数
  
第 3 月:
  - 加入风险管理
  - 模拟盘验证
  
第 4-6 月:
  - 小资金实盘
  - 持续迭代

⚠️ 重要提醒 ​

  1. 回测 ≠ 实盘:滑点、手续费、流动性都会影响
  2. 过拟合是最大风险:参数越多越容易过拟合
  3. 样本外测试:必须用未参与优化的数据测试
  4. 小资金起步:实盘先小资金验证
  5. 持续监控:策略会失效,需要定期回顾

📖 相关阅读 ​

来源 ​

💡 数据截至 2026-08;具体规则以交易所/监管机构最新公告为准。

本知识库内容仅供学习参考,不构成任何投资建议。
本站总访问量 ... 次 · 访客数 ... 人