{"id":"e64e3360-02f5-45fb-a467-7c9aee45d207","shortId":"9JYZWE","kind":"skill","title":"backtrader","tagline":"Backtrader 开源量化回测框架，支持多数据源、多策略、多周期回测与实盘交易，纯Python实现。当用户明确提及backtrader相关策略开发时使用。","description":"# Backtrader（开源量化回测框架）\n\n[Backtrader](https://github.com/mementum/backtrader) 是一个开源 Python 量化回测框架。采用事件驱动架构，核心组件包括：**Cerebro**（引擎）、**Strategy**（策略类）、**Data Feed**（数据源）、**Broker**（经纪商）、**Indicator**（内置 100+ 技术指标）、**Analyzer**（绩效分析）。纯 Python 实现，无外部依赖，适合离线研究。\n\n> 官方文档：https://www.backtrader.com/docu/\n\n## 安装\n\n```bash\npip install backtrader\n# 如需绘图\npip install backtrader[plotting]\n# 或\npip install matplotlib\n```\n\n## 最简示例\n\n```python\nimport backtrader as bt\n\nclass MyStrategy(bt.Strategy):\n    \"\"\"简单均线策略\"\"\"\n    params = (('period', 20),)  # 策略参数：均线周期\n\n    def __init__(self):\n        # 初始化指标（在__init__中定义，自动计算）\n        self.sma = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.period)\n\n    def next(self):\n        # 每根K线触发一次，在此编写交易逻辑\n        if self.data.close[0] > self.sma[0]:\n            if not self.position:  # 无持仓则买入\n                self.buy()\n        elif self.data.close[0] < self.sma[0]:\n            if self.position:      # 有持仓则卖出\n                self.sell()\n\n# 创建引擎\ncerebro = bt.Cerebro()\ncerebro.addstrategy(MyStrategy)\n\n# 加载数据（Yahoo CSV格式）\ndata = bt.feeds.YahooFinanceCSVData(dataname='stock_data.csv')\ncerebro.adddata(data)\n\n# 设置初始资金\ncerebro.broker.setcash(100000.0)\n# 设置手续费\ncerebro.broker.setcommission(commission=0.001)\n\n# 运行回测\nprint(f'初始资金: {cerebro.broker.getvalue():.2f}')\ncerebro.run()\nprint(f'最终资金: {cerebro.broker.getvalue():.2f}')\n\n# 绘制结果\ncerebro.plot()\n```\n\n\n## 数据源\n\n### 从Pandas DataFrame加载\n\n```python\nimport backtrader as bt\nimport pandas as pd\n\n# 从CSV读取数据\ndf = pd.read_csv('stock_data.csv', parse_dates=['date'], index_col='date')\n# DataFrame必须包含列: open, high, low, close, volume（小写列名）\n\ndata = bt.feeds.PandasData(dataname=df)\ncerebro.adddata(data)\n```\n\n### 从CSV文件加载\n\n```python\n# 通用CSV格式\ndata = bt.feeds.GenericCSVData(\n    dataname='stock_data.csv',\n    dtformat='%Y-%m-%d',    # 日期格式\n    datetime=0,              # 日期列索引\n    open=1,                  # 开盘价列索引\n    high=2,                  # 最高价列索引\n    low=3,                   # 最低价列索引\n    close=4,                 # 收盘价列索引\n    volume=5,                # 成交量列索引\n    openinterest=-1          # 持仓量列索引（-1表示无此列）\n)\ncerebro.adddata(data)\n```\n\n### 多股票 / 多周期\n\n```python\n# 加载多只股票数据\ndata1 = bt.feeds.PandasData(dataname=df1, name='stock1')\ndata2 = bt.feeds.PandasData(dataname=df2, name='stock2')\ncerebro.adddata(data1)\ncerebro.adddata(data2)\n\n# 在策略中访问多只股票\nclass MultiStockStrategy(bt.Strategy):\n    def __init__(self):\n        # self.datas[0]是第一只股票，self.datas[1]是第二只\n        self.sma1 = bt.indicators.SMA(self.datas[0].close, period=20)\n        self.sma2 = bt.indicators.SMA(self.datas[1].close, period=20)\n\n    def next(self):\n        for i, d in enumerate(self.datas):\n            print(f'{d._name}: close={d.close[0]:.2f}')\n```\n\n### 数据重采样（分钟线转日线）\n\n```python\n# 加载分钟数据\ndata_min = bt.feeds.GenericCSVData(dataname='1min_data.csv', timeframe=bt.TimeFrame.Minutes)\ncerebro.adddata(data_min)\n\n# 重采样为日线\ncerebro.resampledata(data_min, timeframe=bt.TimeFrame.Days)\n```\n\n\n\n## 策略类详解\n\n### 策略参数\n\n```python\nclass MyStrategy(bt.Strategy):\n    # 定义可调参数（元组格式）\n    params = (\n        ('fast_period', 5),     # 快速均线周期\n        ('slow_period', 20),    # 慢速均线周期\n        ('stake', 100),         # 每次交易手数\n    )\n\n    def __init__(self):\n        self.fast_ma = bt.indicators.SMA(period=self.p.fast_period)\n        self.slow_ma = bt.indicators.SMA(period=self.p.slow_period)\n        # self.p 是 self.params 的简写\n\n    def next(self):\n        if self.fast_ma[0] > self.slow_ma[0]:\n            self.buy(size=self.p.stake)\n\n# 参数可在运行时覆盖\ncerebro.addstrategy(MyStrategy, fast_period=10, slow_period=30)\n```\n\n### 交易方法\n\n```python\nclass MyStrategy(bt.Strategy):\n    def next(self):\n        # 按数量买入\n        self.buy(size=100)                    # 买入100股\n        self.sell(size=100)                   # 卖出100股\n\n        # 调整到目标仓位\n        self.order_target_size(target=500)    # 调整持仓为500股\n        self.order_target_value(target=50000) # 调整持仓为5万元市值\n        self.order_target_percent(target=0.5) # 调整持仓为总资产的50%\n\n        # 限价单\n        self.buy(size=100, price=10.5, exectype=bt.Order.Limit)\n        # 止损单\n        self.sell(size=100, price=9.0, exectype=bt.Order.Stop)\n        # 止损限价单\n        self.buy(size=100, price=10.5, pricelimit=10.8, exectype=bt.Order.StopLimit)\n\n        # 撤单\n        order = self.buy(size=100)\n        self.cancel(order)\n\n        # 对其他股票下单\n        self.buy(data=self.datas[1], size=200)  # 买入第二只股票\n```\n\n### 订单通知回调\n\n```python\nclass MyStrategy(bt.Strategy):\n    def notify_order(self, order):\n        \"\"\"订单状态变化时触发\"\"\"\n        if order.status in [order.Submitted, order.Accepted]:\n            return  # 订单已提交/已接受，等待执行\n\n        if order.status in [order.Completed]:\n            if order.isbuy():\n                print(f'买入执行: 价格={order.executed.price:.2f}, '\n                      f'数量={order.executed.size}, 手续费={order.executed.comm:.2f}')\n            else:\n                print(f'卖出执行: 价格={order.executed.price:.2f}, '\n                      f'数量={order.executed.size}, 手续费={order.executed.comm:.2f}')\n\n        elif order.status in [order.Canceled, order.Margin, order.Rejected]:\n            print(f'订单失败: 状态={order.getstatusname()}')\n\n    def notify_trade(self, trade):\n        \"\"\"交易完成时触发（一买一卖构成完整交易）\"\"\"\n        if trade.isclosed:\n            print(f'交易完成: 毛利润={trade.pnl:.2f}, 净利润={trade.pnlcomm:.2f}')\n```\n\n### 获取数据与持仓\n\n```python\nclass MyStrategy(bt.Strategy):\n    def next(self):\n        # 当前K线数据\n        current_close = self.data.close[0]     # 当前收盘价\n        prev_close = self.data.close[-1]       # 前一根K线收盘价\n        current_volume = self.data.volume[0]   # 当前成交量\n        current_date = self.data.datetime.date(0)  # 当前日期\n\n        # 持仓信息\n        position = self.getposition(self.data)\n        print(f'持仓数量: {position.size}')\n        print(f'平均成本: {position.price:.2f}')\n\n        # 账户信息\n        cash = self.broker.getcash()           # 可用资金\n        value = self.broker.getvalue()         # 总资产\n        print(f'可用资金: {cash:.2f}, 总资产: {value:.2f}')\n```\n\n\n\n## 内置技术指标\n\n```python\nclass MyStrategy(bt.Strategy):\n    def __init__(self):\n        # 均线\n        self.sma = bt.indicators.SimpleMovingAverage(self.data.close, period=20)\n        self.ema = bt.indicators.ExponentialMovingAverage(self.data.close, period=20)\n        self.wma = bt.indicators.WeightedMovingAverage(self.data.close, period=20)\n\n        # MACD\n        self.macd = bt.indicators.MACD(self.data.close)\n        # self.macd.macd = DIF线, self.macd.signal = DEA线, self.macd.histo = MACD柱\n\n        # RSI\n        self.rsi = bt.indicators.RSI(self.data.close, period=14)\n\n        # 布林带\n        self.boll = bt.indicators.BollingerBands(self.data.close, period=20, devfactor=2.0)\n        # self.boll.mid = 中轨, self.boll.top = 上轨, self.boll.bot = 下轨\n\n        # KDJ（随机振荡器）\n        self.stoch = bt.indicators.Stochastic(self.data, period=14)\n\n        # ATR（真实波动幅度）\n        self.atr = bt.indicators.ATR(self.data, period=14)\n\n        # 交叉信号\n        self.crossover = bt.indicators.CrossOver(self.sma, self.ema)\n        # crossover > 0 表示金叉, < 0 表示死叉\n```\n\n\n## 券商/经纪商设置\n\n```python\ncerebro = bt.Cerebro()\n\n# 设置初始资金\ncerebro.broker.setcash(1000000.0)\n\n# 设置手续费\ncerebro.broker.setcommission(commission=0.001)  # 0.1%\n\n# 按百分比设置手续费\ncerebro.broker.setcommission(\n    commission=0.0003,     # 0.03%\n    margin=None,           # 保证金（期货用）\n    mult=1.0               # 合约乘数（期货用）\n)\n\n# 设置滑点\ncerebro.broker.set_slippage_perc(perc=0.001)    # 百分比滑点\ncerebro.broker.set_slippage_fixed(fixed=0.02)   # 固定滑点\n\n# 设置每笔交易数量\ncerebro.addsizer(bt.sizers.FixedSize, stake=100)        # 固定100股\ncerebro.addsizer(bt.sizers.PercentSizer, percents=95)   # 总资产的95%\n```\n\n\n## 分析器\n\n```python\ncerebro = bt.Cerebro()\ncerebro.addstrategy(MyStrategy)\n\n# 添加分析器\ncerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')       # 夏普比率\ncerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')        # 最大回撤\ncerebro.addanalyzer(bt.analyzers.Returns, _name='returns')          # 收益率\ncerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')     # 交易统计\ncerebro.addanalyzer(bt.analyzers.SQN, _name='sqn')                 # 系统质量数\ncerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annual')     # 年化收益\n\nresults = cerebro.run()\nstrat = results[0]\n\n# 获取分析结果\nprint(f\"夏普比率: {strat.analyzers.sharpe.get_analysis()['sharperatio']:.2f}\")\nprint(f\"最大回撤: {strat.analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%\")\nprint(f\"总收益率: {strat.analyzers.returns.get_analysis()['rtot']:.4f}\")\n\n# 交易统计\ntrade_analysis = strat.analyzers.trades.get_analysis()\nprint(f\"总交易次数: {trade_analysis['total']['total']}\")\nprint(f\"盈利次数: {trade_analysis['won']['total']}\")\nprint(f\"亏损次数: {trade_analysis['lost']['total']}\")\n```\n\n\n\n## 参数优化\n\n```python\n# 使用 optstrategy 进行参数网格搜索\ncerebro = bt.Cerebro()\ncerebro.optstrategy(\n    MyStrategy,\n    fast_period=range(5, 15),     # 快速均线: 5 到 14\n    slow_period=range(20, 40, 5)  # 慢速均线: 20, 25, 30, 35\n)\n\ndata = bt.feeds.PandasData(dataname=df)\ncerebro.adddata(data)\ncerebro.broker.setcash(100000)\ncerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')\n\n# 运行优化（自动遍历所有参数组合）\nresults = cerebro.run(maxcpus=4)  # 多核并行\n\n# 提取最优参数\nbest_sharpe = -999\nbest_params = None\nfor result in results:\n    for strat in result:\n        sharpe = strat.analyzers.sharpe.get_analysis().get('sharperatio', 0) or 0\n        if sharpe > best_sharpe:\n            best_sharpe = sharpe\n            best_params = strat.params\n\nprint(f'最优参数: fast={best_params.fast_period}, slow={best_params.slow_period}')\nprint(f'最优夏普: {best_sharpe:.2f}')\n```\n\n\n## 进阶示例\n\n### MACD + 布林带组合策略\n\n```python\nimport backtrader as bt\n\nclass MACDBollStrategy(bt.Strategy):\n    \"\"\"MACD金叉 + 布林带下轨支撑组合买入策略\"\"\"\n    params = (\n        ('macd_fast', 12),\n        ('macd_slow', 26),\n        ('macd_signal', 9),\n        ('boll_period', 20),\n        ('boll_dev', 2.0),\n        ('stake', 100),\n    )\n\n    def __init__(self):\n        self.macd = bt.indicators.MACD(\n            self.data.close,\n            period_me1=self.p.macd_fast,\n            period_me2=self.p.macd_slow,\n            period_signal=self.p.macd_signal\n        )\n        self.boll = bt.indicators.BollingerBands(\n            self.data.close, period=self.p.boll_period, devfactor=self.p.boll_dev\n        )\n        # MACD金叉信号\n        self.macd_cross = bt.indicators.CrossOver(self.macd.macd, self.macd.signal)\n\n    def next(self):\n        if not self.position:\n            # 买入条件：MACD金叉 且 价格低于布林带中轨（低位买入）\n            if self.macd_cross[0] > 0 and self.data.close[0] < self.boll.mid[0]:\n                self.buy(size=self.p.stake)\n                print(f'{self.data.datetime.date(0)} 买入: {self.data.close[0]:.2f}')\n        else:\n            # 卖出条件：价格触及布林带上轨 或 MACD死叉\n            if self.data.close[0] > self.boll.top[0] or self.macd_cross[0] < 0:\n                self.sell(size=self.p.stake)\n                print(f'{self.data.datetime.date(0)} 卖出: {self.data.close[0]:.2f}')\n\n    def notify_trade(self, trade):\n        if trade.isclosed:\n            print(f'交易完成: 净利润={trade.pnlcomm:.2f}')\n\n# 运行回测\ncerebro = bt.Cerebro()\ncerebro.addstrategy(MACDBollStrategy)\ndata = bt.feeds.PandasData(dataname=df)  # df 为包含 OHLCV 数据的 DataFrame\ncerebro.adddata(data)\ncerebro.broker.setcash(100000)\ncerebro.broker.setcommission(commission=0.001)\ncerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')\ncerebro.addanalyzer(bt.analyzers.DrawDown, _name='dd')\nresults = cerebro.run()\nstrat = results[0]\nprint(f'夏普比率: {strat.analyzers.sharpe.get_analysis()[\"sharperatio\"]:.2f}')\nprint(f'最大回撤: {strat.analyzers.dd.get_analysis()[\"max\"][\"drawdown\"]:.2f}%')\ncerebro.plot()\n```\n\n\n### 海龟交易策略（完整实现）\n\n```python\nimport backtrader as bt\n\nclass TurtleStrategy(bt.Strategy):\n    \"\"\"经典海龟交易策略 — 唐奇安通道突破 + ATR仓位管理\"\"\"\n    params = (\n        ('entry_period', 20),    # 入场通道周期\n        ('exit_period', 10),     # 出场通道周期\n        ('atr_period', 20),      # ATR周期\n        ('risk_pct', 0.01),      # 每笔交易风险比例\n    )\n\n    def __init__(self):\n        self.entry_high = bt.indicators.Highest(self.data.high, period=self.p.entry_period)\n        self.entry_low = bt.indicators.Lowest(self.data.low, period=self.p.entry_period)\n        self.exit_high = bt.indicators.Highest(self.data.high, period=self.p.exit_period)\n        self.exit_low = bt.indicators.Lowest(self.data.low, period=self.p.exit_period)\n        self.atr = bt.indicators.ATR(self.data, period=self.p.atr_period)\n        self.order = None\n\n    def next(self):\n        if self.order:\n            return  # 有未完成订单，等待\n\n        # 计算仓位大小（基于ATR的风险管理）\n        atr_val = self.atr[0]\n        if atr_val <= 0:\n            return\n        unit_size = int(self.broker.getvalue() * self.p.risk_pct / atr_val)\n        unit_size = max(unit_size, 1)\n\n        if not self.position:\n            # 突破20日高点 → 做多\n            if self.data.close[0] > self.entry_high[-1]:\n                self.order = self.buy(size=unit_size)\n        else:\n            # 跌破10日低点 → 平仓\n            if self.data.close[0] < self.exit_low[-1]:\n                self.order = self.close()\n\n    def notify_order(self, order):\n        if order.status in [order.Completed]:\n            if order.isbuy():\n                print(f'{self.data.datetime.date(0)} 买入 {order.executed.size} 股 @ {order.executed.price:.2f}')\n            else:\n                print(f'{self.data.datetime.date(0)} 卖出 @ {order.executed.price:.2f}')\n        self.order = None\n```\n\n### 多股票轮动策略\n\n```python\nimport backtrader as bt\n\nclass MomentumRotation(bt.Strategy):\n    \"\"\"动量轮动策略 — 每月持有动量最强的前N只股票\"\"\"\n    params = (\n        ('momentum_period', 20),  # 动量计算周期（交易日）\n        ('hold_num', 3),          # 持股数量\n        ('rebalance_days', 20),   # 调仓周期\n    )\n\n    def __init__(self):\n        self.counter = 0\n        # 计算每只股票的动量指标（N日收益率）\n        self.momentums = {}\n        for d in self.datas:\n            self.momentums[d._name] = bt.indicators.RateOfChange(\n                d.close, period=self.p.momentum_period\n            )\n\n    def next(self):\n        self.counter += 1\n        if self.counter % self.p.rebalance_days != 0:\n            return  # 非调仓日\n\n        # 计算并排序每只股票的动量\n        rankings = []\n        for d in self.datas:\n            mom = self.momentums[d._name][0]\n            rankings.append((d._name, d, mom))\n        rankings.sort(key=lambda x: x[2], reverse=True)\n\n        # 选取动量最强的前N只股票\n        selected = [r[1] for r in rankings[:self.p.hold_num]]\n        selected_names = [r[0] for r in rankings[:self.p.hold_num]]\n        print(f'{self.data.datetime.date(0)} 选中股票: {selected_names}')\n\n        # 卖出不在目标列表中的持仓\n        for d in self.datas:\n            if self.getposition(d).size > 0 and d not in selected:\n                self.close(data=d)\n\n        # 等权重买入目标股票\n        if selected:\n            per_value = self.broker.getvalue() * 0.95 / len(selected)\n            for d in selected:\n                target_size = int(per_value / d.close[0])\n                current_size = self.getposition(d).size\n                if target_size > current_size:\n                    self.buy(data=d, size=target_size - current_size)\n                elif target_size < current_size:\n                    self.sell(data=d, size=current_size - target_size)\n```\n\n\n\n## 常见错误处理\n\n| 错误 | 原因 | 解决方法 |\n|------|------|----------|\n| `KeyError` 或数据列缺失 | DataFrame 列名不符合要求 | 确保列名为小写：`open, high, low, close, volume`，索引为日期 |\n| `IndexError: array index out of range` | 数据量不足，指标无法计算 | 增加数据量或减少指标周期 |\n| 绘图无输出/报错 | 未安装 matplotlib | `pip install matplotlib` |\n| 参数优化结果为空 | sharpe 返回 `None` | 使用 `or 0` 处理空值（见参数优化示例） |\n| 策略不触发交易 | 数据格式或逻辑问题 | 检查 DataFrame 索引是否为 DatetimeIndex，数据是否按日期排序 |\n| `NegativeStackSize` | 数据长度不足以覆盖预热期 | 增加数据量或减小指标窗口 |\n\n## 使用技巧\n\n- Backtrader 是纯本地框架，不依赖在线服务，适合离线研究。\n- 数据需要用户自行准备（可配合 baostock、AKShare、Tushare 等数据源 Skill 使用）。\n- 在 `__init__` 中定义指标，在 `next` 中编写交易逻辑 — 这是核心模式。\n- 使用 `self.data.close[0]` 访问当前值，`[-1]` 访问前一个值。\n- 通过 `optstrategy` 进行参数优化支持多核并行，显著加速。\n- 绘图需要安装 matplotlib；直接调用 `cerebro.plot()` 即可。\n\n## 规则\n\n- 使用此 Skill 前，确认用户明确需要 backtrader 框架进行策略开发。若用户仅需要数据获取，引导使用 baostock/pywencai 等数据 Skill。\n- **指标必须在 `__init__` 中定义**，交易逻辑必须在 `next` 中编写，不要在 `next` 中创建指标。\n- DataFrame 列名必须为**小写**（`open, high, low, close, volume`），索引必须为日期（`DatetimeIndex`）。\n- 示例中若需真实市场数据，应提示用户配合 baostock 等数据源 Skill 获取，不要在示例中使用虚构数据路径。\n- 始终在策略中处理 `sharpe` 为 `None` 的情况（参数优化时）。","tags":["backtrader","finance","quant","skills","lzwme","agent-skills"],"capabilities":["skill","source-lzwme","skill-backtrader","topic-agent-skills","topic-skills"],"categories":["finance-quant-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/lzwme/finance-quant-skills/backtrader","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add lzwme/finance-quant-skills","source_repo":"https://github.com/lzwme/finance-quant-skills","install_from":"skills.sh"}},"qualityScore":"0.469","qualityRationale":"deterministic score 0.47 from registry signals: · indexed on github topic:agent-skills · 39 github stars · SKILL.md body (16,077 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:58:28.456Z","embedding":null,"createdAt":"2026-05-09T01:05:18.182Z","updatedAt":"2026-05-18T18:58:28.456Z","lastSeenAt":"2026-05-18T18:58:28.456Z","tsv":"'-1':212,214,536,1188,1202,1483 '-999':846 '/docu/':43 '/mementum/backtrader)':14 '0':93,95,103,105,194,246,254,279,346,349,531,541,546,650,652,745,863,865,969,970,973,975,982,985,994,996,1000,1001,1008,1011,1059,1158,1162,1185,1199,1219,1229,1264,1288,1300,1326,1336,1349,1377,1446,1481 '0.0003':670 '0.001':130,665,685,1046 '0.01':1104 '0.02':691 '0.03':671 '0.1':666 '0.5':396 '0.95':1364 '1':197,249,261,435,1177,1283,1316 '1.0':677 '10':358,1096 '10.5':403,419 '10.8':421 '100':31,319,373,377,401,409,417,428,697,921 '100000':831,1043 '100000.0':126 '1000000.0':661 '12':907 '14':615,636,643,812 '15':808 '1min_data.csv':289 '2':200,1310 '2.0':623,919 '20':70,257,264,316,589,594,599,621,816,820,916,1092,1100,1249,1258 '200':437 '25':821 '26':910 '2f':136,142,280,470,476,483,489,515,518,560,572,575,753,761,890,986,1012,1025,1066,1074,1224,1232 '3':203,1254 '30':361,822 '35':823 '4':206,841 '40':817 '4f':768 '5':209,312,807,810,818 '500':384 '50000':390 '9':913 '9.0':411 '95':702 'akshar':1467 'analysi':751,758,766,771,773,778,785,792,860,1064,1071 'analyz':33 'annual':739 'array':1425 'atr':637,1098,1155,1160,1170 'atr仓位管理':1088 'atr周期':1101 'backtrad':1,2,9,11,48,52,61,150,896,1080,1238,1460,1499 'baostock':1466,1527 'baostock/pywencai':1503 'bash':45 'best':844,847,868,870,873,888 'best_params.fast':880 'best_params.slow':883 'boll':914,917 'broker':27 'bt':63,152,898,1082,1240 'bt.analyzers.annualreturn':737 'bt.analyzers.drawdown':717,1052 'bt.analyzers.returns':722 'bt.analyzers.sharperatio':712,833,1048 'bt.analyzers.sqn':732 'bt.analyzers.tradeanalyzer':727 'bt.cerebro':112,658,707,801,1028 'bt.feeds.genericcsvdata':185,287 'bt.feeds.pandasdata':176,223,229,825,1032 'bt.feeds.yahoofinancecsvdata':119 'bt.indicators.atr':640,1138 'bt.indicators.bollingerbands':618,941 'bt.indicators.crossover':646,952 'bt.indicators.exponentialmovingaverage':591 'bt.indicators.highest':1111,1125 'bt.indicators.lowest':1118,1132 'bt.indicators.macd':602,926 'bt.indicators.rateofchange':1274 'bt.indicators.rsi':612 'bt.indicators.simplemovingaverage':82,586 'bt.indicators.sma':252,259,326,332 'bt.indicators.stochastic':633 'bt.indicators.weightedmovingaverage':596 'bt.order.limit':405 'bt.order.stop':413 'bt.order.stoplimit':423 'bt.sizers.fixedsize':695 'bt.sizers.percentsizer':700 'bt.strategy':66,241,306,366,443,523,580,901,1085,1243 'bt.timeframe.days':300 'bt.timeframe.minutes':291 'cash':562,571 'cerebro':20,111,657,706,800,1027 'cerebro.addanalyzer':711,716,721,726,731,736,832,1047,1051 'cerebro.adddata':122,179,216,234,236,292,828,1040 'cerebro.addsizer':694,699 'cerebro.addstrategy':113,354,708,1029 'cerebro.broker.getvalue':135,141 'cerebro.broker.set':681,687 'cerebro.broker.setcash':125,660,830,1042 'cerebro.broker.setcommission':128,663,668,1044 'cerebro.optstrategy':802 'cerebro.plot':144,1075,1492 'cerebro.resampledata':296 'cerebro.run':137,742,839,1056 'class':64,239,304,364,441,521,578,899,1083,1241 'close':172,205,255,262,277,529,534,1421,1521 'col':166 'commiss':129,664,669,1045 'cross':951,968,999 'crossov':649 'csv':160 'csv格式':117 'current':528,538,543,1378,1386,1394,1399,1405 'd':191,270,1269,1294,1303,1342,1347,1351,1357,1368,1381,1390,1403 'd._name':276,1273,1299,1302 'd.close':278,1275,1376 'data':24,118,123,175,180,184,217,285,293,297,433,824,829,1031,1041,1356,1389,1402 'data1':222,235 'data2':228,237 'datafram':1039,1415,1452,1515 'dataframe加载':147 'dataframe必须包含列':168 'datanam':120,177,186,224,230,288,826,1033 'date':163,164,167,544 'datetim':193 'datetimeindex':1454,1524 'day':1257,1287 'dd':1054 'dea线':607 'def':73,86,242,265,321,340,367,444,501,524,581,922,955,1013,1106,1145,1205,1260,1279 'dev':918,948 'devfactor':622,946 'df':158,178,827,1034,1035 'df1':225 'df2':231 'dif线':605 'drawdown':719,760,1073 'dtformat':188 'elif':101,490,1396 'els':477,987,1194,1225 'entri':1090 'enumer':272 'exectyp':404,412,422 'exit':1094 'f':133,139,275,466,471,479,484,497,511,553,557,569,748,755,763,775,782,789,877,886,980,1006,1021,1061,1068,1217,1227,1334 'fast':310,356,804,879,906,931 'feed':25 'fix':689,690 'get':861 'github.com':13 'github.com/mementum/backtrader)':12 'high':170,199,1110,1124,1187,1419,1519 'hold':1252 'import':60,149,153,895,1079,1237 'index':165,1426 'indexerror':1424 'indic':29 'init':74,78,243,322,582,923,1107,1261,1473,1507 'instal':47,51,56,1438 'int':1166,1373 'kdj':630 'key':1306 'keyerror':1413 'lambda':1307 'len':1365 'lost':793 'low':171,202,1117,1131,1201,1420,1520 'm':190 'ma':325,331,345,348 'macd':600,892,905,908,911 'macdbollstrategi':900,1030 'macd柱':609 'macd死叉':991 'macd金叉':902,962 'macd金叉信号':949 'margin':672 'matplotlib':57,1436,1439,1490 'max':759,1072,1174 'maxcpus':840 'me1':929 'me2':933 'min':286,294,298 'mom':1297,1304 'momentum':1247 'momentumrot':1242 'mult':676 'multistockstrategi':240 'mystrategi':65,114,305,355,365,442,522,579,709,803 'name':226,232,713,718,723,728,733,738,834,1049,1053,1324,1339 'negativestacks':1456 'next':87,266,341,368,525,956,1146,1280,1476,1510,1513 'none':673,849,1144,1234,1443,1535 'notifi':445,502,1014,1206 'num':1253,1322,1332 'n日收益率':1266 'ohlcv':1037 'open':169,196,1418,1518 'openinterest':211 'optstrategi':798,1486 'order':425,430,446,448,1207,1209 'order.accepted':454 'order.canceled':493 'order.completed':462,1213 'order.executed.comm':475,488 'order.executed.price':469,482,1223,1231 'order.executed.size':473,486,1221 'order.getstatusname':500 'order.isbuy':464,1215 'order.margin':494 'order.rejected':495 'order.status':451,460,491,1211 'order.submitted':453 'panda':154 'param':68,309,848,874,904,1089,1246 'pars':162 'pct':1103,1169 'pd':156 'pd.read':159 'per':1361,1374 'perc':683,684 'percent':394,701 'period':69,84,256,263,311,315,327,329,333,335,357,360,588,593,598,614,620,635,642,805,814,881,884,915,928,932,936,943,945,1091,1095,1099,1113,1115,1120,1122,1127,1129,1134,1136,1140,1142,1248,1276,1278 'pip':46,50,55,1437 'plot':53 'posit':549 'position.price':559 'position.size':555 'prev':533 'price':402,410,418 'pricelimit':420 'print':132,138,274,465,478,496,510,552,556,568,747,754,762,774,781,788,876,885,979,1005,1020,1060,1067,1216,1226,1333 'python':16,36,59,148,182,220,283,303,363,440,520,577,656,705,796,894,1078,1236 'r':1315,1318,1325,1328 'rang':806,815,1429 'rank':1292,1320,1330 'rankings.append':1301 'rankings.sort':1305 'rebal':1256 'result':741,744,838,851,853,857,1055,1058 'return':455,724,1150,1163,1289 'revers':1311 'risk':1102 'rsi':610 'rtot':767 'select':1314,1323,1338,1354,1360,1366,1370 'self':75,88,244,267,323,342,369,447,504,526,583,924,957,1016,1108,1147,1208,1262,1281 'self.atr':639,1137,1157 'self.boll':617,940 'self.boll.bot':628 'self.boll.mid':624,974 'self.boll.top':626,995 'self.broker.getcash':563 'self.broker.getvalue':566,1167,1363 'self.buy':100,350,371,399,415,426,432,976,1190,1388 'self.cancel':429 'self.close':1204,1355 'self.counter':1263,1282,1285 'self.crossover':645 'self.data':551,634,641,1139 'self.data.close':83,92,102,530,535,587,592,597,603,613,619,927,942,972,984,993,1010,1184,1198,1480 'self.data.datetime.date':545,981,1007,1218,1228,1335 'self.data.high':1112,1126 'self.data.low':1119,1133 'self.data.volume':540 'self.datas':245,248,253,260,273,434,1271,1296,1344 'self.ema':590,648 'self.entry':1109,1116,1186 'self.exit':1123,1130,1200 'self.fast':324,344 'self.getposition':550,1346,1380 'self.macd':601,925,950,967,998 'self.macd.histo':608 'self.macd.macd':604,953 'self.macd.signal':606,954 'self.momentums':1267,1272,1298 'self.order':380,386,392,1143,1149,1189,1203,1233 'self.p':336 'self.p.atr':1141 'self.p.boll':944,947 'self.p.entry':1114,1121 'self.p.exit':1128,1135 'self.p.fast':328 'self.p.hold':1321,1331 'self.p.macd':930,934,938 'self.p.momentum':1277 'self.p.rebalance':1286 'self.p.risk':1168 'self.p.slow':334 'self.p.stake':352,978,1004 'self.params':338 'self.params.period':85 'self.position':98,107,960,1180 'self.rsi':611 'self.sell':109,375,407,1002,1401 'self.slow':330,347 'self.sma':81,94,104,585,647 'self.sma1':251 'self.sma2':258 'self.stoch':632 'self.wma':595 'sharp':714,835,845,858,867,869,871,872,889,1050,1441,1533 'sharperatio':752,862,1065 'signal':912,937,939 'size':351,372,376,382,400,408,416,427,436,977,1003,1165,1173,1176,1191,1193,1348,1372,1379,1382,1385,1387,1391,1393,1395,1398,1400,1404,1406,1408 'skill':1470,1496,1505,1529 'skill-backtrader' 'slippag':682,688 'slow':314,359,813,882,909,935 'source-lzwme' 'sqn':734 'stake':318,696,920 'stock1':227 'stock2':233 'stock_data.csv':121,161,187 'strat':743,855,1057 'strat.analyzers.dd.get':1070 'strat.analyzers.drawdown.get':757 'strat.analyzers.returns.get':765 'strat.analyzers.sharpe.get':750,859,1063 'strat.analyzers.trades.get':772 'strat.params':875 'strategi':22 'target':381,383,387,389,393,395,1371,1384,1392,1397,1407 'timefram':290,299 'topic-agent-skills' 'topic-skills' 'total':779,780,787,794 'trade':503,505,729,770,777,784,791,1015,1017 'trade.isclosed':509,1019 'trade.pnl':514 'trade.pnlcomm':517,1024 'true':1312 'turtlestrategi':1084 'tushar':1468 'unit':1164,1172,1175,1192 'val':1156,1161,1171 'valu':388,565,574,1362,1375 'volum':173,208,539,1422,1522 'won':786 'www.backtrader.com':42 'www.backtrader.com/docu/':41 'x':1308,1309 'y':189 'yahoo':116 '一买一卖构成完整交易':507 '上轨':627 '下轨':629 '不依赖在线服务':1462 '不要在':1512 '不要在示例中使用虚构数据路径':1531 '且':963 '中创建指标':1514 '中定义':79,1508 '中定义指标':1474 '中编写':1511 '中编写交易逻辑':1477 '中轨':625 '为':1534 '为包含':1036 '买入':983,1220 '买入100股':374 '买入执行':467 '买入条件':961 '买入第二只股票':438 '亏损次数':790 '交叉信号':644 '交易完成':512,1022 '交易完成时触发':506 '交易方法':362 '交易日':1251 '交易统计':730,769 '交易逻辑必须在':1509 '从csv文件加载':181 '从csv读取数据':157 '从panda':146 '价格':468,481 '价格低于布林带中轨':964 '价格触及布林带上轨':989 '低位买入':965 '使用':797,1444,1471,1479 '使用技巧':1459 '使用此':1495 '保证金':674 '做多':1182 '元组格式':308 '入场通道周期':1093 '内置':30 '内置技术指标':576 '净利润':516,1023 '出场通道周期':1097 '分析器':704 '分钟线转日线':282 '列名不符合要求':1416 '列名必须为':1516 '创建引擎':110 '初始化指标':76 '初始资金':134 '到':811 '券商':654 '前':1497 '前一根k线收盘价':537 '加载分钟数据':284 '加载多只股票数据':221 '加载数据':115 '动量计算周期':1250 '动量轮动策略':1244 '卖出':1009,1230 '卖出100股':378 '卖出不在目标列表中的持仓':1340 '卖出执行':480 '卖出条件':988 '即可':1493 '原因':1411 '参数优化':795 '参数优化时':1537 '参数优化结果为空':1440 '参数可在运行时覆盖':353 '可用资金':564,570 '可配合':1465 '合约乘数':678 '唐奇安通道突破':1087 '固定100股':698 '固定滑点':692 '在':77,1472,1475 '在此编写交易逻辑':90 '在策略中访问多只股票':238 '均线':584 '均线周期':72 '基于atr的风险管理':1154 '增加数据量或减小指标窗口':1458 '增加数据量或减少指标周期':1432 '处理空值':1447 '夏普比率':715,749,1062 '多周期':219 '多周期回测与实盘交易':6 '多核并行':842 '多策略':5 '多股票':218 '多股票轮动策略':1235 '如需绘图':49 '始终在策略中处理':1532 '安装':44 '完整实现':1077 '官方文档':40 '定义可调参数':307 '实现':37 '对其他股票下单':431 '小写':1517 '小写列名':174 '已接受':457 '布林带':616 '布林带下轨支撑组合买入策略':903 '布林带组合策略':893 '常见错误处理':1409 '平仓':1196 '平均成本':558 '年化收益':740 '应提示用户配合':1526 '开源量化回测框架':3,10 '开盘价列索引':198 '引导使用':1502 '引擎':21 '当前k线数据':527 '当前成交量':542 '当前收盘价':532 '当前日期':547 '当用户明确提及backtrader相关策略开发时使用':8 '快速均线':809 '快速均线周期':313 '总交易次数':776 '总收益率':764 '总资产':567,573 '总资产的95':703 '慢速均线':819 '慢速均线周期':317 '成交量列索引':210 '或':54,990 '或数据列缺失':1414 '手续费':474,487 '技术指标':32 '报错':1434 '持仓信息':548 '持仓数量':554 '持仓量列索引':213 '持股数量':1255 '指标必须在':1506 '指标无法计算':1431 '按数量买入':370 '按百分比设置手续费':667 '提取最优参数':843 '撤单':424 '支持多数据源':4 '收益率':725 '收盘价列索引':207 '数据是否按日期排序':1455 '数据格式或逻辑问题':1450 '数据源':26,145 '数据的':1038 '数据重采样':281 '数据量不足':1430 '数据长度不足以覆盖预热期':1457 '数据需要用户自行准备':1464 '数量':472,485 '无外部依赖':38 '无持仓则买入':99 '日期列索引':195 '日期格式':192 '是':337 '是一个开源':15 '是第一只股票':247 '是第二只':250 '是纯本地框架':1461 '显著加速':1488 '最优参数':878 '最优夏普':887 '最低价列索引':204 '最大回撤':720,756,1069 '最简示例':58 '最终资金':140 '最高价列索引':201 '有持仓则卖出':108 '有未完成订单':1151 '期货用':675,679 '未安装':1435 '核心组件包括':19 '框架进行策略开发':1500 '检查':1451 '止损单':406 '止损限价单':414 '每月持有动量最强的前n只股票':1245 '每根k线触发一次':89 '每次交易手数':320 '每笔交易风险比例':1105 '毛利润':513 '海龟交易策略':1076 '添加分析器':710 '状态':499 '百分比滑点':686 '的情况':1536 '的简写':339 '盈利次数':783 '直接调用':1491 '真实波动幅度':638 '确保列名为小写':1417 '确认用户明确需要':1498 '示例中若需真实市场数据':1525 '突破20日高点':1181 '等待':1152 '等待执行':458 '等数据':1504 '等数据源':1469,1528 '等权重买入目标股票':1358 '策略不触发交易':1449 '策略参数':71,302 '策略类':23 '策略类详解':301 '简单均线策略':67 '系统质量数':735 '索引为日期':1423 '索引必须为日期':1523 '索引是否为':1453 '纯':35 '纯python实现':7 '经典海龟交易策略':1086 '经纪商':28 '经纪商设置':655 '绘制结果':143 '绘图无输出':1433 '绘图需要安装':1489 '绩效分析':34 '股':1222 '自动计算':80 '自动遍历所有参数组合':837 '若用户仅需要数据获取':1501 '获取':1530 '获取分析结果':746 '获取数据与持仓':519 '表示无此列':215 '表示死叉':653 '表示金叉':651 '见参数优化示例':1448 '规则':1494 '解决方法':1412 '计算仓位大小':1153 '计算并排序每只股票的动量':1291 '计算每只股票的动量指标':1265 '订单失败':498 '订单已提交':456 '订单状态变化时触发':449 '订单通知回调':439 '设置初始资金':124,659 '设置手续费':127,662 '设置每笔交易数量':693 '设置滑点':680 '访问前一个值':1484 '访问当前值':1482 '调仓周期':1259 '调整到目标仓位':379 '调整持仓为500股':385 '调整持仓为5万元市值':391 '调整持仓为总资产的50':397 '账户信息':561 '跌破10日低点':1195 '运行优化':836 '运行回测':131,1026 '返回':1442 '这是核心模式':1478 '进行参数优化支持多核并行':1487 '进行参数网格搜索':799 '进阶示例':891 '适合离线研究':39,1463 '选中股票':1337 '选取动量最强的前n只股票':1313 '通用csv格式':183 '通过':1485 '采用事件驱动架构':18 '重采样为日线':295 '量化回测框架':17 '错误':1410 '限价单':398 '随机振荡器':631 '非调仓日':1290","prices":[{"id":"c2372e11-6df1-486a-a860-c8e4ea57a83a","listingId":"e64e3360-02f5-45fb-a467-7c9aee45d207","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"lzwme","category":"finance-quant-skills","install_from":"skills.sh"},"createdAt":"2026-05-09T01:05:18.182Z"}],"sources":[{"listingId":"e64e3360-02f5-45fb-a467-7c9aee45d207","source":"github","sourceId":"lzwme/finance-quant-skills/backtrader","sourceUrl":"https://github.com/lzwme/finance-quant-skills/tree/main/skills/backtrader","isPrimary":false,"firstSeenAt":"2026-05-09T01:05:18.182Z","lastSeenAt":"2026-05-18T18:58:28.456Z"}],"details":{"listingId":"e64e3360-02f5-45fb-a467-7c9aee45d207","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"lzwme","slug":"backtrader","github":{"repo":"lzwme/finance-quant-skills","stars":39,"topics":["agent-skills","skills"],"license":null,"html_url":"https://github.com/lzwme/finance-quant-skills","pushed_at":"2026-05-18T07:34:02Z","description":"一个面向金融量化交易领域的 Agent Skills 技能维护仓库，主要聚焦A股量化交易。","skill_md_sha":"4d9645dcfaf42bbb63c58cc3324dd55d5505f7da","skill_md_path":"skills/backtrader/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/lzwme/finance-quant-skills/tree/main/skills/backtrader"},"layout":"multi","source":"github","category":"finance-quant-skills","frontmatter":{"name":"backtrader","description":"Backtrader 开源量化回测框架，支持多数据源、多策略、多周期回测与实盘交易，纯Python实现。当用户明确提及backtrader相关策略开发时使用。"},"skills_sh_url":"https://skills.sh/lzwme/finance-quant-skills/backtrader"},"updatedAt":"2026-05-18T18:58:28.456Z"}}