backtrader指南

目录

  • Backtrader
    • 基础概念
      • Data Feeds
      • Shortcurs for Data Feeds
      • Omitting the Data Feeds
      • Line
      • Lines declaration
      • Accessing `lines` in Data Feed
      • Lines len
      • Inheritance of Lines and Params
      • Indexing: 0 and -1
      • Slicing
      • Getting Slice
      • Lines:DELAYED indexing
      • Lines Coupling
      • Operators, using natural constructs
    • 操作平台
      • Up and Running
      • Data Feeds
      • A Strategy(derived) class
      • A Cerebro
    • Cerebro
      • Cerebro
        • Cerebro
        • 收集输入数据
        • 执行回测
        • 返回结果
        • 绘图
        • 回测逻辑
      • Cerebro - Memory Savings
        • Saving Memory
      • Optimization improvements
        • Data Feed Management
        • 运行测试
      • Exception
        • 异常基类
        • 访问异常
        • 已知的异常
      • Writer
        • 将writer添加到系统中
    • DataFeed
      • Data Feed
        • Data Feed Common paramters
        • CSV Data Feed Common parameters
        • GenericCSVData
      • Extending a Datafeed
      • Data - Multiple Timeframes
      • Data Resampling
      • Data Replay - 数据重播
      • Data Filter

Backtrader

用于量化交易的机器人,可以对于数据进行有效回测和指定策略等。

基础概念

Data Feeds

平台工作的基础将通过策略完成。这些将通过数据馈送,数据馈送以数组的形式自动提供给策略的成员变量,并提供数组位置的快捷方式。

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        sma = btind.SimpleMovingAverage(self.datas[0], period=self.params.period)
    
    ...
    
cerebro = bt.Cerebro()

...

data = btfeeds.MyFeed(...)
cerebro.adddata(data)

...

cerebro.addstrategy(MyStrategy, period=30)
...

Tip:

  • *args**kwargs该策略的__init__方法可以接收使用
  • self.datas为一个数组/列表/可迭代对象,需要至少有一项数据

Shortcurs for Data Feeds

  • self.data表示self.datas[0]
  • self.dataX表示self.datas[X]
class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        sma = btind.SimpleMovingAverage(self.data, period=self.params.period)

Omitting the Data Feeds

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        sma = btind.SimpleMovingAverage(period=self.params.period)

Line

大部分对象都包含一个Line对象,用户角度上来看

  • 它可以容纳一个或多个线,是一系列的线,是一组值的数组,放置在图表中表现为一条线

比较经典的线是由股票收盘价形成的线,称为收盘时线

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        self.movav = btind.SimpleMovingAverage(self.data, period=self.params.period)
    
    def next(self):
        if self.movav.lines.sma[0] < self.data.lines.close[0]:
            print('平均线高于收盘价格')

常见的缩写形式

  • xxxx.lines -> xxx.l
  • xxx.lines.name -> xxx.line_name
  • self.data_name -> self.data.lines.name
  • self.data1_name -> self.data1.lines.name

Lines declaration

定义对象中的线对象,可以采用line的类参数。

class SimpleMovingAverage(Indicator):
    lines = ('sma', )

访问:

  • self.lines[0] -> self.lines.sma
  • self.line -> self.lines[0]
  • self.lineX -> self.lines[X]
  • self.line_X -> self.lines[X]
  • self.dataY -> self.data.lines[Y]
  • self.dataX_Y -> self.data[X].lines[Y]

Accessing lines in Data Feed

通过省略形式访问lines数据

data = btfeeds.BacktraderCSVData(dataname="mydata.csv")
...

class MyStrategy(bt.Strategy):
    ...
    
    def next(self):
        if self.data.close[0] > 30.0:
            ...

Lines len

线对象是一组点,并在执行过程中,动态增长,可以通过调用len随时测量长度。

这些适用于:

  • Data Feeds
  • Strategies
  • Indicators

buflen可以查看预加载的数量。len返回已处理的条数,buflen报告已经加载的组数。

Inheritance of Lines and Params

Indexing: 0 and -1

  • index:0 当前值
  • index:-1 前一个值

