返回文档
Python 量化入门

回测框架入门

backtrader / vectorbt 入门,回测一个真实策略

上一篇我们手撸了一个双均线回测,代码已经有点乱了。如果策略再复杂一点(多周期、多品种、止损止盈),手撸会越来越难维护。这时候就需要专业的回测框架

主流框架对比

框架特点适合
backtrader事件驱动,功能全面,社区大中长期策略、新手入门
vectorbt向量化,速度极快大规模参数扫描、因子研究
ziplineQuantopian 出品已停止维护,不推荐
rqalpha米筐出品,A 股友好A 股策略

新手建议从 backtrader 开始,资料多、API 直观。

backtrader 入门

安装

bash
uv pip install backtrader

核心概念

backtrader 用面向对象的方式组织代码,几个核心概念:

  • Cerebro(大脑)— 整个回测的引擎
  • Strategy(策略)— 你的交易逻辑
  • Data Feed(数据源)— 喂给策略的行情
  • Broker(券商)— 模拟成交、收手续费
  • Analyzer(分析器)— 计算绩效指标

第一个 backtrader 策略

python
import backtrader as bt
import akshare as ak
import pandas as pd

# 1. 定义策略
class DualMAStrategy(bt.Strategy):
    params = (
        ('fast', 5),
        ('slow', 20),
    )

    def __init__(self):
        self.ma_fast = bt.indicators.SMA(self.data.close, period=self.params.fast)
        self.ma_slow = bt.indicators.SMA(self.data.close, period=self.params.slow)
        self.crossover = bt.indicators.CrossOver(self.ma_fast, self.ma_slow)

    def next(self):
        if not self.position:                  # 空仓
            if self.crossover > 0:              # 金叉
                self.buy()
        elif self.crossover < 0:                # 死叉
            self.close()

    def log(self, txt):
        dt = self.data.datetime.date(0)
        print(f'{dt} {txt}')

    def notify_order(self, order):
        if order.status == order.Completed:
            self.log(f'{"BUY" if order.isbuy() else "SELL"} @ {order.executed.price:.2f}')

# 2. 准备数据
df = ak.stock_us_daily(symbol="AAPL", adjust="qfq")
df['date'] = pd.to_datetime(df['date'])
df = df[df['date'] >= '2023-01-01'].set_index('date')
df = df.rename(columns={
    'open':'open', 'high':'high', 'low':'low',
    'close':'close', 'volume':'volume'
})

# 3. 创建 Cerebro
cerebro = bt.Cerebro()

# 4. 添加策略
cerebro.addstrategy(DualMAStrategy, fast=5, slow=20)

# 5. 添加数据
data = bt.feeds.PandasData(dataname=df)
cerebro.adddata(data)

# 6. 设置初始资金、手续费
cerebro.broker.setcash(100000)
cerebro.broker.setcommission(commission=0.0003)

# 7. 运行
print(f'初始资金: {cerebro.broker.getvalue():.2f}')
cerebro.run()
print(f'最终资金: {cerebro.broker.getvalue():.2f}')

# 8. 画图
cerebro.plot(style='candlestick')

跑起来你会看到每次开平仓的日志,最后输出最终账户净值,并自动画出 K 线 + 信号 + 净值曲线。

加入分析器

backtrader 自带很多分析器:

python
cerebro.addanalyzer(bt.analyzers.SharpeRatio,    _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown,       _name='dd')
cerebro.addanalyzer(bt.analyzers.Returns,        _name='returns')
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer,  _name='trades')

results = cerebro.run()
strat = results[0]

print(f'Sharpe Ratio: {strat.analyzers.sharpe.get_analysis()["sharperatio"]:.2f}')
print(f'Max Drawdown: {strat.analyzers.dd.get_analysis()["max"]["drawdown"]:.2f}%')
print(f'Total Return: {strat.analyzers.returns.get_analysis()["rtot"]:.2%}')

trades = strat.analyzers.trades.get_analysis()
print(f'交易次数: {trades.total.total}')
print(f'盈利次数: {trades.won.total}')
print(f'亏损次数: {trades.lost.total}')

加入仓位管理

实战中很少全仓买入。常见做法是按账户资金的固定比例下单:

python
class DualMAStrategy(bt.Strategy):
    def next(self):
        if not self.position:
            if self.crossover > 0:
                # 用账户 30% 的资金买入
                size = int(self.broker.getcash() * 0.3 / self.data.close[0])
                self.buy(size=size)
        elif self.crossover < 0:
            self.close()

