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中,并且考虑到对Ehlers和Hull 移动平均线的依赖,这两者也被添加到了移动平均线的工具中。
总结一下,以下内容已添加到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如何处于ZeroLagIndicator和HullMovingAverage之间的中间位置。后者的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 Average(SMA
)。stop
方法
查看哪个 data(如果没有其他指定,则为close
)高于其 sma,并将其存储在返回值(rets
)的键over
下的 list 中
成员rets
在 analyzers 中是标准的,是一个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
唯一一个低于 10
天 Simple 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