Slicing

backtrader不支持对于线对象的切片方法。切片本身的意义不大。

Getting Slice

backtrader支持通过get方法对于对象进行切片。

myslice = self.my_sma.get(ago=0, size=1)

Lines:DELAYED indexing

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
        sefl.cmpval = self.data.close(-1) > self.sam
    
    def next(self):
        if self.cmpval[0]:
            print("收盘价高于平均线")

Lines Coupling

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    
    def __init__(self):
        
        sma0 = btind.SMA(self.data0, period=15)
        sma1 = btind.SMA(self.data1, period=5)
        
        self.butsig = sma0 > sma1
      
    def next(self):
        if self.buysig[0]:
            print('日均移线大雨周均平均线')

Operators, using natural constructs

支持操作符:

  • and -> And
  • or -> Or

支持逻辑控制:

  • if -> If

支持函数:

  • any -> Any
  • all -> All
  • cmp -> Cmp
  • max -> Max
  • min -> Min
  • sum -> Sum
  • reduce -> Reduce

操作平台

class SimpleMovingAverage(Indicator):
    lines = ('sma', )
    params = dict(period=20)
    
    def __init__(self):
        ...
        
    def prenext(self):
        print(len(self))
        
    def nextstart(self):
        print(len(self))
        self.next()
    
    def next(self):
        print(len(self))

Up and Running

  • Data Feed
  • Strategy
  • Cerebro

Data Feeds

平台提供了集合数据源

  • 几种csv格式和通用csv阅读器
  • Yahoo在线提取器
  • 支持接受pandas DataFrame和blaze对象
  • 通过Interacive Brokers、Visual Chart和Oanda进行数据馈送

雅虎财经数据

import backtrader as bt
import backtrader.feeds as btfeeds

...

datapath = "path/to/you/yahoo/data.csv"

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

A Strategy(derived) class

如果平台使用者是为了对数据进行回测,这些是在Strategy的派生类中实现的,至少需要定制两种方法:

  • init
  • next

基础使用

class MyStrategy(bt.Strategy):
    
    def __init__(self):
        self.sma = btind.SMA(self.data, period=20)
        
    def next(self):
        if self.sma > self.data.close:
            self.buy()
        if 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')
  • start 回测开始调用
  • stop 回测结束调用
  • notify_order 通知订单状态变更

更多的方法

  • buy/sell/close 使用底层经纪商和sizer向经纪人发送买/卖订单
  • getposition 获取当前市场位置
  • setsizer/getsizer 设置/获取基础的权重Sizer

A Cerebro

一旦数据馈送可用并定义了策略,Cerebro就会将所有的内容整合到一起并执行操作。

cerebro = bt.Cerebro()

一些默认值

  • 一个默认的broker被创建
  • 操作的佣金比例为0
  • 数据馈送预加载
  • 默认为批量处理模式

添加数据和策略

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

以上操作产生的效果如下:

  • 添加Data Feed实例
  • 添加自定义策略

更多的操作可见如下:

  • 设置操作模式
cerebro = bt.Cerebro(runonce=True, preload=True)
  • getbroker/setbroker
  • ploting
cerebro.run()
cerebro.plot()

plot支持的几个参数

- numfigs=1 设置分图数量
- plotter=None 传递给绘图仪表实例
- **kwargs 常用的关键词参数
  • 优化策略
cerebro.optstrategy(MyStrategy, period=xrange(10, 20))

Cerebro

Cerebro

Cerebro

此类为backtrader的基石,主要从事下列事务:

  • 收集所有输入、执行策略、观察行情、分析、生成文档
  • 执行回测/实时数据馈送/交易
  • 返回结果
  • 进行图像绘制

收集输入数据

  1. 创建一个cerebro
cerebro = bt.Cerebro(**kwargs)
  1. 添加数据馈送
data = bt.BacktraderCSVData(dataname="mypath.days", timeframe=bt.TimeFrame.Days)
cerebro.adddata(data)

可以对于数据进行重新采样

data = bt.BacktraderCSVData(dataname="mypath.min", timeframe=bt.TimeFrame.Minutes)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Days)

