Skip to content

操作平台

原文: https://www.backtrader.com/docu/operating/

行迭代器

为了参与操作,plaftorm 使用行迭代器的概念。它们松散地模仿 Python 的迭代器,但实际上与它们无关。

策略和指标是行迭代器。

行迭代器概念试图描述以下内容:

  • 行迭代器踢从行迭代器,告诉它们进行迭代

  • 然后,行迭代器迭代其自己声明的命名行设置值

与常规 Python 迭代器一样,迭代的关键是:

  • next方法

    每次迭代都会调用它。行迭代器拥有并作为逻辑/计算基础的datas数组已经被平台移动到下一个索引(禁止数据重放)

    当满足行迭代器的最短周期时调用。下面再详细介绍一下。

但由于它们不是常规迭代器,因此还存在两种附加方法:

  • prenext

    在满足行迭代器`的最短周期之前调用。

  • nextstart

    当满足行迭代器`的最短周期时,精确调用一次

    默认行为是将调用转发到next,但如果需要,当然可以重写。

指标的附加方法

为了加快运行速度,指示器支持称为 runonce 的批量运行模式。它不是严格需要的(一个next方法就足够了),但它大大减少了时间。

runonce 方法规则使索引为 0 的 get/set 点无效,并依赖于对包含数据的底层数组的直接访问,并为每个状态传递正确的索引。

定义的方法遵循下一个族的命名:

  • once(self, start, end)

    在满足最短周期时调用。必须在起始和结束之间处理内部数组,从内部数组的起始处算起,起始和结束为零

  • preonce(self, start, end)

    在满足最短周期之前调用。

  • oncestart(self, start, end)

    当满足最短周期时,精确调用一次

    默认行为是将调用转发到once,但如果需要,当然可以重写。

最短周期

一幅画抵得上千言万语,在这种情况下,也可能是一个例子。SimpleMovingAverage 能够解释这一点:

class SimpleMovingAverage(Indicator):
    lines = ('sma',)
    params = dict(period=20)

    def __init__(self):
        ...  # Not relevant for the explanation

    def prenext(self):
        print('prenext:: current period:', len(self))

    def nextstart(self):
        print('nextstart:: current period:', len(self))
        # emulate default behavior ... call next
        self.next()

    def next(self):
        print('next:: current period:', len(self)) 

实例化过程可能如下所示:

sma = btind.SimpleMovingAverage(self.data, period=25) 

