将支撑阻力Python代码转为Backtrader自定义指标时遇属性错误求助
解决Backtrader自定义支撑阻力指标的AttributeError问题
错误原因
你遇到的AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'shape',是因为Backtrader的DataFeed对象不是Pandas DataFrame,没有shape属性,不能用self.data.shape[0]获取数据长度。此外,原代码的一次性遍历逻辑也不适合Backtrader的逐K线推送机制,指标需要通过next()方法逐根处理数据。
核心修改点
- 移除依赖
shape的循环,改用Backtrader的next()方法处理每一根新K线 - 调整支撑/阻力判断逻辑,适配Backtrader的历史数据索引规则(当前K线为
[0],前N根为[-N]) - 将支撑阻力水平列表
levels设为类实例属性,持续保存历史水平 - 修正
is_far_from_level函数中平均波幅的计算方式,适配Backtrader数据获取方式 - 修正绘图配置,确保线条与指标输出对应
完整修正代码
import backtrader as bt import numpy as np class SR_Fractal(bt.Indicator): lines = ("S", "R") # 支撑线、阻力线 plotinfo = dict(subplot=False) # 在主图显示支撑阻力标记更直观 plotlines = dict( S=dict(color='red', marker='o', markersize=8, fillstyle='full', ls=''), R=dict(color='green', marker='^', markersize=8, fillstyle='full', ls='') ) def __init__(self): self.levels = [] # 保存已识别的支撑阻力水平 def is_far_from_level(self, value): """判断当前价格水平是否与已存在的支撑阻力足够远""" if not self.levels: return True # 计算已加载K线的平均波幅 highs = self.data.high.get(size=len(self.data)) lows = self.data.low.get(size=len(self.data)) ave = np.mean(highs - lows) # 检查是否与已有水平距离小于平均波幅 return all(abs(value - level) >= ave for _, level in self.levels) def next(self): # 至少需要5根K线才能判断 fractal 形态(前后各两根) if len(self.data) >= 5: # 判断倒数第3根K线是否为支撑位(对应原代码的i位置) low_i = self.data.low[-2] cond1 = low_i < self.data.low[-3] cond2 = low_i < self.data.low[-1] cond3 = self.data.low[-1] < self.data.low[0] cond4 = self.data.low[-3] < self.data.low[-4] is_support = cond1 and cond2 and cond3 and cond4 # 判断倒数第3根K线是否为阻力位 high_i = self.data.high[-2] cond1_r = high_i > self.data.high[-3] cond2_r = high_i > self.data.high[-1] cond3_r = self.data.high[-1] > self.data.high[0] cond4_r = self.data.high[-3] > self.data.high[-4] is_resistance = cond1_r and cond2_r and cond3_r and cond4_r # 处理支撑位 if is_support and self.is_far_from_level(low_i): self.levels.append((len(self.data)-3, low_i)) # 记录支撑位的K线索引和价格 self.lines.S[-2] = low_i # 在对应K线位置标记支撑价 # 处理阻力位 if is_resistance and self.is_far_from_level(high_i): self.levels.append((len(self.data)-3, high_i)) # 记录阻力位的K线索引和价格 self.lines.R[-2] = high_i # 在对应K线位置标记阻力价 # 非形态K线位置,支撑阻力线设为NaN(不显示) self.lines.S[0] = np.nan self.lines.R[0] = np.nan
代码说明
- next()方法:Backtrader指标的核心执行逻辑,每根新K线推送时自动调用
- 支撑阻力判断:当积累至少5根K线后,判断倒数第3根K线是否符合fractal形态(前后两根均高于/低于当前,且再外侧一根也高于/低于内侧)
- 水平去重:通过
is_far_from_level确保新识别的支撑阻力与已有水平距离大于平均波幅,避免重复标记 - 绘图配置:用不同颜色和标记在对应K线位置显示支撑阻力,
ls=''隐藏连接线,只保留标记点
内容的提问来源于stack exchange,提问作者bkcollection
相关产品推荐
相关产品推荐

