索引和切片

索引和切片 #

索引:0 和 -1 #

Backtrader 中,Line 代表着一组按时间顺序排列的点。这些点在策略执行期间动态生成,可以通过索引来访问。

使用索引访问 Line #

访问当前值: 使用 0 索引访问当前的线值,如 self.data.close[0] 获取当前收盘价。

class MyStrategy(bt.Strategy):
   def next(self):
       print(self.data.close[0])  # 当前的收盘价

访问前值: 使用负数索引访问之前的值,如 self.data.close[-1] 获取上一条数据的收盘价。

class MyStrategy(bt.Strategy):
   def next(self):
       if self.data.close[0] > self.data.close[-1]:
           print("今天的收盘价高于昨日的收盘价")

索引的意义:

  • 0 索引指向当前时刻的值,-1 指向上一个时刻的值,以此类推。
  • 负数索引指向历史数据点,这对于时间序列分析和策略中的数据回溯非常有用。

简单示例:

class MyStrategy(bt.Strategy):
    def next(self):
        # 比较今天的收盘价和昨天的收盘价
        if self.data.close[0] > self.data.close[-1]:
            print("今天的收盘价更高")
        else:
            print("今天的收盘价更低")

在这个示例中,self.data.close[0] 是今天的收盘价,self.data.close[-1] 是昨天的收盘价。


切片 #

Backtrader 不支持对 Line 对象的切片操作,这是为了保持设计的一致性。切片适用于普通的 Python 数组,但在 Backtrader 中,Line 对象是动态增长的,因此切片的使用存在一定的限制。

为什么不支持切片 #

首先是 Line 的设计上要保持一致性。

Line 对象上的数据是通过索引(如 0-1)动态访问,基于时间序列进行数据处理。切片在此情况下并不适用,因为线的数据是按时间顺序排列的。

而常规可索引对象的切片是什么样的?

对于普通的 Python 对象,切片操作如下:

my_list = [1, 2, 3, 4, 5]
sliced_list = my_list[1:3]  # 返回 [2, 3]

Backtrader 中的 Line 对象更像一个流式数据源,不能直接进行切片。

如何获取线的某些点 #

虽然 Line 不支持切片,但你仍然可以使用 get() 方法来获取线的一部分数据。例如:

# 获取最后 10 个数据点
myslice = self.my_sma.get(size=10)  # 获取最近的 10 个值

这允许我们拿到指定数量的历史数据,且是按时间顺序拿到最近的数据。


延迟索引 #

Backtrader 中,延迟索引允许你在 __init__ 阶段访问历史数据,而无需手动使用负索引。通常情况下,[] 操作符用于在 next 阶段提取数据值,而通过延迟索引,可以在初始化阶段引用历史数据,并生成可以在 next 方法中直接使用的 Lines 对象。

举个例子,如果你想比较前一日的收盘价与当前的简单移动平均线(SMA),你不需要在每次迭代中手动进行比较,而可以通过预先生成的 Lines 对象来实现:

初始化时使用延迟索引 #

__init__ 方法中,你可以通过延迟索引定义需要的历史数据。例如,比较前一天的收盘价和当前的移动平均值:

class MyStrategy(bt.Strategy):
   params = dict(period=20)

   def __init__(self):
       self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
       self.cmpval = self.data.close(-1) > self.movav  # 比较前一日收盘价与当前20日均线

这里,self.data.close(-1) 通过延迟索引获取前一天的收盘价,self.movav 是当前的20日简单移动平均线。self.cmpval 是一个新的 Lines 对象,保存了每次比较的结果。

next 方法中使用延迟数据 #

next 方法中,你可以直接使用 Lines 对象的值进行逻辑判断。self.cmpval[0] 会返回当前条件是否成立:

class MyStrategy(bt.Strategy):
   def next(self):
       if self.cmpval[0]:  # 如果前一日收盘价高于当前移动平均线
           print("前一日收盘价高于当前简单移动平均线")

延迟索引的工作原理 #

self.data.close(-1) 使用延迟索引从历史数据中提取前一天的收盘价。这个语法会返回一个 Line 对象,但它是延迟的,即相对于当前时刻,它表示的是前一个时间点的 Line

语句 self.data.close(-1) > self.movav 会生成一个新的 Line 对象,该对象在 next 方法中返回 1(条件为真)或 0(条件为假),使你在 next 方法可直接使用比较结果。

通过这种方式,Backtrader 提供了更简洁和灵活的方式来引用和比较历史数据,而不需要手动管理索引,从而简化了策略的编写和逻辑实现。