← 返回工具目录 · 全部教程

backtrader 回测入门:第一个策略

系列·回测篇 — 在真实 A 股日线上跑通双均线策略,重点不是收益,而是把回测的口径做诚实

📖 本篇是《量化实操教程》第 3 篇,前置:akshare 数据实操(本篇直接喂数据篇拉好的日线)。

01 · 为什么选 backtrader

纯 Python、事件驱动、社区成熟,个人研究者从"想验证一个想法"到"跑出结果"最快的一条路。安装无重依赖:

pip install backtrader
# 可选:绘图需要 matplotlib,且老版本兼容更好(matplotlib>=3.8 会报错),本篇聚焦指标输出,先不装

02 · 喂数据:akshare 的 DataFrame 直接进 backtrader

用数据篇的清洗口径,索引是 DatetimeIndex、列小写英文,PandasData 就能直接吃:

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

df = ak.stock_zh_a_hist(symbol="000001", period="daily",
                        start_date="20230101", end_date="20250801", adjust="qfq")
df["date"] = pd.to_datetime(df["日期"])
df = df.rename(columns={"开盘": "open", "最高": "high", "最低": "low",
                        "收盘": "close", "成交量": "volume"})
df = df.set_index("date")[["open", "high", "low", "close", "volume"]]

03 · 第一个策略:双均线

金叉(短均线上穿长均线)买入,死叉卖出——最经典的教学策略:

class SmaCross(bt.Strategy):
    params = dict(fast=5, slow=20)

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

    def next(self):
        if not self.position and self.crossover > 0:
            self.buy(size=100)        # A股一手 = 100 股
        elif self.position and self.crossover < 0:
            self.close()

口径说明:backtrader 默认在 next() 里下的单按下一根 bar 的开盘价成交——这正是诚实的 口径(信号在收盘后确认,下一时刻才能成交)。如果你手动改成当日 close 成交,就是在用未来数据作弊。

04 · 跑起来:A 股成本要算进去

cerebro = bt.Cerebro()
cerebro.adddata(bt.feeds.PandasData(dataname=df))
cerebro.addstrategy(SmaCross)
cerebro.broker.setcash(100000)
cerebro.broker.setcommission(commission=0.0003)   # 佣金万2.5,双边简化
cerebro.broker.set_slippage_perc(0.001)           # 滑点 0.1%

cerebro.addanalyzer(bt.analyzers.Returns, _name="ret")
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe", timeframe=bt.TimeFrame.Days)
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="dd")

result = cerebro.run()
print("期末净值:", round(cerebro.broker.getvalue(), 0))
print("年化收益:", result[0].analyzers.ret.get_analysis()["rnorm"])
print("夏普:", result[0].analyzers.sharpe.get_analysis()["sharperatio"])
print("最大回撤: %.1f%%" % result[0].analyzers.dd.get_analysis()["max"]["drawdown"])

成本简化声明:setcommission 不分买卖边,A 股真实口径是佣金双边 +卖出印花税(0.05%)。低频策略影响不大,但精确复算成本要在佣金类里分边实现——本教程先按简化口径。

05 · 结果怎么读

06 · 四个必避的坑

🚀 回测跑上瘾后,你会发现"每天自动更新数据 + 每周定时回测"必须有一台不关机的机器——这正是 基础篇的用武之地:

阿里云入口 · 新客可享 85 折起 →

本站入口含推广归属,你的价格不变;价格与折扣以官方活动页实时为准。本教程不构成任何投资建议;历史回测不代表未来表现。