或者

data = bt.BacktraderCSVData(dataname="mypath.min", timeframe=bt.TimeFrame.Minutes)
cerebro.replaydatadata(data, timeframe=bt.TimeFrame.Days)
  1. 添加策略
cerebro.addstrategy(MyStrategy, myparam1=value1, myparam2=value2)

优化参数可以采用迭代器

cerebro.optstrategy(MyStrategy, myparam1=range(10, 20)
  1. 其它部分

还可以通过一些其它元素来增强回测体验,相关方法为:

  • addwriter
  • addanalyzer
  • addobserver / addmultiobserver
  1. 更换经纪人
broker = MyBroker()
cerebro.broker = broker
  1. 接受通知

当代理商或者数据馈送发送通知是,他们将通过Cerebro.notify_store执行。有三种方法可以执行这些通知:

  • 通过回调cerebro.addnotifycallback(callback)
callback(msg, *args, **kwargs)
  • 在策略子类中,覆盖notify_store方法
  • 在Cerebro子类中覆盖notify_store方法

执行回测

result = cerebro.run(**kwargs)

标准观察员

  • 一个经纪人观察员跟踪cashvalue
  • 一个交易员观察员
  • 一个买卖观察员

返回结果

result = cerebro.run(**kwargs)

result的格式取决于run是否使用了优化

  • 添加一个策略addstrategy,返回一个结果
  • 添加1个或更多策略optstrategy,但会一组结果

绘图

cerebro.plot()

回测逻辑

  1. 发送任何通知
  2. 要求数据馈送提供下一句分时柱线
  3. 通知有关订单、交易和现金/价值的经济人的信息
  4. 通知经纪人接受排队订单并使用新数据执行挂单
  5. 调用策略的next方法,允许策略评估新数据
  6. 告诉writer将数据写入新目标

Cerebro - Memory Savings

Saving Memory

backtrader认为通过绘图获得的视觉反馈是一个很好且必须的事情。因此设计上将所有内容放在了内存中,这样设计有一些缺陷:

  • array.array用于数据存储的数据必须在超出某些边界时分配和移动数据
  • 内存不足的机器会受影响
  • 实时馈赠系统可以在线数周/数月接受分辨率为秒/分钟的数据
  • 有可能backtrader运行在嵌入式设备中

因此需要backtrader支持动态内存方案:

  • exactbars(default: False)
    使用默认False值则内容存储在内存中

    可能的值

    • True or 1
      仅仅保存最小周期数据
      • 停用preloadrunonce
      • 停用绘图功能
    • -1 策略级别的数据会存储到内存中
      • 允许执行plottingpreloading
      • runonce将会停用
    • -2 作为策略属性保存的数据和指标保存在内存中

Optimization improvements

backtrader支持改善Data Feed和结果返回等。

支持的参数:

  • optdata(Default: False) 优化DataFeed流程
  • optreturn(Default: True) 优化返回结果
    如果设置为True则返回的不是完整的策略对象,而是具有以下属性的对象
    • params(or p)
    • analyzers

Data Feed Management

  • preload=True 回测前,预加载数据馈送
  • runonce=True 批处理模式

运行测试

  • maxcpus=None 限定执行回测的cpu核数

Exception

编写异常可以尽早可能的退出,让用户清晰了解错误的发生。

异常基类

所有异常都是基于BacktraderError实现。

访问异常

import backtrader as bt

...

class MyStrategy(bt.Strategy):
    
    def __init__(self):
        if something_goes_wrong():
            raise bt.errors.StrategySkipError # or raise bt.StrategySkipError

已知的异常

  • StrategySkipError 跳过该策略的异常

Writer

以下内容将写入流

  • 带有数据源、策略、指标和观察者的csv流
  • 属性的总结
    • 数据馈送
    • 策略
    • 指标/观察者
    • 分析器

将writer添加到系统中

  • 设置cerebro实例中的writer参数
  • 执行cerebro实例中的addwriter方法
cerebro.addwriter(bt.WriterFile, csv=True)

DataFeed

Data Feed

backtrader提供了一组数据馈送器

  • Yahoo
  • VisualChart
  • Backtrader CSV
  • Generic CSV support

Data Feed Common paramters

  • dataname(default: None) Required
  • name(default: “”) 绘图中装饰使用
  • fromdate(default: mindate) 开始时间
  • todate(default: maxdate) 结束时间
  • timeframe(default: TimeFrame.Days) 可能的值: Ticks, Seconds, Minutes, Days, Weeks, Months和Years
  • compression(default: 1) 样条图的实际条数
  • sessionstart(default: None) 设置数据会话开始时间
  • sessionend(default: None) 设置数据会话结束时间

CSV Data Feed Common parameters

  • headers(default: True)
  • separator(default: ‘,’)

GenericCSVData

  • dataname
  • datetime(default: 0)
  • time(default: -1)
  • open(default: 1), high(default: 2), low(default: 3), close(default: 4), volume(default: 5), opeinterest(default: 6)
  • nullvalue(default: float(‘NaN’))
  • dtformat(default: %Y-%m-%d %H:%M:%S)
  • tmformat(default: %H:%M:%S)

Extending a Datafeed

可以通过继承的方法,扩展数据馈送,增加部分数据。

from backtrader.feeds import GenericCSVData

class GenericCSV_PE(GenericCSVData):
    lines = ('pe', )
    params = (('pe', 8), )

Data - Multiple Timeframes

有时投资决策是在不同的时间范围内做出的,比如每周的趋势指标和每日的执行指标。甚至5分钟和60分钟。

这意味着需要组合多个时间范围的数据,backtrader支持这种组合。

cerebro已经支持了该种策略,用户应该遵循以下规则:

  • 时间范围最小的数据最先添加
  • 数据必须正确对齐才有意义

函数cerebro.resample用于创建更大的时间范围。

# Load the Data
datapath = args.dataname or '../../datas/2006-day-001.txt'
data = btfeeds.BacktraderCSVData(dataname=datapath)
cerebro.adddata(data)  # First add the original data - smaller timeframe

tframes = dict(daily=bt.TimeFrame.Days, weekly=bt.TimeFrame.Weeks,
               monthly=bt.TimeFrame.Months)

# Handy dictionary for the argument timeframe conversion
# Resample the data
if args.noresample:
    datapath = args.dataname2 or '../../datas/2006-week-001.txt'
    data2 = btfeeds.BacktraderCSVData(dataname=datapath)
    # And then the large timeframe
    cerebro.adddata(data2)
else:
    cerebro.resampledata(data, timeframe=tframes[args.timeframe],
                         compression=args.compression)

# Run over everything
cerebro.run()

Data Resampling

函数cerebro.resampledata支持的参数

  • timeframe(default: bt.TimeFrame.Days) 压缩的时间尺度
  • compression(default: 1) 压缩生成样条数
  • bar2edge(default: True) 使用时间边界进行目标冲采样
  • adjbartime(default: True) 调整重采样柱数
  • rightedge(default: True) 使用时间边界右边界
  • boundoff(default: 0) 按照一定数量的单位推动重采样/重播的边界
import datetime
import backtrader as bt


cerebro = bt.Cerebro()
data = bt.feeds.YahooFinanceCSVData(
    dataname="./data/orcl-1995-2014.txt",
    fromdate=datetime.datetime(2000, 1, 1),
    todate=datetime.datetime(2000, 12, 31),
    reverse=0
)

cerebro.adddata(data)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Weeks)

cerebro.run()
cerebro.plot(style='bar')

Data Replay - 数据重播

函数cerebro.replaydata支持的参数

  • timeframe(default: bt.TimeFrame.Days) 压缩的时间尺度
  • compression(default: 1) 压缩生成样条数
  • bar2edge(default: True) 使用时间边界进行目标冲采样
  • adjbartime(default: True) 调整重播柱数
  • rightedge(default: True) 使用时间边界右边界

Data Filter

定义datafilter需要满足两种形式:

  • callable(data, *args, **kwargs)
  • init(self, data, *args, **kwargs)和__call__(self, data, *args, **kwargs)

简单示例

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

你可能感兴趣的:(文档说明,python)