Backtrader logo

Backtrader

Organization
lzwme
backtrader

Backtrader 开源量化回测框架,支持多数据源、多策略、多周期回测与实盘交易,纯Python实现。当用户需要开发量化策略、进行回测分析、编写交易逻辑、回测参数优化,或提及 backtrader、量化回测框架时使用。若用户仅需数据获取而无回测需求,引导使用 baostock/akshare/tushare 等数据 Skill。

Overview

Publisherlzwme
Repositoryfinance-quant-skills
Skill namebacktrader
Stars
461
Forks
85
Bundled files
1
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 1 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by lzwme on GitHub. Read the source before you install it.

Installation

Install the Backtrader AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/lzwme/finance-quant-skills/tree/main/skills/backtrader
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/lzwme/finance-quant-skills.git /tmp/finance-quant-skills
mkdir -p .claude/skills
cp -r /tmp/finance-quant-skills/skills/backtrader .claude/skills/backtrader
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Backtrader in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Backtrader on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Backtrader is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Backtrader(开源量化回测框架)

Backtrader 是一个开源 Python 量化回测框架。采用事件驱动架构,核心组件包括:Cerebro(引擎)、Strategy(策略类)、Data Feed(数据源)、Broker(经纪商)、Indicator(内置 100+ 技术指标)、Analyzer(绩效分析)。纯 Python 实现,无外部依赖,适合离线研究。

官方文档:https://www.backtrader.com/docu/

安装

bash
pip install backtrader
# 如需绘图
pip install backtrader[plotting]
# 或
pip install matplotlib

最简示例

python
import backtrader as bt

class MyStrategy(bt.Strategy):
    """简单均线策略"""
    params = (('period', 20),)  # 策略参数:均线周期

    def __init__(self):
        # 初始化指标(在__init__中定义,自动计算)
        self.sma = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.period)

    def next(self):
        # 每根K线触发一次,在此编写交易逻辑
        if self.data.close[0] > self.sma[0]:
            if not self.position:  # 无持仓则买入
                self.buy()
        elif self.data.close[0] < self.sma[0]:
            if self.position:      # 有持仓则卖出
                self.sell()

# 创建引擎
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)

# 加载数据(Yahoo CSV格式)
data = bt.feeds.YahooFinanceCSVData(dataname='stock_data.csv')
cerebro.adddata(data)

# 设置初始资金
cerebro.broker.setcash(100000.0)
# 设置手续费
cerebro.broker.setcommission(commission=0.001)

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

# 绘制结果
cerebro.plot()

数据源

从Pandas DataFrame加载

python
import backtrader as bt
import pandas as pd

# 从CSV读取数据
df = pd.read_csv('stock_data.csv', parse_dates=['date'], index_col='date')
# DataFrame必须包含列: open, high, low, close, volume(小写列名)

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

从CSV文件加载

python
# 通用CSV格式
data = bt.feeds.GenericCSVData(
    dataname='stock_data.csv',
    dtformat='%Y-%m-%d',    # 日期格式
    datetime=0,              # 日期列索引
    open=1,                  # 开盘价列索引
    high=2,                  # 最高价列索引
    low=3,                   # 最低价列索引
    close=4,                 # 收盘价列索引
    volume=5,                # 成交量列索引
    openinterest=-1          # 持仓量列索引(-1表示无此列)
)
cerebro.adddata(data)

多股票 / 多周期

python
# 加载多只股票数据
data1 = bt.feeds.PandasData(dataname=df1, name='stock1')
data2 = bt.feeds.PandasData(dataname=df2, name='stock2')
cerebro.adddata(data1)
cerebro.adddata(data2)

# 在策略中访问多只股票
class MultiStockStrategy(bt.Strategy):
    def __init__(self):
        # self.datas[0]是第一只股票,self.datas[1]是第二只
        self.sma1 = bt.indicators.SMA(self.datas[0].close, period=20)
        self.sma2 = bt.indicators.SMA(self.datas[1].close, period=20)

    def next(self):
        for i, d in enumerate(self.datas):
            print(f'{d._name}: close={d.close[0]:.2f}')

数据重采样(分钟线转日线)

python
# 加载分钟数据
data_min = bt.feeds.GenericCSVData(dataname='1min_data.csv', timeframe=bt.TimeFrame.Minutes)
cerebro.adddata(data_min)

# 重采样为日线
cerebro.resampledata(data_min, timeframe=bt.TimeFrame.Days)

策略类详解

策略参数

python
class MyStrategy(bt.Strategy):
    # 定义可调参数(元组格式)
    params = (
        ('fast_period', 5),     # 快速均线周期
        ('slow_period', 20),    # 慢速均线周期
        ('stake', 100),         # 每次交易手数
    )

    def __init__(self):
        self.fast_ma = bt.indicators.SMA(period=self.p.fast_period)
        self.slow_ma = bt.indicators.SMA(period=self.p.slow_period)
        # self.p 是 self.params 的简写

    def next(self):
        if self.fast_ma[0] > self.slow_ma[0]:
            self.buy(size=self.p.stake)

