Skip to content

重新审视战略选择

原文: https://www.backtrader.com/blog/posts/2017-05-16-stsel-revisited/stsel-revisited/

最初的策略选择方法使用两种策略,手动注册和一个简单的[0, 1]列表来决定哪种策略将成为策略的目标。

由于 Python 为元类提供了许多透视可能性,因此实际上可以将该方法自动化。让我们使用decorator方法,这可能是本例中侵入性最小的方法(无需为策略定义元类

改造工厂

工厂现在:

  • 在策略之前声明

  • 有一个空的_STRATS类属性(之前有返回的策略)

  • 有一个register类方法,该类方法将用作装饰器,并接受将添加到_STRATS的参数

  • 有一个COUNT类方法,它将返回一个迭代器(实际上是一个range),其中包含要优化的可用策略的计数

  • 对实际工厂方法__new__没有任何更改,该方法继续使用idx参数返回给定索引处_STRATS类属性中的任何内容

class StFetcher(object):
    _STRATS = []

    @classmethod
    def register(cls, target):
        cls._STRATS.append(target)

    @classmethod
    def COUNT(cls):
        return range(len(cls._STRATS))

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

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

像这样的:

  • StFetcher策略工厂本身不再包含任何硬编码策略

要优化的装饰策略

示例中的策略不需要修改。用StFetcherregister方法进行装饰就足以将其添加到选择组合中。

@StFetcher.register
class St0(bt.SignalStrategy): 

@StFetcher.register
class St1(bt.SignalStrategy): 

利用COUNT

过去在系统中添加策略工厂时使用optstrategy的手动[0, 1]列表可以完全替换为对StFetcher.COUNT()的透明调用。硬编码已经结束。

 cerebro.optstrategy(StFetcher, idx=StFetcher.COUNT()) 

试运行

$ ./stselection-revisited.py --optreturn
Strat 0 Name OptReturn:
  - analyzer: OrderedDict([(u'rtot', 0.04847392369449283), (u'ravg', 9.467563221580632e-05), (u'rnorm', 0.02414514457151587), (u'rnorm100', 2.414514457151587)])

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

我们的两个战略已经运行并(如预期)产生了不同的结果。

笔记

该示例非常小,但已使用所有可用的 CPU 运行。用--maxpcpus=1执行会更快。对于更复杂的场景,使用所有 CPU 将非常有用。

结论

选择已完全自动化。正如以前一样,我们可以设想类似于查询数据库中可用策略的数量,然后逐个获取这些策略。

样本使用

$ ./stselection-revisited.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
from backtrader.utils.py3 import range

class StFetcher(object):
    _STRATS = []

    @classmethod
    def register(cls, target):
        cls._STRATS.append(target)

    @classmethod
    def COUNT(cls):
        return range(len(cls._STRATS))

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

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

@StFetcher.register
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)

@StFetcher.register
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)

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=StFetcher.COUNT())
    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() 

我们一直在努力

apachecn/AiLearning

【布客】中文翻译组