最後,似乎已經付出了開發 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,nextprenext在這種情況下不需要 -
該
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)