# 参数可在运行时覆盖
cerebro.addstrategy(MyStrategy, fast_period=10, slow_period=30)

交易方法

python
class MyStrategy(bt.Strategy):
    def next(self):
        # 按数量买入
        self.buy(size=100)                    # 买入100股
        self.sell(size=100)                   # 卖出100股

        # 调整到目标仓位
        self.order_target_size(target=500)    # 调整持仓为500股
        self.order_target_value(target=50000) # 调整持仓为5万元市值
        self.order_target_percent(target=0.5) # 调整持仓为总资产的50%

        # 限价单
        self.buy(size=100, price=10.5, exectype=bt.Order.Limit)
        # 止损单
        self.sell(size=100, price=9.0, exectype=bt.Order.Stop)
        # 止损限价单
        self.buy(size=100, price=10.5, pricelimit=10.8, exectype=bt.Order.StopLimit)

        # 撤单
        order = self.buy(size=100)
        self.cancel(order)

        # 对其他股票下单
        self.buy(data=self.datas[1], size=200)  # 买入第二只股票

订单通知回调

python
class MyStrategy(bt.Strategy):
    def notify_order(self, order):
        """订单状态变化时触发"""
        if order.status in [order.Submitted, order.Accepted]:
            return  # 订单已提交/已接受,等待执行

        if order.status in [order.Completed]:
            if order.isbuy():
                print(f'买入执行: 价格={order.executed.price:.2f}, '
                      f'数量={order.executed.size}, 手续费={order.executed.comm:.2f}')
            else:
                print(f'卖出执行: 价格={order.executed.price:.2f}, '
                      f'数量={order.executed.size}, 手续费={order.executed.comm:.2f}')

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            print(f'订单失败: 状态={order.getstatusname()}')

    def notify_trade(self, trade):
        """交易完成时触发(一买一卖构成完整交易)"""
        if trade.isclosed:
            print(f'交易完成: 毛利润={trade.pnl:.2f}, 净利润={trade.pnlcomm:.2f}')

获取数据与持仓

python
class MyStrategy(bt.Strategy):
    def next(self):
        # 当前K线数据
        current_close = self.data.close[0]     # 当前收盘价
        prev_close = self.data.close[-1]       # 前一根K线收盘价
        current_volume = self.data.volume[0]   # 当前成交量
        current_date = self.data.datetime.date(0)  # 当前日期

        # 持仓信息
        position = self.getposition(self.data)
        print(f'持仓数量: {position.size}')
        print(f'平均成本: {position.price:.2f}')

        # 账户信息
        cash = self.broker.getcash()           # 可用资金
        value = self.broker.getvalue()         # 总资产
        print(f'可用资金: {cash:.2f}, 总资产: {value:.2f}')

内置技术指标

python
class MyStrategy(bt.Strategy):
    def __init__(self):
        # 均线
        self.sma = bt.indicators.SimpleMovingAverage(self.data.close, period=20)
        self.ema = bt.indicators.ExponentialMovingAverage(self.data.close, period=20)
        self.wma = bt.indicators.WeightedMovingAverage(self.data.close, period=20)

        # MACD
        self.macd = bt.indicators.MACD(self.data.close)
        # self.macd.macd = DIF线, self.macd.signal = DEA线, self.macd.histo = MACD柱

        # RSI
        self.rsi = bt.indicators.RSI(self.data.close, period=14)

        # 布林带
        self.boll = bt.indicators.BollingerBands(self.data.close, period=20, devfactor=2.0)
        # self.boll.mid = 中轨, self.boll.top = 上轨, self.boll.bot = 下轨

        # KDJ(随机振荡器)
        self.stoch = bt.indicators.Stochastic(self.data, period=14)

        # ATR(真实波动幅度)
        self.atr = bt.indicators.ATR(self.data, period=14)

        # 交叉信号
        self.crossover = bt.indicators.CrossOver(self.sma, self.ema)
        # crossover > 0 表示金叉, < 0 表示死叉

券商/经纪商设置

python
cerebro = bt.Cerebro()

# 设置初始资金
cerebro.broker.setcash(1000000.0)

# 设置手续费
cerebro.broker.setcommission(commission=0.001)  # 0.1%

# 按百分比设置手续费
cerebro.broker.setcommission(
    commission=0.0003,     # 0.03%
    margin=None,           # 保证金(期货用)
    mult=1.0               # 合约乘数(期货用)
)

