BackTrader 中文文档(二十一)(3)

简介: BackTrader 中文文档(二十一)

BackTrader 中文文档(二十一)(2)https://developer.aliyun.com/article/1505417

多空头场景

这将模拟类似于具有年度利息的ETF,可以是常规的或反向的。首先让我们建立基线。

$ ./credit-interest.py --plot --stocklike
01 2005-03-22 23:59:59 SELL Size: -10 / Price: 3040.55
02 2005-04-11 23:59:59 BUY  Size: +10 / Price: 3088.47
...
...
34 2006-12-19 23:59:59 BUY  Size: +10 / Price: 4121.01
35 2006-12-19 23:59:59 BUY  Size: +10 / Price: 4121.01

还有更多操作,系统始终在市场中

由于ETF将对多头和空头操作收取利息,现在利息将同时增加:

$ ./credit-interest.py --plot --stocklike --interest 0.15 --interest_long
01 2005-03-22 23:59:59 SELL Size: -10 / Price: 3040.55
02 2005-04-11 23:59:59 BUY  Size: +10 / Price: 3088.47
...
...
34 2006-12-19 23:59:59 BUY  Size: +10 / Price: 4121.01

注意34次操作而不是35。似乎有些地方可能出了问题,但是……没有……

收取的利息会稍微减少现金储备,最终导致最后一个订单无法执行,因为现金不足

多头操作中去除利息费用(即使对于ETF来说并非真实)将使系统能够结束:

$ ./credit-interest.py --plot --stocklike --interest 0.15
01 2005-03-22 23:59:59 SELL Size: -10 / Price: 3040.55
02 2005-04-11 23:59:59 BUY  Size: +10 / Price: 3088.47
...
...
34 2006-12-19 23:59:59 BUY  Size: +10 / Price: 4121.01
35 2006-12-19 23:59:59 BUY  Size: +10 / Price: 4121.01

回到业务,直到第35次操作。

与原始数据快速比较显示,最终现金从7490(不计利息)变为5418(仅对空头操作应用利息)

结论

这种新功能允许更真实地模拟回测场景,以尝试实现梦想:一个盈利系统

示例用法

$ ./credit-interest.py --help
usage: credit-interest.py [-h] [--data DATA] [--fromdate FROMDATE]
                          [--todate TODATE] [--cash CASH] [--period1 PERIOD1]
                          [--period2 PERIOD2] [--interest INTEREST]
                          [--interest_long] [--long | --short] [--no-exit]
                          [--stocklike] [--margin MARGIN] [--mult MULT]
                          [--stake STAKE] [--plot [kwargs]]
Sample for Slippage
optional arguments:
  -h, --help            show this help message and exit
  --data DATA           Specific data to be read in (default:
                        ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default: None)
  --todate TODATE       Ending date in YYYY-MM-DD format (default: None)
  --cash CASH           Cash to start with (default: 50000)
  --period1 PERIOD1     Fast moving average period (default: 10)
  --period2 PERIOD2     Slow moving average period (default: 30)
  --interest INTEREST   Activate credit interest rate (default: 0.0)
  --interest_long       Credit interest rate for long positions (default:
                        False)
  --long                Do a long only strategy (default: False)
  --short               Do a long only strategy (default: False)
  --no-exit             The 1st taken position will not be exited (default:
                        False)
  --stocklike           Consider the asset to be stocklike (default: False)
  --margin MARGIN       Margin for future like instruments (default: 0.0)
  --mult MULT           Multiplier for future like instruments (default: 1.0)
  --stake STAKE         Stake to apply (default: 10)
  --plot [kwargs], -p [kwargs]
                        Plot the read data applying any kwargs passed For
                        example: --plot style="candle" (to plot candles)
                        (default: None)

示例代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import collections
import datetime
import itertools
import backtrader as bt
class SMACrossOver(bt.Signal):
    params = (('p1', 10), ('p2', 30),)
    def __init__(self):
        sma1 = bt.indicators.SMA(period=self.p.p1)
        sma2 = bt.indicators.SMA(period=self.p.p2)
        self.lines.signal = bt.indicators.CrossOver(sma1, sma2)
