Backtrader策略选择

  |  

休士顿我们有一个问题:

  • cerebro 不应多次运行。这不是第1 ,而不是认为用户做错了,这似乎是一个用例。

这个有趣的用例是通过票证177出现的。在这种情况下, cerebro 被多次用于评估从外部数据源获取的不同策略。

backtrader 仍然可以支持此用例,但不能以直接尝试的方式支持。

backtrader中的内置优化已经完成了所需的操作:

  • 实例化多个策略实例并收集结果

是唯一一个实例都属于同一类的东西。这就是Python通过让我们控制对象的创建来提供说明的地方。

首先,让我们使用内置的信号技术向脚本中添加非常快速的策略 backtrader

class St0(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)


class St1(bt.SignalStrategy):
    def __init__(self):
        sma1 = bt.ind.SMA(period=10)
        crossover = bt.ind.CrossOver(self.data.close, sma1)
        self.signal_add(bt.SIGNAL_LONG, crossover)

它再简单不过了。

现在让我们来做一个神奇的实现这两个策略。

class StFetcher(object):
    _STRATS = [St0, St1]

    def __new__(cls, *args, **kwargs):
        idx = kwargs.pop('idx')

        obj = cls._STRATS[idx](*args, **kwargs)
        return obj

Et voilá!实例化类StFetcher 时,方法 __new__ 将控制实例的创建。在这种情况下:

  • 获取idx 传递给它的参数

  • 使用此参数从_STRATS 存储了我们之前的范例策略的清单中获取策略

    注意

    没有什么可以阻止使用此idx 值从服务器和/或数据库获取策略。

  • 实例化并返回受影响的策略

主持演出

    cerebro.addanalyzer(bt.analyzers.Returns)
    cerebro.optstrategy(StFetcher, idx=[0, 1])
    results = cerebro.run(maxcpus=args.maxcpus, optreturn=args.optreturn)

事实上!优化就是这样!而不是addstrategy 我们使用 optstrategy 并传递的值数组 idx。这些值将由优化引擎反复运算。

由于cerebro 可以在每个优化传递中托管多个策略,因此结果将包含清单清单。每个子清单都是每个优化传递的结果。

在我们的例子中,每次通过只有 1 个策略,我们可以快速平展结果并提取我们添加的分析器的值。

    strats = [x[0] for x in results]  # flatten the result
    for i, strat in enumerate(strats):
        rets = strat.analyzers.returns.get_analysis()
        print('Strat {} Name {}:\n  - analyzer: {}\n'.format(
            i, strat.__class__.__name__, rets))

示例运行

./strategy-selection.py

Strat 0 Name St0:
  - analyzer: OrderedDict([(u'rtot', 0.04847392369449283), (u'ravg', 9.467563221580632e-05), (u'rnorm', 0.02414514457151587), (u'rnorm100', 2.414514457151587)])

Strat 1 Name St1:
  - analyzer: OrderedDict([(u'rtot', 0.05124714332260593), (u'ravg', 0.00010009207680196471), (u'rnorm', 0.025543999840699633), (u'rnorm100', 2.5543999840699634)])

我们的2个策略已经运行,并交付(如预期)不同的结果。

注意

该示例很少,但已使用所有可用的CPU运行。运行--maxpcpus=1 它将更快。对于使用所有 CPU 的更复杂的方案,将非常有用。

结论

策略选择用例是可能的,并且不需要绕过 backtrader 或Python本身中的任何内置设施。

示例用法

$ ./strategy-selection.py --help
usage: strategy-selection.py [-h] [--data DATA] [--maxcpus MAXCPUS]
                             [--optreturn]

Sample for strategy selection

optional arguments:
  -h, --help         show this help message and exit
  --data DATA        Data to be read in (default:
                     ../../datas/2005-2006-day-001.txt)
  --maxcpus MAXCPUS  Limit the numer of CPUs to use (default: None)
  --optreturn        Return reduced/mocked strategy object (default: False)

代码

这已被包括在 backtrader

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse

import backtrader as bt


class St0(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)


class St1(bt.SignalStrategy):
    def __init__(self):
        sma1 = bt.ind.SMA(period=10)
        crossover = bt.ind.CrossOver(self.data.close, sma1)
        self.signal_add(bt.SIGNAL_LONG, crossover)