# 设置滑点
cerebro.broker.set_slippage_perc(perc=0.001)    # 百分比滑点
cerebro.broker.set_slippage_fixed(fixed=0.02)   # 固定滑点

# 设置每笔交易数量
cerebro.addsizer(bt.sizers.FixedSize, stake=100)        # 固定100股
cerebro.addsizer(bt.sizers.PercentSizer, percents=95)   # 总资产的95%

分析器

python
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)

# 添加分析器
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')       # 夏普比率
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.AnnualReturn, _name='annual')     # 年化收益

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

# 获取分析结果
print(f"夏普比率: {strat.analyzers.sharpe.get_analysis()['sharperatio']:.2f}")
print(f"最大回撤: {strat.analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%")
print(f"总收益率: {strat.analyzers.returns.get_analysis()['rtot']:.4f}")

# 交易统计
trade_analysis = strat.analyzers.trades.get_analysis()
print(f"总交易次数: {trade_analysis['total']['total']}")
print(f"盈利次数: {trade_analysis['won']['total']}")
print(f"亏损次数: {trade_analysis['lost']['total']}")

参数优化

python
# 使用 optstrategy 进行参数网格搜索
cerebro = bt.Cerebro()
cerebro.optstrategy(
    MyStrategy,
    fast_period=range(5, 15),     # 快速均线: 5 到 14
    slow_period=range(20, 40, 5)  # 慢速均线: 20, 25, 30, 35
)

data = bt.feeds.PandasData(dataname=df)
cerebro.adddata(data)
cerebro.broker.setcash(100000)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')

# 运行优化(自动遍历所有参数组合)
results = cerebro.run(maxcpus=4)  # 多核并行

# 提取最优参数
best_sharpe = -999
best_params = None
for result in results:
    for strat in result:
        sharpe = strat.analyzers.sharpe.get_analysis().get('sharperatio', 0) or 0
        if sharpe > best_sharpe:
            best_sharpe = sharpe
            best_params = strat.params

print(f'最优参数: fast={best_params.fast_period}, slow={best_params.slow_period}')
print(f'最优夏普: {best_sharpe:.2f}')

进阶示例

更多完整策略示例(MACD+布林带组合、海龟交易、多股票轮动)见 references/advanced-strategies.md。

常见错误处理

错误原因解决方法
KeyError 或数据列缺失DataFrame 列名不符合要求确保列名为小写:open, high, low, close, volume,索引为日期
IndexError: array index out of range数据量不足,指标无法计算增加数据量或减少指标周期
绘图无输出/报错未安装 matplotlibpip install matplotlib
参数优化结果为空sharpe 返回 None使用 or 0 处理空值(见参数优化示例)
策略不触发交易数据格式或逻辑问题检查 DataFrame 索引是否为 DatetimeIndex,数据是否按日期排序
NegativeStackSize数据长度不足以覆盖预热期增加数据量或减小指标窗口

使用技巧

  • Backtrader 是纯本地框架,不依赖在线服务,适合离线研究。
  • 数据需要用户自行准备(可配合 baostock、AKShare、Tushare 等数据源 Skill 使用)。
  • 在 __init__ 中定义指标,在 next 中编写交易逻辑 — 这是核心模式。
  • 使用 self.data.close[0] 访问当前值,[-1] 访问前一个值。
  • 通过 optstrategy 进行参数优化支持多核并行,显著加速。
  • 绘图需要安装 matplotlib;直接调用 cerebro.plot() 即可。

资源索引

规则

  • 使用此 Skill 前,确认用户明确需要 backtrader 框架进行策略开发。若用户仅需要数据获取,引导使用 baostock/pywencai 等数据 Skill。
  • 指标必须在 __init__ 中定义,交易逻辑必须在 next 中编写,不要在 next 中创建指标。
  • DataFrame 列名必须为小写(open, high, low, close, volume),索引必须为日期(DatetimeIndex)。
  • 示例中若需真实市场数据,应提示用户配合 baostock 等数据源 Skill 获取,不要在示例中使用虚构数据路径。
  • 始终在策略中处理 sharpe 为 None 的情况(参数优化时)。

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Backtrader AI skill do?

Backtrader 开源量化回测框架,支持多数据源、多策略、多周期回测与实盘交易,纯Python实现。当用户需要开发量化策略、进行回测分析、编写交易逻辑、回测参数优化,或提及 backtrader、量化回测框架时使用。若用户仅需数据获取而无回测需求,引导使用 baostock/akshare/tushare 等数据 Skill。

Why use Backtrader on TypingMind?

Because you install it once and use it with any model. Backtrader is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Backtrader in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/lzwme/finance-quant-skills/tree/main/skills/backtrader. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Backtrader?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Backtrader?

As many as you like. As long as a model supports skills, you can use Backtrader with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Backtrader AI skill free?

It is published on GitHub by lzwme. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