class NoExit(bt.Signal):
    def next(self):
        self.lines.signal[0] = 0.0
class St(bt.SignalStrategy):
    opcounter = itertools.count(1)
    def notify_order(self, order):
        if order.status == bt.Order.Completed:
            t = ''
            t += '{:02d}'.format(next(self.opcounter))
            t += ' {}'.format(order.data.datetime.datetime())
            t += ' BUY ' * order.isbuy() or ' SELL'
            t += ' Size: {:+d} / Price: {:.2f}'
            print(t.format(order.executed.size, order.executed.price))
def runstrat(args=None):
    args = parse_args(args)
    cerebro = bt.Cerebro()
    cerebro.broker.set_cash(args.cash)
    dkwargs = dict()
    if args.fromdate is not None:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dkwargs['fromdate'] = fromdate
    if args.todate is not None:
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dkwargs['todate'] = todate
    # if dataset is None, args.data has been given
    data = bt.feeds.BacktraderCSVData(dataname=args.data, **dkwargs)
    cerebro.adddata(data)
    cerebro.signal_strategy(St)
    cerebro.addsizer(bt.sizers.FixedSize, stake=args.stake)
    sigtype = bt.signal.SIGNAL_LONGSHORT
    if args.long:
        sigtype = bt.signal.SIGNAL_LONG
    elif args.short:
        sigtype = bt.signal.SIGNAL_SHORT
    cerebro.add_signal(sigtype,
                       SMACrossOver, p1=args.period1, p2=args.period2)
    if args.no_exit:
        if args.long:
            cerebro.add_signal(bt.signal.SIGNAL_LONGEXIT, NoExit)
        elif args.short:
            cerebro.add_signal(bt.signal.SIGNAL_SHORTEXIT, NoExit)
    comminfo = bt.CommissionInfo(
        mult=args.mult,
        margin=args.margin,
        stocklike=args.stocklike,
        interest=args.interest,
        interest_long=args.interest_long)
    if True:
        cerebro.broker.addcommissioninfo(comminfo)
    cerebro.run()
    if args.plot:
        pkwargs = dict(style='bar')
        if args.plot is not True:  # evals to True but is not True
            npkwargs = eval('dict(' + args.plot + ')')  # args were passed
            pkwargs.update(npkwargs)
        cerebro.plot(**pkwargs)
def parse_args(pargs=None):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for Slippage')
    parser.add_argument('--data', required=False,
                        default='../../datas/2005-2006-day-001.txt',
                        help='Specific data to be read in')
    parser.add_argument('--fromdate', required=False, default=None,
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--todate', required=False, default=None,
                        help='Ending date in YYYY-MM-DD format')
    parser.add_argument('--cash', required=False, action='store',
                        type=float, default=50000,
                        help=('Cash to start with'))
    parser.add_argument('--period1', required=False, action='store',
                        type=int, default=10,
                        help=('Fast moving average period'))
    parser.add_argument('--period2', required=False, action='store',
                        type=int, default=30,
                        help=('Slow moving average period'))
    parser.add_argument('--interest', required=False, action='store',
                        default=0.0, type=float,
                        help=('Activate credit interest rate'))
    parser.add_argument('--interest_long', required=False, action='store_true',
                        help=('Credit interest rate for long positions'))
    pgroup = parser.add_mutually_exclusive_group()
    pgroup.add_argument('--long', required=False, action='store_true',
                        help=('Do a long only strategy'))
    pgroup.add_argument('--short', required=False, action='store_true',
                        help=('Do a long only strategy'))
    parser.add_argument('--no-exit', required=False, action='store_true',
                        help=('The 1st taken position will not be exited'))
    parser.add_argument('--stocklike', required=False, action='store_true',
                        help=('Consider the asset to be stocklike'))
    parser.add_argument('--margin', required=False, action='store',
                        default=0.0, type=float,
                        help=('Margin for future like instruments'))
    parser.add_argument('--mult', required=False, action='store',
                        default=1.0, type=float,
                        help=('Multiplier for future like instruments'))
    parser.add_argument('--stake', required=False, action='store',
                        default=10, type=int,
                        help=('Stake to apply'))
    # Plot options
    parser.add_argument('--plot', '-p', nargs='?', required=False,
                        metavar='kwargs', const=True,
                        help=('Plot the read data applying any kwargs passed\n'
                              '\n'
                              'For example:\n'
                              '\n'
                              '  --plot style="candle" (to plot candles)\n'))
    if pargs is not None:
        return parser.parse_args(pargs)
    return parser.parse_args()
