即使BT提供的内置指标数量已经很多,开发指标主要是定义输入、输出并以自然方式编写公式,还是希望使用TA-LIB。原因:
安装前提:
使用BT中已内置的任何指标一样简单。简单移动平均线的示例:
import backtrader as bt
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
self.sma = bt.indicators.SMA(self.data, period=self.p.period)
...
...
ta-lib示例:
import backtrader as bt
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
self.sma = bt.talib.SMA(self.data, timeperiod=self.p.period)
...
...
ta-lib指标的参数是由库本身定义的,而不是由bt定义的。在这种情况下,ta-lib中的SMA采用一个名为timeperiod的参数来定义操作window的大小。
对于需要多个输入参数的指标,例如随机指标:
import backtrader as bt
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
self.stoc = bt.talib.STOCH(self.data.high, self.data.low, self.data.close,
fastk_period=14, slowk_period=3, slowd_period=3)
...
...
Notice how high, low and close have been individually passed. One could always pass open instead of low (or any other data series) and experiment.
The ta-lib indicator documentation is automatically parsed and added to the backtrader docs. You may also check the ta-lib source code/docs. Or adittionally do:
注意最高价、最低价和收盘价是作为参数分别传递的。总是传递开盘价,而不是最低价(或任何其他数据系列)。
ta-lib指标文档被自动解析并添加到bt文档中。可以查看ta-lib源代码/文档:
print(bt.talib.SMA.doc)
输出:
SMA([input_arrays], [timeperiod=30])
Simple Moving Average (Overlap Studies)
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
文档说明信息:
要为bt.talib.STOCH指标选择特定的移动平均线,可通过backtrader.talib.MA_Type访问标准ta-lib MA_Type :
import backtrader as bt
print('SMA:', bt.talib.MA_Type.SMA)
print('T3:', bt.talib.MA_Type.T3)
结果:
SMA: 0
T3: 8
正如常规用法一样,绘制ta-lib指标并没有特别的操作。
注意:
输出蜡烛的指标(所有寻找烛台模式的指标)提供二进制输出:0或100。为了避免在图表中添加子图,有一个自动绘图转换功能,可以在模式被识别的时间点的数据上绘制子图。
bt给出的示例都是在命令行的方式,通过命令行不同的参数,实现不同功能。找到一个不用修改代码,直接在jupyter中运行的方法:
代码:
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015-2023 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
import backtrader.talib as tbl
class TALibStrategy(bt.Strategy):
#params = (('ind', 'sma'), ('doji', True),)
params = (('ind', 'sma'), ('doji', False),)
INDS = ['sma', 'ema', 'stoc', 'rsi', 'macd', 'bollinger', 'aroon',
'ultimate', 'trix', 'kama', 'adxr', 'dema', 'ppo', 'tema',
'roc', 'williamsr']
def __init__(self):
print(self.p.doji,self.p.ind)
if self.p.doji:
tbl.CDLDOJI(self.data.open, self.data.high,self.data.low, self.data.close)
if self.p.ind == 'sma':
tbl.SMA(self.data.close, timeperiod=25, plotname='TA_SMA')
bt.indicators.SMA(self.data, period=25)
elif self.p.ind == 'ema':
tbl.EMA(timeperiod=25, plotname='TA_SMA')
bt.indicators.EMA(period=25)
elif self.p.ind == 'stoc':
tbl.STOCH(self.data.high, self.data.low, self.data.close,
fastk_period=14, slowk_period=3, slowd_period=3,
plotname='TA_STOCH')
bt.indicators.Stochastic(self.data)
elif self.p.ind == 'macd':
tbl.MACD(self.data, plotname='TA_MACD')
bt.indicators.MACD(self.data)
bt.indicators.MACDHisto(self.data)
elif self.p.ind == 'bollinger':
tbl.BBANDS(self.data, timeperiod=25,
plotname='TA_BBANDS')
bt.indicators.BBANDS(self.data, period=25) #BollingerBands BBANDS
elif self.p.ind == 'rsi':
tbl.RSI(self.data, plotname='TA_RSI')
bt.indicators.RSI(self.data)
elif self.p.ind == 'aroon':
tbl.AROON(self.data.high, self.data.low, plotname='TA_AROON')
bt.indicators.AroonIndicator(self.data)
elif self.p.ind == 'ultimate':
tbl.ULTOSC(self.data.high, self.data.low, self.data.close,
plotname='TA_ULTOSC')
bt.indicators.UltimateOscillator(self.data)
elif self.p.ind == 'trix':
tbl.TRIX(self.data, timeperiod=25, plotname='TA_TRIX')
bt.indicators.Trix(self.data, period=25)
elif self.p.ind == 'adxr':
tbl.ADXR(self.data.high, self.data.low, self.data.close,
plotname='TA_ADXR')
bt.indicators.ADXR(self.data)
elif self.p.ind == 'kama':
tbl.KAMA(self.data, timeperiod=25, plotname='TA_KAMA')
bt.indicators.KAMA(self.data, period=25)
elif self.p.ind == 'dema':
tbl.DEMA(self.data, timeperiod=25, plotname='TA_DEMA')
bt.indicators.DEMA(self.data, period=25)
elif self.p.ind == 'ppo':
tbl.PPO(self.data, plotname='TA_PPO')
bt.indicators.PPO(self.data, _movav=bt.indicators.SMA)
elif self.p.ind == 'tema':
tbl.TEMA(self.data, timeperiod=25, plotname='TA_TEMA')
bt.indicators.TEMA(self.data, period=25)
elif self.p.ind == 'roc':
tbl.ROC(self.data, timeperiod=12, plotname='TA_ROC')
tbl.ROCP(self.data, timeperiod=12, plotname='TA_ROCP')
tbl.ROCR(self.data, timeperiod=12, plotname='TA_ROCR')
tbl.ROCR100(self.data, timeperiod=12, plotname='TA_ROCR100')
bt.indicators.ROC(self.data, period=12)
bt.indicators.Momentum(self.data, period=12)
bt.indicators.MomentumOscillator(self.data, period=12)
elif self.p.ind == 'williamsr':
tbl.WILLR(self.data.high, self.data.low, self.data.close,
plotname='TA_WILLR')
bt.indicators.WilliamsR(self.data)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
dkwargs = dict()
if args.fromdate:
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
dkwargs['fromdate'] = fromdate
if args.todate:
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
dkwargs['todate'] = todate
data0 = bt.feeds.YahooFinanceCSVData(dataname=args.data0, **dkwargs)
cerebro.adddata(data0)
cerebro.addstrategy(TALibStrategy, ind=args.ind, doji=not args.no_doji)
cerebro.run(runcone=not args.use_next, stdstats=False)
if args.plot:
pkwargs = dict(style='candle')
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)
cerebro.plot(iplot=False,**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Sample for sizer')
parser.add_argument('--data0', required=False,
default='./datas/yhoo-1996-2015.txt',
help='Data to be read in')
parser.add_argument('--fromdate', required=False,
default='2005-01-01',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', required=False,
default='2006-12-31',
help='Ending date in YYYY-MM-DD format')
parser.add_argument('--ind', required=False, action='store',
default=TALibStrategy.INDS[0],
choices=TALibStrategy.INDS,
help=('Which indicator pair to show together'))
parser.add_argument('--no-doji', required=False, action='store_true',
help=('Remove Doji CandleStick pattern checker'))
parser.add_argument('--use-next', required=False, action='store_true',
help=('Use next (step by step) '
'instead of once (batch)'))
# 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 (escape the quotes if needed):\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
修改部分:
cerebro.plot(iplot=False,**pkwargs)
%matplotlib inline
runstrat('--help'.split())
执行结果:
usage: ipykernel_launcher.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE]
[--ind {sma,ema,stoc,rsi,macd,bollinger,aroon,ultimate,trix,kama,adxr,dema,ppo,tema,roc,williamsr}]
[--no-doji] [--use-next] [--plot [kwargs]]
Sample for sizer
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to be read in (default:
./datas/yhoo-1996-2015.txt)
--fromdate FROMDATE Starting date in YYYY-MM-DD format (default:
2005-01-01)
--todate TODATE Ending date in YYYY-MM-DD format (default: 2006-12-31)
--ind {sma,ema,stoc,rsi,macd,bollinger,aroon,ultimate,trix,kama,adxr,dema,ppo,tema,roc,williamsr}
Which indicator pair to show together (default: sma)
--no-doji Remove Doji CandleStick pattern checker (default:
False)
--use-next Use next (step by step) instead of once (batch)
(default: False)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example (escape the quotes if needed): --plot
style="candle" (to plot candles) (default: None)
The following are plots comparing the outputs of some ta-lib indicators against the equivalent built-in indicators in backtrader. To consider:
ta-lib指标与bt中相应内置指标绘图对比,考虑:
第一个示例,因为它是唯一有差异的(在bt和ta所有样本的直接比较中):
bt做的选择例如从股票软件图表中选择一样
股票软件图表中的KAMA
需要一个初始值来开始计算,所以第一个KAMA只是一个简单的移动平均值
因此两者有所不同。此外:
ta-lib KAMA实现不允许为Kaufman定义的可伸缩常数的调整指定快速和慢速周期。
测试:
%matplotlib inline
runstrat('--plot --ind kama'.split())
测试:
%matplotlib inline
runstrat('--plot --ind sma'.split())
测试:
runstrat(‘–plot --ind ema’.split())
测试:
runstrat(‘–plot --ind stoc’.split())
测试:
runstrat(‘–plot --ind rsi’.split())
测试:
runstrat(‘–plot --ind macd’.split())
测试:
runstrat(‘–plot --ind bollinger’.split())
报错,花了一些时间找问题。
TypeError: Invalid parameter value for nbdevup (expected float, got int)
源代码:
bt.talib.BBANDS(self.data, timeperiod=25,
plotname='TA_BBANDS')
bt.indicators.BollingerBands(self.data, period=25)
修改为:
elif self.p.ind == 'bollinger':
tbl.BBANDS(self.data, timeperiod=25, nbdevup=2.0,nbdevdn=2.0, matype=0,plotname='TA_BBANDS')
bt.indicators.BBands(self.data, period=25) #nbdevup=2,nbdevdn=2, matype=0
源代码两处问题:
- 参数应该是float ,调整接口默认是int,所以报错。直接指定浮点数:nbdevup=2.0,nbdevdn=2.0 。
- bt.indicators.BBands 不是bt.indicators.BBANDS ,bt和ta两个的名字大小写不一样 。
注意:
ta-lib选择将下行线放在第一位,与backtrader内置指标相比,颜色是相反的。
测试:
runstrat(‘–plot --ind aroon’.split())
测试:
runstrat(‘–plot --ind ultimate’.split())
测试:
runstrat(‘–plot --ind trix’.split())
测试:
runstrat(‘–plot --ind adxr’.split())
测试:
runstrat(‘–plot --ind dema’.split())
测试:
runstrat(‘–plot --ind tema’.split())
backtrader不仅提供了ppo线,还提供传统的macd方法。
测试:
runstrat(‘–plot --ind ppo’.split())
测试:
runstrat(‘–plot --ind williamsr’.split())
所有指标显示具有完全相同的形状,但跟踪动量或变化率有几种定义
测试:
runstrat(‘–plot --ind roc’.split())
ind = []
tal = []
for i in dir(bt.indicators):
if i[:1] != '_' :
ind.append (i)
for i in dir(bt.talib) :
if i[:1] != '_' :
tal.append (i)
print(len(ind)) # 410
print(len(tal)) # 181
tal_notin_ind = []
tal_in_ind = []
for i in tal :
if i in ind :
#index = ind.index(i)
tal_in_ind.append(i)
else :
#print(i,' not in ind.')
tal_notin_ind.append(i)
print('talib in bt indicator:')
print(tal_in_ind)
print('talib not in bt indicator:')
print(tal_notin_ind)
输出结果:
bt indicator 有410属性方法
talib 只有181个属性方法
410
181
talib in bt indicator:
['ADX', 'ADXR', 'APO', 'ATR', 'CCI', 'DEMA', 'EMA', 'KAMA', 'MACD', 'PPO', 'ROC', 'RSI', 'SMA', 'TEMA', 'TRIX', 'WMA', 'absolute_import', 'bt', 'division', 'print_function', 'sys', 'unicode_literals', 'with_metaclass']
talib not in bt indicator:
['ACOS', 'AD', 'ADD', 'ADOSC', 'AROON', 'AROONOSC', 'ASIN', 'ATAN', 'AVGPRICE', 'BBANDS', 'BETA', 'BOP', 'CDL2CROWS', 'CDL3BLACKCROWS', 'CDL3INSIDE', 'CDL3LINESTRIKE', 'CDL3OUTSIDE', 'CDL3STARSINSOUTH', 'CDL3WHITESOLDIERS', 'CDLABANDONEDBABY', 'CDLADVANCEBLOCK', 'CDLBELTHOLD', 'CDLBREAKAWAY', 'CDLCLOSINGMARUBOZU', 'CDLCONCEALBABYSWALL', 'CDLCOUNTERATTACK', 'CDLDARKCLOUDCOVER', 'CDLDOJI', 'CDLDOJISTAR', 'CDLDRAGONFLYDOJI', 'CDLENGULFING', 'CDLEVENINGDOJISTAR', 'CDLEVENINGSTAR', 'CDLGAPSIDESIDEWHITE', 'CDLGRAVESTONEDOJI', 'CDLHAMMER', 'CDLHANGINGMAN', 'CDLHARAMI', 'CDLHARAMICROSS', 'CDLHIGHWAVE', 'CDLHIKKAKE', 'CDLHIKKAKEMOD', 'CDLHOMINGPIGEON', 'CDLIDENTICAL3CROWS', 'CDLINNECK', 'CDLINVERTEDHAMMER', 'CDLKICKING', 'CDLKICKINGBYLENGTH', 'CDLLADDERBOTTOM', 'CDLLONGLEGGEDDOJI', 'CDLLONGLINE', 'CDLMARUBOZU', 'CDLMATCHINGLOW', 'CDLMATHOLD', 'CDLMORNINGDOJISTAR', 'CDLMORNINGSTAR', 'CDLONNECK', 'CDLPIERCING', 'CDLRICKSHAWMAN', 'CDLRISEFALL3METHODS', 'CDLSEPARATINGLINES', 'CDLSHOOTINGSTAR', 'CDLSHORTLINE', 'CDLSPINNINGTOP', 'CDLSTALLEDPATTERN', 'CDLSTICKSANDWICH', 'CDLTAKURI', 'CDLTASUKIGAP', 'CDLTHRUSTING', 'CDLTRISTAR', 'CDLUNIQUE3RIVER', 'CDLUPSIDEGAP2CROWS', 'CDLXSIDEGAP3METHODS', 'CEIL', 'CMO', 'CORREL', 'COS', 'COSH', 'DIV', 'DX', 'EXP', 'FLOOR', 'FUNC_FLAGS_CANDLESTICK', 'FUNC_FLAGS_SAMESCALE', 'FUNC_FLAGS_UNSTABLE', 'HT_DCPERIOD', 'HT_DCPHASE', 'HT_PHASOR', 'HT_SINE', 'HT_TRENDLINE', 'HT_TRENDMODE', 'LINEARREG', 'LINEARREG_ANGLE', 'LINEARREG_INTERCEPT', 'LINEARREG_SLOPE', 'LN', 'LOG10', 'MA', 'MACDEXT', 'MACDFIX', 'MAMA', 'MAVP', 'MAX', 'MAXINDEX', 'MA_Type', 'MEDPRICE', 'MFI', 'MIDPOINT', 'MIDPRICE', 'MIN', 'MININDEX', 'MINMAX', 'MINMAXINDEX', 'MINUS_DI', 'MINUS_DM', 'MOM', 'MULT', 'NATR', 'OBV', 'OUT_FLAGS_DASH', 'OUT_FLAGS_DOTTED', 'OUT_FLAGS_HISTO', 'OUT_FLAGS_LINE', 'OUT_FLAGS_LOWER', 'OUT_FLAGS_UPPER', 'PLUS_DI', 'PLUS_DM', 'ROCP', 'ROCR', 'ROCR100', 'R_TA_FUNC_FLAGS', 'R_TA_OUTPUT_FLAGS', 'SAR', 'SAREXT', 'SIN', 'SINH', 'SQRT', 'STDDEV', 'STOCH', 'STOCHF', 'STOCHRSI', 'SUB', 'SUM', 'T3', 'TAN', 'TANH', 'TRANGE', 'TRIMA', 'TSF', 'TYPPRICE', 'ULTOSC', 'VAR', 'WCLPRICE', 'WILLR', 'np', 'tafunc', 'tafunctions', 'talib']
两者名称完全相同的属性方法:
['ADX', 'ADXR', 'APO', 'ATR', 'CCI', 'DEMA', 'EMA', 'KAMA', 'MACD', 'PPO', 'ROC', 'RSI', 'SMA', 'TEMA', 'TRIX', 'WMA', 'absolute_import', 'bt', 'division', 'print_function', 'sys', 'unicode_literals', 'with_metaclass']