You are here:  Home » 量化交易与机器学习 » backtrader » 优化improvements- backtrader中文教程

优化improvements

backtrader包括如何改善data feedsresultsmultiprocessing.

Note

两种行为已made

这些选项的行为可以通过两种新的Cerebro控制参数:

  • optdatas(默认值:True

    如果True和优化(并且该系统可以preload和使用runonce,数据预载将在主过程只需进行一次为了节省时间和resources.

  • optreturn(默认:True

    如果True优化结果不会是完整的Strategy对象(和所有datas, indicators, observers…),但和对象具有以下属性(同Strategy):

    • params(或p)策略曾用于execution
    • analyzers的策略具有executed

    在大多数occassions,只有analyzers并与params是事情需要评估的策略的性能。如果对于生成的值的详细分析(例如)indicators是必要的,把这个off

数据馈送Management

In了Optimization场景这是Cerebro一个可能的组合参数:

  • preload=True(默认)

    的数据Feeeds将运行的任何回溯测试code

  • runonce=True(默认值)之前被预加载

    Indicators将以批处理模式紧来计算for循环,而不是一步step.

If的两个条件都为Trueoptdatas=True,则:

  • Data Feeds将在主预加载产卵前的新工艺子过程(那些负责执行的backtesting

结果management

In了Optimization情况下两件事情应该发挥的最重要作用评价当不同的parameters with which each *Strategy是运行:

  • strategy.params(或strategy.p

    用于backtesting

  • strategy.analyzers

    The的实际设定值的负责提供如何Strategy评价的对象已实际执行。例如:

    SharpeRatio_A的(年率SharpeRatio

optreturn=True,而不是返回全strategy的情况下,占位符对象将被创建携带这两个属性的前述让评估采取place.

这避免了回传大量生成的数据的像例如值期间由指标生成的backtesting

如若full strategy objects被希望,只需设置optreturn=False脑期间在instantiation源一直延伸到添加做时cerebro.run.

的一些测试runs

Theoptimization样品backtrader或控制optdatasoptreturn(实际上禁用它们)

单核Run

As参考时会发生什么CPU的数量是有限的,以1multiprocessing模块不使用:

$ ./optimization.py --maxcpus 1
==================================================
**************************************************
--------------------------------------------------
OrderedDict([(u"smaperiod", 10), (u"macdperiod1", 12), (u"macdperiod2", 26), (u"macdperiod3", 9)])
**************************************************
--------------------------------------------------
OrderedDict([(u"smaperiod", 10), (u"macdperiod1", 13), (u"macdperiod2", 26), (u"macdperiod3", 9)])
...
...
OrderedDict([(u"smaperiod", 29), (u"macdperiod1", 19), (u"macdperiod2", 29), (u"macdperiod3", 14)])
==================================================
Time used: 184.922727833

多个Core Runs

Without限制的CPU的数量,Python的multiprocessing模块将尝试使用他们。optdatasoptreturn会disabled

Bothoptdataoptreturnactive

The默认行为:

$ ./optimization.py
...
...
...
==================================================
Time used: 56.5889185394

由具有多核的总的改进和data feedresults改进装置184.9256.58seconds.

Take到的是,样品使用252杆和指标从下降与252点的长度仅生成值。这只是一个example.

真正的问题是多少的,这是因为新型behavior.

optreturn deactivated

Let的传球全strategy对象返回给调用者:

$ ./optimization.py --no-optreturn
...
...
...
==================================================
Time used: 67.056914007

的执行时间增加18.50%(或15.62%的速度时)是在place.

optdatas deactivated

Each subproccess被强制加载自己的一套价值观的data feeds

$ ./optimization.py --no-optdatas
...
...
...
==================================================
Time used: 72.7238112637

执行时间增加了28.52%(或的加速22.19%)是在使用place.

Both deactivated

Still多核但与旧的非改进的性能:

$ ./optimization.py --no-optdatas --no-optreturn
...
...
...
==================================================
Time used: 83.6246643786

的执行时间增加47.79%(或一个速度 -最多的32.34%)是在place.

This表明,多核的使用是主要贡献者时间improvement.

Note

The处决已在笔记本电脑已经完成与i7-4710HQ(4核/ 8逻辑的)与在Windows 10的64位的RAM 16个千兆字节。里程可能会有所不同下优化过程中时间的减少等conditions

Concluding

  • The最大的因素是使用的多cores
  • 将样品与运行optdatasoptreturn显示的速度起坐围绕22.19%15.62%的每个(32.34%两者一起在测试)

样品Usage

$ ./optimization.py --help
usage: optimization.py [-h] [--data DATA] [--fromdate FROMDATE]
                       [--todate TODATE] [--maxcpus MAXCPUS] [--no-runonce]
                       [--exactbars EXACTBARS] [--no-optdatas]
                       [--no-optreturn] [--ma_low MA_LOW] [--ma_high MA_HIGH]
                       [--m1_low M1_LOW] [--m1_high M1_HIGH] [--m2_low M2_LOW]
                       [--m2_high M2_HIGH] [--m3_low M3_LOW]
                       [--m3_high M3_HIGH]

Optimization

optional arguments:
  -h, --help            show this help message and exit
  --data DATA, -d DATA  data to add to the system
  --fromdate FROMDATE, -f FROMDATE
                        Starting date in YYYY-MM-DD format
  --todate TODATE, -t TODATE
                        Starting date in YYYY-MM-DD format
  --maxcpus MAXCPUS, -m MAXCPUS
                        Number of CPUs to use in the optimization
                          - 0 (default): use all available CPUs
                          - 1 -> n: use as many as specified
  --no-runonce          Run in next mode
  --exactbars EXACTBARS
                        Use the specified exactbars still compatible with preload
                          0 No memory savings
                          -1 Moderate memory savings
                          -2 Less moderate memory savings
  --no-optdatas         Do not optimize data preloading in optimization
  --no-optreturn        Do not optimize the returned values to save time
  --ma_low MA_LOW       SMA range low to optimize
  --ma_high MA_HIGH     SMA range high to optimize
  --m1_low M1_LOW       MACD Fast MA range low to optimize
  --m1_high M1_HIGH     MACD Fast MA range high to optimize
  --m2_low M2_LOW       MACD Slow MA range low to optimize
  --m2_high M2_HIGH     MACD Slow MA range high to optimize
  --m3_low M3_LOW       MACD Signal range low to optimize
  --m3_high M3_HIGH     MACD Signal range high to optimize

Sample Code

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

import argparse
import datetime
import time

from backtrader.utils.py3 import range

import backtrader as bt
import backtrader.indicators as btind
import backtrader.feeds as btfeeds


class OptimizeStrategy(bt.Strategy):
    params = (("smaperiod", 15),
              ("macdperiod1", 12),
              ("macdperiod2", 26),
              ("macdperiod3", 9),
              )

    def __init__(self):
        # Add indicators to add load

        btind.SMA(period=self.p.smaperiod)
        btind.MACD(period_me1=self.p.macdperiod1,
                   period_me2=self.p.macdperiod2,
                   period_signal=self.p.macdperiod3)


def runstrat():
    args = parse_args()

    # Create a cerebro entity
    cerebro = bt.Cerebro(maxcpus=args.maxcpus,
                         runonce=not args.no_runonce,
                         exactbars=args.exactbars,
                         optdatas=not args.no_optdatas,
                         optreturn=not args.no_optreturn)

    # Add a strategy
    cerebro.optstrategy(
        OptimizeStrategy,
        smaperiod=range(args.ma_low, args.ma_high),
        macdperiod1=range(args.m1_low, args.m1_high),
        macdperiod2=range(args.m2_low, args.m2_high),
        macdperiod3=range(args.m3_low, args.m3_high),
    )

    # Get the dates from the args
    fromdate = datetime.datetime.strptime(args.fromdate, "%Y-%m-%d")
    todate = datetime.datetime.strptime(args.todate, "%Y-%m-%d")

    # Create the 1st data
    data = btfeeds.BacktraderCSVData(
        dataname=args.data,
        fromdate=fromdate,
        todate=todate)

    # Add the Data Feed to Cerebro
    cerebro.adddata(data)

    # clock the start of the process
    tstart = time.clock()

    # Run over everything
    stratruns = cerebro.run()

    # clock the end of the process
    tend = time.clock()

    print("==================================================")
    for stratrun in stratruns:
        print("**************************************************")
        for strat in stratrun:
            print("--------------------------------------------------")
            print(strat.p._getkwargs())
    print("==================================================")

    # print out the result
    print("Time used:", str(tend - tstart))


def parse_args():
    parser = argparse.ArgumentParser(
        description="Optimization",
        formatter_class=argparse.RawTextHelpFormatter,
    )

    parser.add_argument(
        "--data", "-d",
        default="../../datas/2006-day-001.txt",
        help="data to add to the system")

    parser.add_argument(
        "--fromdate", "-f",
        default="2006-01-01",
        help="Starting date in YYYY-MM-DD format")

    parser.add_argument(
        "--todate", "-t",
        default="2006-12-31",
        help="Starting date in YYYY-MM-DD format")

    parser.add_argument(
        "--maxcpus", "-m",
        type=int, required=False, default=0,
        help=("Number of CPUs to use in the optimization"
              "\n"
              "  - 0 (default): use all available CPUs\n"
              "  - 1 -> n: use as many as specified\n"))

    parser.add_argument(
        "--no-runonce", action="store_true", required=False,
        help="Run in next mode")

    parser.add_argument(
        "--exactbars", required=False, type=int, default=0,
        help=("Use the specified exactbars still compatible with preload\n"
              "  0 No memory savings\n"
              "  -1 Moderate memory savings\n"
              "  -2 Less moderate memory savings\n"))

    parser.add_argument(
        "--no-optdatas", action="store_true", required=False,
        help="Do not optimize data preloading in optimization")

    parser.add_argument(
        "--no-optreturn", action="store_true", required=False,
        help="Do not optimize the returned values to save time")

    parser.add_argument(
        "--ma_low", type=int,
        default=10, required=False,
        help="SMA range low to optimize")

    parser.add_argument(
        "--ma_high", type=int,
        default=30, required=False,
        help="SMA range high to optimize")

    parser.add_argument(
        "--m1_low", type=int,
        default=12, required=False,
        help="MACD Fast MA range low to optimize")

    parser.add_argument(
        "--m1_high", type=int,
        default=20, required=False,
        help="MACD Fast MA range high to optimize")

    parser.add_argument(
        "--m2_low", type=int,
        default=26, required=False,
        help="MACD Slow MA range low to optimize")

    parser.add_argument(
        "--m2_high", type=int,
        default=30, required=False,
        help="MACD Slow MA range high to optimize")

    parser.add_argument(
        "--m3_low", type=int,
        default=9, required=False,
        help="MACD Signal range low to optimize")

    parser.add_argument(
        "--m3_high", type=int,
        default=15, required=False,
        help="MACD Signal range high to optimize")

    return parser.parse_args()


if __name__ == "__main__":
    runstrat()

评论被关闭。