class StFetcher(object):
    _STRATS = [St0, St1]

    def __new__(cls, *args, **kwargs):
        idx = kwargs.pop('idx')

        obj = cls._STRATS[idx](*args, **kwargs)
        return obj


def runstrat(pargs=None):
    args = parse_args(pargs)

    cerebro = bt.Cerebro()
    data = bt.feeds.BacktraderCSVData(dataname=args.data)
    cerebro.adddata(data)

    cerebro.addanalyzer(bt.analyzers.Returns)
    cerebro.optstrategy(StFetcher, idx=[0, 1])
    results = cerebro.run(maxcpus=args.maxcpus, optreturn=args.optreturn)

    strats = [x[0] for x in results]  # flatten the result
    for i, strat in enumerate(strats):
        rets = strat.analyzers.returns.get_analysis()
        print('Strat {} Name {}:\n  - analyzer: {}\n'.format(
            i, strat.__class__.__name__, rets))


def parse_args(pargs=None):

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for strategy selection')

    parser.add_argument('--data', required=False,
                        default='../../datas/2005-2006-day-001.txt',
                        help='Data to be read in')

    parser.add_argument('--maxcpus', required=False, action='store',
                        default=None, type=int,
                        help='Limit the numer of CPUs to use')

    parser.add_argument('--optreturn', required=False, action='store_true',
                        help='Return reduced/mocked strategy object')

    return parser.parse_args(pargs)


if __name__ == '__main__':
    runstrat()

推荐阅读

相关文章

Backtrader教程:经纪人 - 开仓作弊

“发布”1.9.44.116 添加了对 Cheat-On-Open的支持。这似乎是那些全力以赴的人的需求功能,他们在酒吧 close 后进行了计算,但希望与 open 价格相匹配。 当开盘价跳空(上涨或下跌,取决于是否buysell有效)并且现金不足以进行全面运营时,这样的用例就会失败。这将强制代理拒绝该操作。

Backtrader教程:安装

要求和版本 backtrader 是独立的,没有外部依赖关系(除非要绘图) 基本要求是: Python 2.7 Python 3.2 / 3.3/ 3.4 / 3.5 pypy/pypy3 如果需要绘图,则其他要求: Matplotlib >= 1.4.

Backtrader股票筛选

在寻找其他一些东西时,我在StackOverlow家族网站之一上遇到了一个问题:Quantitative Finance aka Quant StackExchange。问题: 它被标记为Python,因此值得一看的是 backtrader 是否能够胜任这项任务。 分析仪本身 该问题似乎适合用于简单的分析器。

Backtrader迪克森移动平均线

下面的reddit帖子以自己的作者Nathan Dickson(reddit句柄)命名了这个平均值Dickson移动平均线。 在一次对reddit Algotrading 的定期访问中,我发现了一篇关于移动平均线的帖子,该移动平均线试图模仿Jurik移动平均线(又名JMA)。

Backtrader数据同步

在最新版本中,次要编号已从 8 移至 9,以指示即使已考虑兼容性,也可能会对行为产生一些影响。 在 1.9.0.99 版中,使用 datetime 同步多个数据的整个机制已经重新设计(适用于下一个和一次模式)。

数据多时间帧

有时投资决策是使用不同的时间框架做出的: 每周评估趋势 每天执行条目 或者5分钟对60分钟。 这意味着需要将多个时间帧的数据组合在 backtrader 中以支援此类组合。 对它的本机支持已经内置。

Backtrader智能质押

版本 1.6.4.93 标志着 backtrader 的一个重要里程碑,即使版本号的更改很小。 职位大小调整是阅读Van K. Tharp的《Trade Your Way To Financial Freedom 》后,为这个项目奠定基础的事情之一。

Backtrader教程:绘图 - 日期范围

该版本1.9.31.x 增加了制作部分绘图的功能。 使用策略实例中保存的完整时间戳数组的索引 或者使用实际datetime.date 或 datetime.datetime 实例来限制必须绘制的内容。 一切都超过标准cerebro.plot。

Backtrader教程:分析仪 - PyFolio

注意 从(至少)2017-07-25pyfolio 开始,API已更改,不再 create_full_tear_sheet 具有 gross_lev 作为命名参数的参数。

Backtrader教程:数据馈送 - 多个时间帧

有时投资决策是使用不同的时间框架做出的: 每周评估趋势 每天运行条目 或者5分钟对60分钟。 这意味着需要组合多个时间帧的数据backtrader 来支持这种组合。 对它的本机支持已经内置。