简要说明:

  • 假设传递给移动平均线的数据是标准数据馈送,其默认周期为1,即:数据馈送产生一个没有初始延迟的条。

  • 那么“period=25”实例化移动平均线的方法调用如下:

    • prenext24 次

    • nextstart1 次(依次呼叫next

    • nextn 额外次数,直到数据馈送耗尽

让我们来看杀手指标:一个简单移动平均值超过另一个简单移动平均值。实例化可能如下所示:

sma1 = btind.SimpleMovingAverage(self.data, period=25)

sma2 = btind.SimpleMovingAverage(sma1, period=20) 

现在发生了什么:

  • sma1同上

  • sma2正在接收数据馈送,其最短周期为 25,这是我们的sma1,因此

  • sma2方法的调用如图所示:

    • prenext前 25+18 次共 43 次

    • 25 次,让sma1产生其 1st敏感值

    • 18 次累积额外的sma1

    • 总共 19 个值(25 次调用后为 1 次,然后再调用 18 次)

    • nextstart然后 1 次(依次呼叫next

    • next数据馈送耗尽之前,再重复 n 次

当系统已经处理 44 条时,平台正在调用next

最短周期已根据传入数据自动调整。

战略和指标遵循以下行为:

  • 只有在达到自动计算的最短周期时才会调用next(除非对nextstart进行初始钩子调用)

笔记

对于跳动批量操作模式,同样的规则适用于preonceoncestartonce

笔记

最短周期行为可以被操纵,尽管不建议这样做。是否希望在战略或指标中使用setminperiod(minperiod)方法

正常运转

起跑至少涉及 3 条线对象:

  • 数据源

  • 策略(实际上是从策略派生的类)

  • 大脑(西班牙语中的大脑

数据源

显然,这些对象提供的数据将通过应用计算(直接和/或使用指标)进行回溯测试

该平台提供了几个数据源:

  • 几种 CSV 格式和一个通用的 CSV 阅读器

  • 雅虎在线抓取器

  • 支持接收熊猫数据帧火焰对象

  • 通过互动经纪人视觉图表Oanda提供实时数据源

该平台对数据提要的内容(如时间框架和压缩)不作任何假设。这些值以及名称可用于提供信息和数据馈送重采样等高级操作(将例如 5 分钟的数据馈送转换为每日数据馈送)

设置 Yahoo Finance 数据源的示例:

import backtrader as bt
import backtrader.feeds as btfeeds

...

datapath = 'path/to/your/yahoo/data.csv'

data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True) 

显示 Yahoo 的可选reversed参数,因为直接从 Yahoo 下载的 CSV 文件以最新日期开始,而不是以最旧日期开始。

如果数据跨越较大的时间范围,则实际加载的数据可以限制如下:

data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True
    fromdate=datetime.datetime(2014, 1, 1),
    todate=datetime.datetime(2014, 12, 31)) 

如果数据馈送中存在fromdatetodate,则两者都将包括在内。

如前所述,可以添加压缩和名称:

data = btfeeds.YahooFinanceCSVData(
    dataname=datapath,
    reversed=True
    fromdate=datetime.datetime(2014, 1, 1),
    todate=datetime.datetime(2014, 12, 31)
    timeframe=bt.TimeFrame.Days,
    compression=1,
    name='Yahoo'
   ) 

如果绘制数据,将使用这些值。

策略(派生)类

笔记

在继续之前,如果不希望对策略进行子类化,请检查文档中的信号部分,以获得更简化的方法。

任何使用该平台的人的目标都是对数据进行回溯测试,这是在一个策略(派生类)中完成的。

至少有 2 种方法需要定制:

  • __init__

  • next

在初始化期间,将创建数据和其他计算的指标,以备以后应用逻辑。

接下来调用下一个方法,为每个数据条应用逻辑。

笔记

如果传递了不同时间段的数据馈送(因此也传递了不同的条数),则将调用next方法来获取主数据(传递给 Cerbero 的 1st方法,见下文),该主数据必须是具有较小时间段的数据

笔记

如果使用数据重放功能,则在重放条形图的开发过程中,同一条形图将多次调用next方法。

派生类的基本策略:

class MyStrategy(bt.Strategy):

    def __init__(self):

        self.sma = btind.SimpleMovingAverage(self.data, period=20)

    def next(self):

        if self.sma > self.data.close:
            self.buy()

        elif self.sma < self.data.close:
            self.sell() 

策略还有其他可以覆盖的方法(或挂钩点):

class MyStrategy(bt.Strategy):

    def __init__(self):

        self.sma = btind.SimpleMovingAverage(self.data, period=20)

    def next(self):

        if self.sma > self.data.close:
            submitted_order = self.buy()

        elif self.sma < self.data.close:
            submitted_order = self.sell()

    def start(self):
        print('Backtesting is about to start')

    def stop(self):
        print('Backtesting is finished')

    def notify_order(self, order):
        print('An order new/changed/executed/canceled has been received') 

startstop方法应该是自解释的。正如预期的那样,在打印函数中的文本之后,当策略需要通知时,将调用notify_order方法。用例:

  • 请求购买或出售(如下图所示)

    买入/卖出将返回提交给经纪人的订单。保留对此已提交订单的引用由调用方决定。

    例如,它可用于确保在订单仍处于挂起状态时不会提交新订单。

  • 如果订单被接受/执行/取消/更改,代理将通过 notify 方法将状态更改(例如执行大小)通知回策略

《快速入门指南》中有一个完整的、功能性的notify_order方法订单管理示例。

其他策略类可以做更多工作:

  • buy/sell/close

    使用基础经纪人sizer向经纪人发送买入/卖出订单

    同样可以通过手动创建订单并将其传递给代理来完成。但是这个平台是为了让使用它的人更容易。

    close将获取当前市场头寸并立即关闭。

  • getposition(或物业“位置”)

    返回当前市场位置

  • setsizer/getsizer(或物业“sizer”)

    这些允许设置/获取基本的桩尺寸。同样的逻辑可以对照为相同情况(固定规模、与资本成比例、指数型)提供不同股权的规模确定器进行检查

    有大量的文学作品,但范·K·萨普在这方面有很多优秀的书籍。

策略是一个对象和这些支持参数,它们是使用标准 Python kwargs 参数收集的:

class MyStrategy(bt.Strategy):

    params = (('period', 20),)

    def __init__(self):

        self.sma = btind.SimpleMovingAverage(self.data, period=self.params.period)

    ...
    ... 

请注意,SimpleMovingAverage不再使用固定值 20 实例化,而是使用为策略定义的参数“period”。

大脑

一旦数据源可用,并且策略已经定义,一个脑波实例就是将所有东西聚集在一起并执行动作的地方。实例化一个很容易:

cerebro = bt.Cerebro() 

如果不希望有任何特殊情况,默认值将得到处理。

  • 将创建一个默认代理

  • 业务没有佣金

  • 数据源将被预加载

  • 默认执行模式为 runonce(批处理操作),速度更快

    所有指示器必须支持全速的runonce模式。平台中包含的那些都可以。

    自定义指示器不需要实现 runonce 功能。Cerebro将模拟它,这意味着那些与跳动不兼容的指示器将运行较慢。但大多数系统仍将以批处理模式运行。

由于数据馈送已经可用,并且也有一个策略(在前面创建),因此将所有数据馈送放在一起并使其运行的标准方法是:

cerebro.adddata(data)
cerebro.addstrategy(MyStrategy, period=25)
cerebro.run() 

请注意以下事项:

  • 添加了数据提要“实例”

  • MyStrategy“class”与将传递给它的参数(kwargs)一起添加。

    MyStrategy 的实例化将由 Cerbero 在后台完成,“addstrategy”中的任何 Kwarg 都将传递给它

用户可以根据需要添加任意多的策略和数据源。平台不强制/限制战略如何相互沟通以实现协调(如果愿意)。

当然,大脑提供了额外的可能性:

  • 决定预加载和运行模式:

    py cerebro = bt.Cerebro(runonce=True, preload=True)

    这里有一个约束:runonce需要预加载(如果没有,则无法运行批处理操作),当然预加载数据源不会强制runonce

  • setbroker/getbroker(及经纪人物业)

    如果需要,可以设置自定义代理。也可以访问实际的代理实例

  • 策划。在常规情况下,尽可能简单:

    py cerebro.run() cerebro.plot()

    plot 接受一些自定义参数

    • numfigs=1

      如果绘图过于密集,可能会将其分解为多个绘图

    • plotter=None

      可以传递客户绘图仪实例,而 Cerbero 不会实例化默认绘图仪实例

    • **kwargs-标准关键字参数

      这将传递给绘图仪。

    有关更多信息,请参见绘图部分。

  • 优化战略。

    如上所述,Cerbero 获得一个策略派生类(不是实例)和关键字参数,这些参数将在实例化时传递给它,这将在调用“run”时发生。

    这是为了实现优化。同一个策略类将根据需要使用新参数多次实例化。如果一个实例被传递给了大脑…这是不可能的。

    优化要求如下:

    py cerebro.optstrategy(MyStrategy, period=xrange(10, 20))

    方法optstrategyaddstrategy具有相同的特征码,但进行额外的内务处理以确保优化按预期运行。策略可能期望范围作为策略的正常参数,addstrategy不会对传递的参数进行假设。

    另一方面,optstrategy将理解 iterable 是一组必须按顺序传递给 Strategy 类的每个实例化的值。

    请注意,传递的不是单个值,而是一个值的范围。在这种简单的情况下,将为该策略尝试 10 个值 10->19(20 是上限)。

    如果使用额外参数开发更复杂的策略,则它们都可以传递给optstrategy。不必进行优化的参数可以直接传递,而最终用户不必创建一个只有一个值的伪 iterable。例子:

    py cerebro.optstrategy(MyStrategy, period=xrange(10, 20), factor=3.5)

    optstrategy方法查看 factor,并在背景中为具有单个元素的 factor 创建(所需的)伪 iterable(在示例 3.5 中)

    笔记

    交互式 Python shell 和Windows下的某些类型的冻结可执行文件与 Pythonmultiprocessing模块存在问题

    请阅读关于multiprocessing的 Python 文档。


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组