if __name__ == '__main__':
    runstrat()

迪克森移动平均线

原文:www.backtrader.com/blog/posts/2016-08-18-dickson-moving-average/dickson-moving-average/

下面的reddit帖子将这种平均线称为迪克森移动平均线,以其作者内森·迪克森reddit用户名)的名字命名。

在定期访问reddit Algotrading时,我发现了一篇关于一种试图模拟 Jurik Moving Average(又称JMA)的移动平均线的帖子

描述为EasyLanguage中的算法,我不得不询问种子值和ec的性质,最终导致了Ehlers零滞后指标

为了将迪克森移动平均线实现到backtrader中,并且考虑到对EhlersHull 移动平均线的依赖,这两者也被添加到了移动平均线的工具中。

总结一下,以下内容已添加到Release 1.8.7.96中:

  • Hull 移动平均线
  • 零滞后指标
  • 迪克森移动平均线

结果可以通过使用样本数据和btrun绘制图表来观察:

$ btrun --nostdstats \
    --format btcsv \
    --data ../../../backtrader/datas/2006-day-001.txt \
    --indicator :SMA \
    --indicator :EMA \
    --indicator :HMA \
    --indicator :ZeroLagIndicator \
    --indicator :DMA \
    --plot style=\'line\'

现在的问题在于让迪克森移动平均线产生利润……就像任何其他指标一样。

注意

注意Hull 移动平均线(又名HMA)开始比其他几个值晚几个值产生。这是因为它使用了移动平均延迟了初始产生。

通过比较显示DMA如何处于ZeroLagIndicatorHullMovingAverage之间的中间位置。后者的period=7迪克森移动平均线内部的默认值匹配:

$ btrun --nostdstats \
    --format btcsv \
    --data ../../../backtrader/datas/2006-day-001.txt \
    --indicator :HMA:period=7 \
    --indicator :ZeroLagIndicator \
    --indicator :DMA \
    --plot style=\'line\'

股票筛选

原文:www.backtrader.com/blog/posts/2016-08-15-stock-screening/stock-screening/

在寻找其他东西时,我在 StackOverlow 家族网站之一上看到了一个问题:Quantitative Finance,也就是 Quant StackExchange。问题是:

它被标记为 Python,所以值得看看 backtrader 是否能胜任这项任务。

分析器本身

这个问题似乎适合一个简单的分析器。虽然问题只想要那些高于移动平均线的股票,但我们会保留额外的信息,比如那些不符合条件的股票,以确保谷物确实被分离出来。

class Screener_SMA(bt.Analyzer):
    params = dict(period=10)
    def start(self):
        self.smas = {data: bt.indicators.SMA(data, period=self.p.period)
                     for data in self.datas}
    def stop(self):
        self.rets['over'] = list()
        self.rets['under'] = list()
        for data, sma in self.smas.items():
            node = data._name, data.close[0], sma[0]
            if data > sma:  # if data.close[0] > sma[0]
                self.rets['over'].append(node)
            else:
                self.rets['under'].append(node)

注意

当然,还需要 import backtrader as bt

这基本上解决了问题。对 Analyzer 的分析:

  • period 作为参数,以便有一个灵活的分析器
  • start 方法
    对系统中的每个 data 制作一个 Simple Moving AverageSMA)。
  • stop 方法
    查看哪个 data(如果没有其他指定,则为 close)高于其 sma,并将其存储在返回值(rets)的键 over 下的 list
    成员 retsanalyzers 中是标准的,是一个 collections.OrderedDict。由基类创建。
    将不符合条件的股票保留在 under 键下

现在的问题是:让分析器运行起来。

注意

我们假设代码已经放在一个名为 st-screener.py 的文件中

方法 1

