BackTrader 中文文档(四)(1)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: BackTrader 中文文档(四)

数据供稿 - 过滤器

过滤器

原文:www.backtrader.com/docu/filters/

此功能是相对较晚添加到backtrader中的,并且必须适应已经存在的内部结构。这使得它不像希望的那样灵活和 100%功能齐全,但在许多情况下仍然可以实现目的。

尽管实现尝试允许即插即用的过滤器链接,但是现有的内部结构使得很难确保总是可以实现。因此,一些过滤器可能被链接,而另一些则可能没有。

目的

  • 转换由数据源提供的值以提供不同的数据源

实现是为了简化可以通过cerebro API 直接使用的两个明显过滤器的实现。这些是:

  • 重新采样cerebro.resampledata
    在这里,过滤器转换了传入数据源时间框架压缩。例如:
(Seconds, 1) -> (Days, 1)` 
  • 这意味着原始数据提供的是分辨率为1 秒的柱状图。 重新采样过滤器拦截数据并将其缓冲,直到可以提供1 天柱状图。当看到下一天的1 秒柱状图时,将会发生这种情况。
  • 重播cerebro.replaydata
    对于上述相同的时间段,该过滤器将使用1 秒分辨率的柱状图来重建1 天柱状图。
    这意味着1 天柱状图会被提供与看到的1 秒柱状图一样多次,并更新以包含最新信息。
    例如,这模拟了实际交易日的发展方式。
    注意
    数据的长度,len(data)以及策略的长度在不变的情况下保持不变。

过滤器工作中

给定现有的数据源,您可以使用数据源的addfilter方法:

data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.addata(data)

即使它恰好与重新采样/重播过滤器兼容,也可以执行以下操作:

data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.replaydata(data)

过滤器接口

一个filter必须符合给定的接口,即:

  • 一个可调用的函数,接受此签名:
callable(data, *args, **kwargs)` 

或者

  • 一个可以实例化调用的类
  • 在实例化期间,__init__方法必须支持此签名:
def __init__(self, data, *args, **kwargs)` 
  • __call__方法具有以下签名:
def __call__(self, data, *args, **kwargs)` 
  • 对于来自数据源的每个新输入值,将调用该实例。 \*args\*kwargs__init__传递的相同。
    返回值
* `True`: the inner data fetching loop of the data feed must retry
  fetching data from the feed, becaue the length of the stream was
  manipulated
* `False` even if data may have been edited (example: changed
  `close` price), the length of the stream has remain untouched` 
  • 在基于类的过滤器的情况下,可以实现 2 个附加方法
  • 具有以下签名的last
def last(self, data, *args, **kwargs)` 
  • 数据源结束时,将调用此方法,允许过滤器传递它可能已经缓冲的数据。一个典型的情况是重新采样,因为柱状图被缓冲,直到看到下一个时间段的数据。当数据源结束时,没有新数据来推送缓冲的数据出去。
    last提供了将缓冲数据推送出去的机会。

注意

很明显,如果过滤器根本不支持任何参数,并且将添加而无任何参数,则签名可以简化为:

def __init__(self, data, *args, **kwargs) -> def __init__(self, data)

一个示例过滤器

一个非常快速的过滤器实现:

class SessionFilter(object):
    def __init__(self, data):
        pass
    def __call__(self, data):
        if data.p.sessionstart <= data.datetime.time() <= data.p.sessionend:
            # bar is in the session
            return False  # tell outer data loop the bar can be processed
        # bar outside of the regular session times
        data.backwards()  # remove bar from data stack
        return True  # tell outer data loop to fetch a new bar

这个过滤器:

  • 使用data.p.sessionstartdata.p.sessionend(标准数据源参数)来判断条是否在会话中。
  • 如果在会话中,返回值为False,以指示未执行任何操作,可以继续处理当前条目
  • 如果不在会话中,则从流中移除该条,并返回True以指示必须获取新条。
    注意
    data.backwards()利用LineBuffer接口。 这深入到backtrader的内部。

这种过滤器的用法:

  • 一些数据源包含非常规交易时间外的数据,这些数据可能不受交易者的关注。 使用此过滤器仅将会话内条考虑在内。

用于过滤器的数据伪-API

