最后,似乎已经付出了开发 backtrader是值得的。
在观察 last 周的欧洲市场时,似乎世界末日了,一位朋友问我是否可以看看我们图表包中的数据,看看与以前类似情况相比,下跌幅度如何。
当然可以,但我说我可以做的不仅仅是查看图表,因为我可以快速:
-
创建一个快速
LegDown
指示器来测量跌落的范围。它也可能被命名为HighLowRange
或HiLoRange
。幸运的是,如果这被认为是必要的,可以通过以下方式解决alias
-
创建一个
LegDownAnalyzer
将收集结果并对其进行排序的
这导致了一个额外的请求:
-
未来5天,10天,15天,20天跌后的复苏(交易...
通过一个
LegUp
指针解决,该指针将值写回以与相应的“LegDown”对齐
工作很快完成(在我的空闲时间内),并与请求者分享了结果。但。。。作为我看到的唯一问题:
-
自动化方面的改进
bt-run.py
-
多种策略/observers/analyzers ,具有分离的kwargs
-
将指针直接注入策略,每个指针都有 kwargs
-
单一情节论证也接受瓦格斯
-
-
API 中的
Analyzer
改进,使结果具有自动 打印 功能(作为dict
类似 -的实例返回)并具有直接data
访问别名
尽管如此:
-
由于我编写的实现组合,出现了一个晦涩的错误,通过混合声明和附加使用来对齐
LegDown
和LegUp
值next
引入该错误是为了简化单个数据与多个
Lines
数据的传递,以便Indicators
可以作为单个数据对每个 lines 进行操作
后者将我推入:
-
添加一个与
LineDelay
“展望”“未来”相反的背景对象这实际上意味着实际值被写入过去的数组位置
一旦上述所有问题都到位,就该重新测试上述请求带来的(小?)挑战可以更容易,更快地(在实现时间内)解决得有多好。
最后,从1998年到今天,Eurostoxx 50 Future的运行和结果:
bt-run.py \ --csvformat vchartcsv \ --data ../datas/sample/1998-2015-estx50-vchart.txt \ --analyzer legdownup \ --pranalyzer \ --nostdstats \ --plot ==================== == Analyzers ==================== ########## legdownupanalyzer ########## Date,LegDown,LegUp_5,LegUp_10,LegUp_15,LegUp_20 2008-10-10,901.0,331.0,69.0,336.0,335.0 2001-09-11,889.0,145.0,111.0,239.0,376.0 2008-01-22,844.0,328.0,360.0,302.0,344.0 2001-09-21,813.0,572.0,696.0,816.0,731.0 2002-07-24,799.0,515.0,384.0,373.0,572.0 2008-01-23,789.0,345.0,256.0,319.0,290.0 2001-09-17,769.0,116.0,339.0,405.0,522.0 2008-10-09,768.0,102.0,0.0,120.0,208.0 2001-09-12,764.0,137.0,126.0,169.0,400.0 2002-07-23,759.0,331.0,183.0,285.0,421.0 2008-10-16,758.0,102.0,222.0,310.0,201.0 2008-10-17,740.0,-48.0,219.0,218.0,116.0 2015-08-24,731.0,nan,nan,nan,nan 2002-07-22,729.0,292.0,62.0,262.0,368.0 ... ... ... 2001-10-05,-364.0,228.0,143.0,286.0,230.0 1999-01-04,-370.0,219.0,99.0,-7.0,191.0 2000-03-06,-382.0,-60.0,-127.0,-39.0,-161.0 2000-02-14,-393.0,-92.0,90.0,340.0,230.0 2000-02-09,-400.0,-22.0,-46.0,96.0,270.0 1999-01-05,-438.0,3.0,5.0,-107.0,5.0 1999-01-07,-446.0,-196.0,-6.0,-82.0,-50.0 1999-01-06,-536.0,-231.0,-42.0,-174.0,-129.0
2015年8月的回合排名第13位。显然,一个不常见的现象,尽管发生了更大的情况。
对于静态主义者和聪明的数学头脑来说,从指向上方的后续腿中该做什么比我多得多。
有关实现的详细信息(请参阅末尾的整个模块代码):LegUpDownAnalyzer
-
它像其他对象一
__init__
样创建指针:Strategies
,Indicators
通常是通常的嫌疑人这些指针会自动注册到分析器所附加到的策略中
-
就像策略一样,
Analyzer
它有self.datas
(一个数据数字)和别名:self.data
,self.data0
,self.data1
... -
再次像策略:
nexstart
和stop
钩子(指针中不存在这些钩子)在这种情况下,用于:
-
nextstart
:记录策略的初始起点 -
stop
:因为事情已经完成而进行最终计算
-
-
注意:其他方法,如
start
,next
prenext
在这种情况下不需要 -
该
LegDownUpAnalyzer
方法print
已被覆盖,不再调用该pprint
方法,而是创建计算的CSV打印输出
经过多次交谈,由于我们加入了--plot
混合...图表。
最后是由legupdown
加载的 bt-run
模块。
from __future__ import (absolute_import, division, print_function, unicode_literals) import itertools import operator import six from six.moves import map, xrange, zip import backtrader as bt import backtrader.indicators as btind from backtrader.utils import OrderedDict class LegDown(bt.Indicator): ''' Calculates what the current legdown has been using: - Current low - High from ``period`` bars ago ''' lines = ('legdown',) params = (('period', 10),) def __init__(self): self.lines.legdown = self.data.high(-self.p.period) - self.data.low class LegUp(bt.Indicator): ''' Calculates what the current legup has been using: - Current high - Low from ``period`` bars ago If param ``writeback`` is True the value will be written backwards ``period`` bars ago ''' lines = ('legup',) params = (('period', 10), ('writeback', True),) def __init__(self): self.lu = self.data.high - self.data.low(-self.p.period) self.lines.legup = self.lu(self.p.period * self.p.writeback) class LegDownUpAnalyzer(bt.Analyzer): params = ( # If created indicators have to be plotteda along the data ('plotind', True), # period to consider for a legdown ('ldown', 10), # periods for the following legups after a legdown ('lups', [5, 10, 15, 20]), # How to sort: date-asc, date-desc, legdown-asc, legdown-desc ('sort', 'legdown-desc'), ) sort_options = ['date-asc', 'date-des', 'legdown-desc', 'legdown-asc'] def __init__(self): # Create the legdown indicator self.ldown = LegDown(self.data, period=self.p.ldown) self.ldown.plotinfo.plot = self.p.plotind # Create the legup indicators indicator - writeback is not touched # so the values will be written back the selected period and therefore # be aligned with the end of the legdown self.lups = list() for lup in self.p.lups: legup = LegUp(self.data, period=lup) legup.plotinfo.plot = self.p.plotind self.lups.append(legup) def nextstart(self): self.start = len(self.data) - 1 def stop(self): # Calculate start and ending points with values start = self.start end = len(self.data) size = end - start # Prepare dates (key in the returned dictionary) dtnumslice = self.strategy.data.datetime.getzero(start, size) dtslice = map(lambda x: bt.num2date(x).date(), dtnumslice) keys = dtslice # Prepare the values, a list for each key item # leg down ldown = self.ldown.legdown.getzero(start, size) # as many legs up as requested lups = [up.legup.getzero(start, size) for up in self.lups] # put legs down/up together and interleave (zip) vals = [ldown] + lups zvals = zip(*vals) # Prepare sorting options if self.p.sort == 'date-asc': reverse, item = False, 0 elif self.p.sort == 'date-desc': reverse, item = True, 0 elif self.p.sort == 'legdown-asc': reverse, item = False, 1 elif self.p.sort == 'legdown-desc': reverse, item = True, 1 else: # Default ordering - date-asc reverse, item = False, 0 # Prepare a sorted array of 2-tuples keyvals_sorted = sorted(zip(keys, zvals), reverse=reverse, key=operator.itemgetter(item)) # Use it to build an ordereddict self.ret = OrderedDict(keyvals_sorted) def get_analysis(self): return self.ret def print(self, *args, **kwargs): # Overriden to change default behavior (call pprint) # provides a CSV printout of the legs down/up header_items = ['Date', 'LegDown'] header_items.extend(['LegUp_%d' % x for x in self.p.lups]) header_txt = ','.join(header_items) print(header_txt) for key, vals in six.iteritems(self.ret): keytxt = key.strftime('%Y-%m-%d') txt = ','.join(itertools.chain([keytxt], map(str, vals))) print(txt)