backtrader 自从很早以前就包含了一个名为 btrun 的自动脚本运行,可以从 Python 模块加载策略、指标、分析器,解析参数,当然还可以绘图。

让我们来运行一下:

$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-07-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA --cerebro runonce=0 --writer --nostdstats
===============================================================================
Cerebro:
  -----------------------------------------------------------------------------
  - Datas:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data0:
      - Name: YHOO
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data1:
      - Name: IBM
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data2:
      - Name: NVDA
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data3:
      - Name: TSLA
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data4:
      - Name: ORCL
      - Timeframe: Days
      - Compression: 1
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data5:
      - Name: AAPL
      - Timeframe: Days
      - Compression: 1
  -----------------------------------------------------------------------------
  - Strategies:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Strategy:
      *************************************************************************
      - Params:
      *************************************************************************
      - Indicators:
        .......................................................................
        - SMA:
          - Lines: sma
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 10
      *************************************************************************
      - Observers:
      *************************************************************************
      - Analyzers:
        .......................................................................
        - Value:
          - Begin: 10000.0
          - End: 10000.0
        .......................................................................
        - Screener_SMA:
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 10
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Analysis:
            - over: ('ORCL', 41.09, 41.032), ('IBM', 161.95, 161.221), ('YHOO', 42.94, 39.629000000000005), ('AAPL', 108.18, 106.926), ('NVDA', 63.04, 58.327)
            - under: ('TSLA', 224.91, 228.423)

我们使用了一组众所周知的股票代码:

  • AAPL, IBM, NVDA, ORCL, TSLA, YHOO

唯一一个低于 10Simple Moving Average 的是 TSLA

让我们尝试一个 50 天的周期。是的,这也可以通过 btrun 控制。运行(输出缩短):

$ btrun --format yahoo --data YHOO --data IBM --data NVDA --data TSLA --data ORCL --data AAPL --fromdate 2016-05-15 --todate 2016-08-13 --analyzer st-screener:Screener_SMA:period=50 --cerebro runonce=0 --writer --nostdstats
===============================================================================
Cerebro:
  -----------------------------------------------------------------------------
  - Datas:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    - Data0:
...
...
...
        - Screener_SMA:
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Params:
            - period: 50
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          - Analysis:
            - over: ('ORCL', 41.09, 40.339), ('IBM', 161.95, 155.0356), ('YHOO', 42.94, 37.9648), ('TSLA', 224.91, 220.4784), ('AAPL', 108.18, 98.9782), ('NVDA', 63.04, 51.4746)
            - under:

注意如何在命令行中指定了 50 天的周期:

  • st-screener:Screener_SMA:period=50
    在上一次运行中,这是 st-screener:Screener_SMA,并且使用了代码中的默认 10

我们还需要调整 fromdate,以确保有足够的条形图用于计算 Simple Moving Averages

在这种情况下,所有股票的 50 天移动平均线都在上面。


BackTrader 中文文档(二十一)(4)https://developer.aliyun.com/article/1505420

相关文章
|
5天前
BackTrader 中文文档(二十一)(1)
BackTrader 中文文档(二十一)
11 0
|
5天前
|
索引
BackTrader 中文文档(二十一)(4)
BackTrader 中文文档(二十一)
16 0
|
5天前
BackTrader 中文文档(二十一)(2)
BackTrader 中文文档(二十一)
11 0
|
5天前
BackTrader 中文文档(十九)(2)
BackTrader 中文文档(十九)
11 0
|
5天前
BackTrader 中文文档(十九)(1)
BackTrader 中文文档(十九)
10 0
|
5天前
BackTrader 中文文档(十九)(3)
BackTrader 中文文档(十九)
10 0
|
5天前
BackTrader 中文文档(十九)(4)
BackTrader 中文文档(十九)
12 0
|
5天前
BackTrader 中文文档(二十二)(1)
BackTrader 中文文档(二十二)
11 0
|
5天前
|
存储 测试技术 Python
BackTrader 中文文档(二十二)(2)
BackTrader 中文文档(二十二)
14 0
|
5天前
|
存储 Python
BackTrader 中文文档(二十二)(3)
BackTrader 中文文档(二十二)
18 0