在上述示例中,已经展示了过滤器如何调用data.backwards()以从流中移除当前条。 数据源对象的有用调用,旨在作为过滤器的伪-API

  • data.backwards(size=1, force=False):通过将逻辑指针向后移动来从数据流中删除size条(默认为1)。 如果force=True,则物理存储也将被删除。
    移除物理存储是一项细致的操作,仅用作内部操作的黑客方法。
  • data.forward(value=float('NaN'), size=1):将size条移动到存储区向前移动,必要时增加物理存储并用value填充。
  • data._addtostack(bar, stash=False):将bar添加到堆栈以供以后处理。 bar是一个包含与数据源的lines一样多的值的可迭代对象。
    如果stash=False,则添加到堆栈的条将立即被系统消耗,在下一次迭代开始时。
    如果stash=True,则条将经历整个循环处理,包括可能被过滤器重新解析
  • data._save2stack(erase=False, force=False):将当前数据条保存到堆栈以供以后处理。 如果erase=True,则将调用data.backwards并将接收参数force
  • data._updatebar(bar, forward=False, ago=0):使用可迭代对象bar中的值来覆盖数据流中ago位置的值。 默认情况下,ago=0将更新当前条。 如果是-1,则是前一个。

另一个示例:粉鱼过滤器

这是一个可以链接的过滤器的示例,并且旨在如此,以连接到另一个过滤器,即replay 过滤器Pinkfish名称来自于其主页描述该想法的库:使用每日数据执行仅在分时数据中才可能的操作。

要实现效果:

  • 每日条将分解为 2 个组件:OHL然后是C
  • 这两个部分通过重播链接以在流中发生以下情况:
With Len X     -> OHL
With Len X     -> OHLC
With Len X + 1 -> OHL
With Len X + 1 -> OHLC
With Len X + 2 -> OHL
With Len X + 2 -> OHLC
...` 

逻辑:

  • 收到OHLC条时,将其复制到一个可迭代对象中,并分解为以下内容:
  • 一个OHL条。 由于这个概念实际上并不存在,收盘价格被替换为开盘价格以真正形成一个OHLO条。
  • 一个不存在的 C 条,实际上会被传递为一个刻度 CCCC
  • 成交量在这两部分之间分配
  • 当前条被从流中移除
  • OHLO 部分被放入堆栈中进行即时处理
  • CCCC 部分被放入存储区,在下一轮处理中处理
  • 因为堆栈中有一些需要立即处理的内容,过滤器可以返回 False 来指示这一点。

这个过滤器与以下内容一起工作:

  • 重播 过滤器将 OHLOCCCC 部分组合在一起,最终生成一个 OHLC 条。

使用案例:

  • 看到像是如果今天的最大值是过去 20 个交易日中的最高最大值,就发出一个 Close 订单,该订单在第 2 个刻度执行。

代码:

class DaySplitter_Close(bt.with_metaclass(bt.MetaParams, object)):
  '''
 Splits a daily bar in two parts simulating 2 ticks which will be used to
 replay the data:
 - First tick: ``OHLX``
 The ``Close`` will be replaced by the *average* of ``Open``, ``High``
 and ``Low``
 The session opening time is used for this tick
 and
 - Second tick: ``CCCC``
 The ``Close`` price will be used for the four components of the price
 The session closing time is used for this tick
 The volume will be split amongst the 2 ticks using the parameters:
 - ``closevol`` (default: ``0.5``) The value indicate which percentage, in
 absolute terms from 0.0 to 1.0, has to be assigned to the *closing*
 tick. The rest will be assigned to the ``OHLX`` tick.
 **This filter is meant to be used together with** ``cerebro.replaydata``
 '''
    params = (
        ('closevol', 0.5),  # 0 -> 1 amount of volume to keep for close
    )
    # replaying = True
    def __init__(self, data):
        self.lastdt = None
    def __call__(self, data):
        # Make a copy of the new bar and remove it from stream
        datadt = data.datetime.date()  # keep the date
        if self.lastdt == datadt:
            return False  # skip bars that come again in the filter
        self.lastdt = datadt  # keep ref to last seen bar
        # Make a copy of current data for ohlbar
        ohlbar = [data.lines[i][0] for i in range(data.size())]
        closebar = ohlbar[:]  # Make a copy for the close
        # replace close price with o-h-l average
        ohlprice = ohlbar[data.Open] + ohlbar[data.High] + ohlbar[data.Low]
        ohlbar[data.Close] = ohlprice / 3.0
        vol = ohlbar[data.Volume]  # adjust volume
        ohlbar[data.Volume] = vohl = int(vol * (1.0 - self.p.closevol))
        oi = ohlbar[data.OpenInterest]  # adjust open interst
        ohlbar[data.OpenInterest] = 0
        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionstart)
        ohlbar[data.DateTime] = data.date2num(dt)
        # Ajust closebar to generate a single tick -> close price
        closebar[data.Open] = cprice = closebar[data.Close]
        closebar[data.High] = cprice
        closebar[data.Low] = cprice
        closebar[data.Volume] = vol - vohl
        ohlbar[data.OpenInterest] = oi
        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionend)
        closebar[data.DateTime] = data.date2num(dt)
        # Update stream
        data.backwards(force=True)  # remove the copied bar from stream
        data._add2stack(ohlbar)  # add ohlbar to stack
        # Add 2nd part to stash to delay processing to next round
        data._add2stack(closebar, stash=True)
        return False  # initial tick can be further processed from stack

Filters Reference

原文:www.backtrader.com/docu/filters-reference/

SessionFilter

class backtrader.filters.SessionFilter(data)

此类可以作为过滤器应用于数据源,并将过滤掉超出常规会话时间的盘中 bar(即:盘前/盘后市场数据)

这是一个“非简单”的过滤器,必须管理数据的堆栈(在初始化和 call 期间传递)

它不需要“last”方法,因为它没有需要传递的内容

SessionFilterSimple

class backtrader.filters.SessionFilterSimple(data)

此类可以作为过滤器应用于数据源,并将过滤掉超出常规会话时间的盘中 bar(即:盘前/盘后市场数据)

这是一个“简单”过滤器,不必管理数据的堆栈(在初始化和 call 期间传递)

它不需要“last”方法,因为它没有需要传递的内容

Bar 管理将由 SimpleFilterWrapper 类完成,该类在 DataBase.addfilter_simple 调用时添加

SessionFilller

class backtrader.filters.SessionFiller(data)

声明会话开始/结束时间内的数据源的 Bar Filler。

填充 bar 是使用声明的 Data Source timeframecompression 构建的(用于计算中间缺失的时间)

参数:

  • fill_price (def: None):
    如果传递了 None,则将使用前一个 bar 的收盘价。例如,要得到一个 bar,该 bar 需要时间,但不会在图表中显示… 使用 float(‘Nan’)
  • fill_vol (def: float(‘NaN’)):
    用于填充缺失的 volume 的值
  • fill_oi (def: float(‘NaN’)):
    用于填充缺失的持仓量的值
  • skip_first_fill (def: True):
    在看到第一个有效 bar 时,不要从 sessionstart 填充到该 bar

CalendarDays

class backtrader.filters.CalendarDays(data)

在交易日中添加缺失的日历天的 Bar Filler

参数:

  • fill_price (def: None):

0:用于填充 0 或 None 的给定值:使用最后已知的收盘价 -1:使用最后一个 bar 的中点(High-Low 平均值)

  • fill_vol (def: float(‘NaN’)):
    用于填充缺失的 volume 的值
  • fill_oi (def: float(‘NaN’)):
    用于填充缺失的持仓量的值

BarReplayer_Open

class backtrader.filters.BarReplayer_Open(data)

此过滤器将一个 bar 拆分为两部分:

  • Open:将使用 bar 的开盘价提供一个初始价格 bar,在该 bar 中,四个组件(OHLC)相等
    该初始 bar 的 volume/openinterest 字段为 0
  • OHLC:原始 bar 包含原始的 volume/openinterest

拆分模拟了一次回放,无需使用 replay 过滤器。

DaySplitter_Close

class backtrader.filters.DaySplitter_Close(data)

将每日 bar 拆分为两部分,模拟用于重放数据的 2 个 tick:

  • 第一个 tick:OHLX
    Close 将被替换为 OpenHighLow平均值
    此 tick 使用会话开放时间

  • 第二个 tick:CCCC
    Close价格将用于价格的四个组成部分
    会话结束时间用于此点

体积将根据以下参数分配给 2 个点:

  • closevol(默认:0.5)该值表示从 0.0 到 1.0 的绝对比例,应分配给收盘点。其余将分配给OHLX点。

此过滤器意在与 cerebro.replaydata 一同使用

平均趋势烛(HeikinAshi)

类 backtrader.filters.HeikinAshi(data)

此过滤器重新构建开盘价、最高价、最低价、收盘价以绘制平均趋势烛

参见:

* [`en.wikipedia.org/wiki/Candlestick_chart#Heikin_Ashi_candlesticks`](https://en.wikipedia.org/wiki/Candlestick_chart#Heikin_Ashi_candlesticks)
* [`stockcharts.com/school/doku.php?id=chart_school:chart_analysis:heikin_ashi`](http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:heikin_ashi)