或者用 backtrader 内置的 sizer:

python
cerebro.addsizer(bt.sizers.PercentSizer, percents=30)

加入止损止盈

python
class DualMAWithStop(bt.Strategy):
    params = (
        ('fast', 5),
        ('slow', 20),
        ('stop_loss', 0.05),    # 5% 止损
        ('take_profit', 0.10),  # 10% 止盈
    )

    def __init__(self):
        self.ma_fast = bt.indicators.SMA(self.data.close, period=self.params.fast)
        self.ma_slow = bt.indicators.SMA(self.data.close, period=self.params.slow)
        self.crossover = bt.indicators.CrossOver(self.ma_fast, self.ma_slow)
        self.entry_price = None

    def next(self):
        if not self.position:
            if self.crossover > 0:
                self.buy()
                self.entry_price = self.data.close[0]
        else:
            current = self.data.close[0]
            ret = (current - self.entry_price) / self.entry_price

            if ret <= -self.params.stop_loss:
                self.close()  # 止损
            elif ret >= self.params.take_profit:
                self.close()  # 止盈
            elif self.crossover < 0:
                self.close()  # 死叉

多品种回测

python
symbols = ['AAPL', 'MSFT', 'GOOGL']

cerebro = bt.Cerebro()
cerebro.addstrategy(DualMAStrategy)

for symbol in symbols:
    df = ak.stock_us_daily(symbol=symbol, adjust="qfq")
    df['date'] = pd.to_datetime(df['date'])
    df = df[df['date'] >= '2023-01-01'].set_index('date')

    data = bt.feeds.PandasData(dataname=df, name=symbol)
    cerebro.adddata(data)

cerebro.broker.setcash(300000)
cerebro.broker.setcommission(commission=0.0003)
cerebro.run()

策略代码会自动对每个品种独立运行。

vectorbt:向量化回测

vectorbt 用纯 numpy 向量化运算,速度比 backtrader 快几十倍,适合参数扫描因子研究

安装

bash
uv pip install vectorbt

一行代码回测双均线

python
import vectorbt as vbt
import yfinance as yf

# 拉取数据
price = yf.download('AAPL', start='2023-01-01', end='2024-12-31')['Close']

# 计算均线
fast_ma = vbt.MA.run(price, 5)
slow_ma = vbt.MA.run(price, 20)

# 生成信号
entries = fast_ma.ma_crossed_above(slow_ma)
exits   = fast_ma.ma_crossed_below(slow_ma)

# 回测
pf = vbt.Portfolio.from_signals(
    price, entries, exits,
    init_cash=100000,
    fees=0.0003,
)

# 查看结果
print(pf.stats())
pf.plot().show()

pf.stats() 会输出几十个统计指标,比 backtrader 完整。

参数扫描

vectorbt 的杀手锏是一次跑几百组参数

python
import numpy as np

# 5 个快线 × 5 个慢线 = 25 组参数
fast_periods = [5, 10, 15, 20, 25]
slow_periods = [30, 50, 60, 100, 200]

fast_ma = vbt.MA.run(price, window=fast_periods, short_name='fast')
slow_ma = vbt.MA.run(price, window=slow_periods, short_name='slow')

entries = fast_ma.ma_crossed_above(slow_ma)
exits   = fast_ma.ma_crossed_below(slow_ma)

pf = vbt.Portfolio.from_signals(price, entries, exits, fees=0.0003)

# 找出夏普最高的参数组合
print(pf.sharpe_ratio().sort_values(ascending=False).head())

不到 1 秒钟就能跑完。

框架选择建议

场景推荐
学习量化交易、写第一个策略backtrader
复杂的事件驱动逻辑backtrader
大规模参数优化vectorbt
快速验证想法vectorbt
实盘策略部署backtrader(社区有实盘对接方案)

我自己的做法:研究阶段用 vectorbt 快速试错,定型后用 backtrader 写正式代码

小结

你已经会:

  • ✅ backtrader 基础用法
  • ✅ 加入分析器、仓位管理、止损止盈
  • ✅ 多品种回测
  • ✅ vectorbt 向量化回测
  • ✅ 参数扫描

下一篇 风险与绩效指标,我们详细搞懂回测报告里那些指标到底意味着什么。

📌 避坑提示 别一上来就用复杂框架。如果一个策略你手撸都说不清楚收益从哪来,框架只会让你更迷茫。先理解原理,再用框架。