砖形图(Renko)

类 backtrader.filters.Renko(data)

修改数据流以绘制砖形图(或砖块)

参数:

  • hilo(默认:False)使用最高价和最低价而不是收盘价来决定是否需要新砖
  • size(默认:None)每个砖的考虑大小
  • autosize(默认:20.0)如果sizeNone,则将用于自动计算砖的大小(简单地将当前价格除以给定值)
  • dynamic(默认:False)如果True并使用autosize,则移至新砖时将重新计算砖的大小。这当然会消除砖的完美对齐。
  • align(默认:1.0)用于对齐砖的价格边界的因子。例如,如果价格为3563.25,而align10.0,则得到的对齐价格将为3560。计算方式:
  • 3563.25 / 10.0 = 356.325
  • 四舍五入并去除小数 -> 356
  • 356 * 10.0 -> 3560

参见:

* [`stockcharts.com/school/doku.php?id=chart_school:chart_analysis:renko`](http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:renko)

雅虎数据源注意事项

原文:www.backtrader.com/docu/datayahoo/

2017 年 5 月,雅虎停止了用于历史数据下载的现有 csv 格式的 API。

一个新的 API(此处命名为 v7)迅速被标准化并已实施。

这也带来了实际 CSV 下载格式的更改。

使用 v7 API/格式

从版本 1.9.49.116 开始,这是默认行为。只需简单选择

  • YahooFinanceData 用于在线下载
  • YahooFinanceCSVData 用于离线下载的文件

使用传统的 API/格式

要使用旧的 API/格式

  1. 将在线雅虎数据源实例化为:
data = bt.feeds.YahooFinanceData(
    ...
    version='',
    ...
)` 
  1. 离线雅虎数据源为:
data = bt.feeds.YahooFinanceCSVData(
    ...
    version='',
    ...
)` 
  1. 可能在线服务会回来(该服务没有任何公告地停止了… 也有可能会回来)

或者

  1. 仅对在更改发生之前下载的离线文件,也可以进行以下操作:
data = bt.feeds.YahooLegacyCSV(
    ...
    ...
)` 
  1. 新的 YahooLegacyCSV 简单地使用 version='' 进行自动化。

Pandas 数据源示例

原文:www.backtrader.com/docu/pandas-datafeed/pandas-datafeed/

注意

必须安装 pandas 及其依赖项

支持 Pandas Dataframes 似乎是许多人关注的问题,他们依赖于已经可用的用于不同数据源(包括 CSV)的解析代码以及 Pandas 提供的其他功能。

数据源的重要声明。

注意

这些只是声明。不要盲目复制此代码。请参见下面示例中的实际用法

class PandasData(feed.DataBase):
  '''
 The ``dataname`` parameter inherited from ``feed.DataBase`` is the pandas
 DataFrame
 '''
    params = (
        # Possible values for datetime (must always be present)
        #  None : datetime is the "index" in the Pandas Dataframe
        #  -1 : autodetect position or case-wise equal name
        #  >= 0 : numeric index to the colum in the pandas dataframe
        #  string : column name (as index) in the pandas dataframe
        ('datetime', None),
        # Possible values below:
        #  None : column not present
        #  -1 : autodetect position or case-wise equal name
        #  >= 0 : numeric index to the colum in the pandas dataframe
        #  string : column name (as index) in the pandas dataframe
        ('open', -1),
        ('high', -1),
        ('low', -1),
        ('close', -1),
        ('volume', -1),
        ('openinterest', -1),
    )

上述从 PandasData 类中摘录的片段显示了键:

  • 实例化期间传递给类的 dataname 参数保存了 Pandas Dataframe
    此参数从基类 feed.DataBase 继承
  • 新参数使用DataSeries中常规字段的名称,并遵循以下约定
  • datetime(默认值:无)
  • None:datetime 是 Pandas Dataframe 中的“索引”
  • -1:自动检测位置或大小写相等的名称

= 0:对应 pandas 数据帧中的列的数字索引

  • string:pandas 数据帧中的列名(作为索引)
  • open, high, low, high, close, volume, openinterest(默认值:全部为 -1)
  • None:列不存在
  • -1:自动检测位置或大小写相等的名称

= 0:对应 pandas 数据帧中的列的数字索引

  • string:pandas 数据帧中的列名(作为索引)

一个小示例应该能够加载标准的 2006 示例,已由 Pandas 解析,而不是直接由 backtrader 解析

运行示例以使用 CSV 数据中的现有“标题”:

$ ./panda-test.py
--------------------------------------------------
               Open     High      Low    Close  Volume  OpenInterest
Date
2006-01-02  3578.73  3605.95  3578.73  3604.33       0             0
2006-01-03  3604.08  3638.42  3601.84  3614.34       0             0
2006-01-04  3615.23  3652.46  3615.23  3652.46       0             0

相同但告诉脚本跳过标题:

$ ./panda-test.py --noheaders
--------------------------------------------------
                  1        2        3        4  5  6
0
2006-01-02  3578.73  3605.95  3578.73  3604.33  0  0
2006-01-03  3604.08  3638.42  3601.84  3614.34  0  0
2006-01-04  3615.23  3652.46  3615.23  3652.46  0  0

第 2 次运行使用的是 tells pandas.read_csv

  • 跳过第一行输入(将 skiprows 关键字参数设置为 1)
  • 不查找标题行(将 header 关键字参数设置为 None)

backtrader 对 Pandas 的支持尝试自动检测是否使用了列名,否则使用数字索引,并相应地采取行动,尝试提供最佳匹配。

下图是对成功的致敬。Pandas Dataframe 已正确加载(在两种情况下)


测试的示例代码。

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import pandas
def runstrat():
    args = parse_args()
    # Create a cerebro entity
    cerebro = bt.Cerebro(stdstats=False)
    # Add a strategy
    cerebro.addstrategy(bt.Strategy)
    # Get a pandas dataframe
    datapath = ('../../datas/2006-day-001.txt')
    # Simulate the header row isn't there if noheaders requested
    skiprows = 1 if args.noheaders else 0
    header = None if args.noheaders else 0
    dataframe = pandas.read_csv(datapath,
                                skiprows=skiprows,
                                header=header,
                                parse_dates=True,
                                index_col=0)
    if not args.noprint:
        print('--------------------------------------------------')
        print(dataframe)
        print('--------------------------------------------------')
    # Pass it to the backtrader datafeed and add it to the cerebro
    data = bt.feeds.PandasData(dataname=dataframe)
    cerebro.adddata(data)
    # Run over everything
    cerebro.run()
    # Plot the result
    cerebro.plot(style='bar')
def parse_args():
    parser = argparse.ArgumentParser(
        description='Pandas test script')
    parser.add_argument('--noheaders', action='store_true', default=False,
                        required=False,
                        help='Do not use header rows')
    parser.add_argument('--noprint', action='store_true', default=False,
                        help='Print the dataframe')
    return parser.parse_args()
if __name__ == '__main__':
    runstrat()

数据源参考

译文:www.backtrader.com/docu/dataautoref/

AbstractDataBase

行:

* close
* low
* high
* open
* volume
* openinterest
* datetime

参数:

* dataname (None)
* name ()
* compression (1)
* timeframe (5)
* fromdate (None)
* todate (None)
* sessionstart (None)
* sessionend (None)
* filters ([])
* tz (None)
* tzinput (None)
* qcheck (0.0)
* calendar (None)

BackTrader 中文文档(四)(2)https://developer.aliyun.com/article/1489242

相关文章
|
9月前
|
索引
BackTrader 中文文档(六)(2)
BackTrader 中文文档(六)
106 0
|
9月前
|
Unix 索引 Python
BackTrader 中文文档(一)(2)
BackTrader 中文文档(一)
241 0
|
9月前
|
存储 算法 索引
BackTrader 中文文档(三)(1)
BackTrader 中文文档(三)
228 0
|
9月前
|
存储 缓存 Shell
BackTrader 中文文档(二)(3)
BackTrader 中文文档(二)
212 0
|
9月前
BackTrader 中文文档(五)(2)
BackTrader 中文文档(五)
103 0
|
9月前
|
索引 Python
BackTrader 中文文档(五)(3)
BackTrader 中文文档(五)
86 0
|
9月前
|
测试技术 索引 Python
BackTrader 中文文档(二)(2)
BackTrader 中文文档(二)
101 0
|
9月前
|
Python
BackTrader 中文文档(一)(3)
BackTrader 中文文档(一)
131 0
|
9月前
|
存储 API 索引
BackTrader 中文文档(四)(3)
BackTrader 中文文档(四)
71 0
|
9月前
|
存储 数据库连接 数据库
BackTrader 中文文档(三)(2)
BackTrader 中文文档(三)
166 0

热门文章

最新文章