导入backtrader ,以及backtrader 的指示器、数据反馈的模块 。
import backtrader as bt
import backtrader.indicators as btind
import backtrader.feeds as btfeeds
看看btind模块下有什么方法和属性:
obj_str = ''
for i in dir(btind):
if i[:1] != '_' :
obj_str += i + ','
print(obj_str)
指示器中的指标函数很多,方法属性如下:
ADX,ADXR,AO,APO,ATR,AbsPriceOsc,AbsolutePriceOscillator,AccDeOsc,AccelerationDecelerationOscillator,Accum,AdaptiveMovingAverage,AdaptiveMovingAverageEnvelope,AdaptiveMovingAverageOsc,AdaptiveMovingAverageOscillator,All,AllN,And,Any,AnyN,ApplyN,ArithmeticMean,AroonDown,AroonIndicator,AroonOsc,AroonOscillator,AroonUp,AroonUpDown,AroonUpDownOsc,AroonUpDownOscillator,Average,AverageDirectionalMovementIndex,AverageDirectionalMovementIndexRating,AverageTrueRange,AverageWeighted,AwesomeOsc,AwesomeOscillator,BBands,BaseApplyN,BollingerBands,BollingerBandsPct,CCI,Cmp,CmpEx,CointN,CommodityChannelIndex,CrossDown,CrossOver,CrossUp,CumSum,CumulativeSum,DEMA,DEMAEnvelope,DEMAOsc,DEMAOscillator,DI,DM,DMA,DMAEnvelope,DMAOsc,DMAOscillator,DMI,DPO,DV2,DemarkPivotPoint,DetrendedPriceOscillator,DicksonMA,DicksonMAEnvelope,DicksonMAOsc,DicksonMAOscillator,DicksonMovingAverage,DicksonMovingAverageEnvelope,DicksonMovingAverageOsc,DicksonMovingAverageOscillator,DirectionalIndicator,DirectionalMovement,DirectionalMovementIndex,DivByZero,DivZeroByZero,DoubleExponentialMovingAverage,DoubleExponentialMovingAverageEnvelope,DoubleExponentialMovingAverageOsc,DoubleExponentialMovingAverageOscillator,DownDay,DownDayBool,DownMove,EC,ECEnvelope,ECOsc,ECOscillator,EMA,EMAEnvelope,EMAOsc,EMAOscillator,Envelope,EnvelopeMixIn,ErrorCorrecting,ErrorCorrectingEnvelope,ErrorCorrectingOsc,ErrorCorrectingOscillator,ExpSmoothing,ExpSmoothingDynamic,ExponentialMovingAverage,ExponentialMovingAverageEnvelope,ExponentialMovingAverageOsc,ExponentialMovingAverageOscillator,ExponentialSmoothing,ExponentialSmoothingDynamic,FibonacciPivotPoint,FindFirstIndex,FindFirstIndexHighest,FindFirstIndexLowest,FindLastIndex,FindLastIndexHighest,FindLastIndexLowest,HMA,HMAEnvelope,HMAOsc,HMAOscillator,HeikinAshi,Highest,HullMA,HullMAEnvelope,HullMAOsc,HullMAOscillator,HullMovingAverage,HullMovingAverageEnvelope,HullMovingAverageOsc,HullMovingAverageOscillator,Hurst,HurstExponent,Ichimoku,If,Indicator,KAMA,KAMAEnvelope,KAMAOsc,KAMAOscillator,KST,KnowSureThing,LAGF,LRSI,LaguerreFilter,LaguerreRSI,LineActions,List,Logic,Lowest,MACD,MACDHisto,MACDHistogram,MAXINT,Max,MaxN,Mean,MeanDev,MeanDeviation,MetaMovAvBase,Min,MinN,MinusDI,MinusDirectionalIndicator,ModifiedMovingAverage,ModifiedMovingAverageEnvelope,ModifiedMovingAverageOsc,ModifiedMovingAverageOscillator,Momentum,MomentumOsc,MomentumOscillator,MovAv,MovingAverage,MovingAverageAdaptive,MovingAverageAdaptiveEnvelope,MovingAverageAdaptiveOsc,MovingAverageAdaptiveOscillator,MovingAverageBase,MovingAverageDoubleExponential,MovingAverageDoubleExponentialEnvelope,MovingAverageDoubleExponentialOsc,MovingAverageDoubleExponentialOscillator,MovingAverageExponential,MovingAverageExponentialEnvelope,MovingAverageExponentialOsc,MovingAverageExponentialOscillator,MovingAverageSimple,MovingAverageSimpleEnvelope,MovingAverageSimpleOsc,MovingAverageSimpleOscillator,MovingAverageSmoothed,MovingAverageSmoothedEnvelope,MovingAverageSmoothedOsc,MovingAverageSmoothedOscillator,MovingAverageTripleExponential,MovingAverageTripleExponentialEnvelope,MovingAverageTripleExponentialOsc,MovingAverageTripleExponentialOscillator,MovingAverageWeighted,MovingAverageWeightedEnvelope,MovingAverageWeightedOsc,MovingAverageWeightedOscillator,MovingAverageWilder,MovingAverageWilderEnvelope,MovingAverageWilderOsc,MovingAverageWilderOscillator,MultiLogic,MultiLogicReduce,NZD,NonZeroDifference,OLS_BetaN,OLS_Slope_InterceptN,OLS_TransformationN,OperationN,Or,Oscillator,OscillatorMixIn,PGO,PPO,PPOShort,PSAR,ParabolicSAR,PctChange,PctRank,PercPriceOsc,PercPriceOscShort,PercentChange,PercentRank,PercentagePriceOscillator,PercentagePriceOscillatorShort,PeriodN,PivotPoint,PlusDI,PlusDirectionalIndicator,PrettyGoodOsc,PrettyGoodOscillator,PriceOsc,PriceOscillator,RMI,ROC,ROC100,RSI,RSI_Cutler,RSI_EMA,RSI_SMA,RSI_SMMA,RSI_Safe,RSI_Wilder,RateOfChange,RateOfChange100,Reduce,ReduceN,RelativeMomentumIndex,RelativeStrengthIndex,SMA,SMAEnvelope,SMAOsc,SMAOscillator,SMMA,SMMAEnvelope,SMMAOsc,SMMAOscillator,SimpleMovingAverage,SimpleMovingAverageEnvelope,SimpleMovingAverageOsc,SimpleMovingAverageOscillator,SmoothedMovingAverage,SmoothedMovingAverageEnvelope,SmoothedMovingAverageOsc,SmoothedMovingAverageOscillator,StandardDeviation,StdDev,Stochastic,StochasticFast,StochasticFull,StochasticSlow,Sum,SumN,TEMA,TEMAEnvelope,TEMAOsc,TEMAOscillator,TR,TRIX,TSI,TripleExponentialMovingAverage,TripleExponentialMovingAverageEnvelope,TripleExponentialMovingAverageOsc,TripleExponentialMovingAverageOscillator,Trix,TrixSignal,TrueHigh,TrueLow,TrueRange,TrueStrengthIndicator,UltimateOscillator,UpDay,UpDayBool,UpMove,Vortex,WMA,WMAEnvelope,WMAOsc,WMAOscillator,WeightedAverage,WeightedMovingAverage,WeightedMovingAverageEnvelope,WeightedMovingAverageOsc,WeightedMovingAverageOscillator,WilderMA,WilderMAEnvelope,WilderMAOsc,WilderMAOscillator,WilliamsAD,WilliamsR,ZLEMA,ZLEMAEnvelope,ZLEMAOsc,ZLEMAOscillator,ZLInd,ZLIndEnvelope,ZLIndOsc,ZLIndOscillator,ZLIndicator,ZLIndicatorEnvelope,ZLIndicatorOsc,ZLIndicatorOscillator,ZeroLagEma,ZeroLagEmaEnvelope,ZeroLagEmaOsc,ZeroLagEmaOscillator,ZeroLagExponentialMovingAverage,ZeroLagExponentialMovingAverageEnvelope,ZeroLagExponentialMovingAverageOsc,ZeroLagExponentialMovingAverageOscillator,ZeroLagIndicator,ZeroLagIndicatorEnvelope,ZeroLagIndicatorOsc,ZeroLagIndicatorOscillator,absolute_import,accdecoscillator,alias,aroon,atr,awesomeoscillator,basicops,bollinger,bt,cci,cmp,contrib,crossover,dema,deviation,directionalmove,division,dma,dpo,dv2,ema,envelope,functools,haD,haDelta,hadelta,heikinashi,hma,hurst,ichimoku,kama,kst,linename,lrsi,mabase,macd,map,math,module,momentum,movav,movname,newaliases,newcls,newclsdct,newclsdoc,newclsname,ols,operator,oscillator,percentchange,percentrank,pivotpoint,prettygoodoscillator,priceoscillator,print_function,psar,range,rmi,rsi,sma,smma,stochastic,suffix,sys,trix,tsi,ultimateoscillator,unicode_literals,williams,with_metaclass,wma,zlema,zlind,
也可以直接通过bt导入下面的模块feeds indicators
import backtrader as bt
thefeed = bt.feeds.OneOfTheFeeds(...)
theind = bt.indicators.SimpleMovingAverage(...)
所有的策略都基于数据,平台端用户不用考虑如何接收数据。
Data Feeds are automagically provided member variables to the strategy in the form of an array and shortcuts to the array positions
数据源是以数组的形式或者对数组位置快捷访问的方式提供给strategy(策略)作为成员变量使用的。
这句话需要好好理解。
数组的形式: self.datas[0].close
数组位置快捷访问:self.data0.close
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(self.datas[0], period=self.params.period)
print(sma)
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.dataclosetest = self.data0.close
print('-'* 20,'close','-' * 20 )
print(self.dataclose[0])
print(self.dataclosetest[0])
执行结果
sma 的数据类型backtrader.indicators.sma.SimpleMovingAverage
<backtrader.indicators.sma.SimpleMovingAverage object at 0x7f616bd7c820>
-------------------- close --------------------
133.01
133.01
Data Feeds get added to the platform and they will show up inside the strategy in the sequential order in which they were added to the system.
SQL语句按日期排序,不论是正序还是逆序desc ,到BackTrader中,都是按时间倒序排列,[0]是最后的日期。
self.datas数组项可以通过自动成员变量直接访问:
self.data targets self.datas[0]
self.dataX targets self.datas[X]
下面好好测试一下BackTrader的数据访问,数据之间的关系。
#<class 'backtrader.linebuffer.LineBuffer'>
print(type(cerebro.datas[0].close))
#<class 'backtrader.feeds.pandafeed.PandasData'>
print(type(cerebro.datas[0]))
#<class 'list'>
print(type(cerebro.datas))
# ('close', 'low', 'high', 'open', 'volume', 'openinterest', 'datetime')
print(cerebro.datas[0].getlinealiases())
结果如下:
<class 'backtrader.linebuffer.LineBuffer'>
<class 'backtrader.feeds.pandafeed.PandasData'>
<class 'list'>
('close', 'low', 'high', 'open', 'volume', 'openinterest', 'datetime')
说明:
print(cerebro.datas[0].datetime[0])
print(pd.to_datetime(cerebro.datas[0].datetime[0],unit='s'))
print(bt.num2date(cerebro.datas[0].datetime[0]))
结果如下:
737424.0
1970-01-09 12:50:24
2019-12-31 00:00:00
直接访问datetime列 ,是浮点数。
开始用pd.to_datetime 函数,转换的时间是1970年,迷惑很长时间。
重要:必须用自带的函数转换时间 bt.num2date()!!!
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(period=self.params.period)
...
self.data has been completely removed from the invocation of SimpleMovingAverage. If this is done, the indicator (in this case the SimpleMovingAverage) receives the first data of the object in which is being created (the Strategy), which is self.data (aka self.data0 or self.datas[0])
默认使用的self是什么?
如果只有一个数据源,cerebro只载入一个股票数据,不用显式指定,系统会缺省使用self.datas[0],self.data=self.data0=self.datas[0] ,也就是第一个加入的数据源 。所以说self.data 就没有显式出现在调用SMA指示器 。
如果有多个载入数据,还是注明好,清晰可读。
class MyStrategy(bt.Strategy):
#定义策略全局参数
params = dict(period1=20, period2=25, period3=10, period4)
def __init__(self):
# 使用SMA指示器载入datas[0],使用参数1
sma1 = btind.SimpleMovingAverage(self.datas[0], period=self.p.period1)
# This 2nd Moving Average operates using sma1 as "data"
# 使用第一个SMA指示器数据再次作为SMA的数据载入,使用参数2
sma2 = btind.SimpleMovingAverage(sma1, period=self.p.period2)
# New data created via arithmetic operation
# 随意的计算
something = sma2 - sma1 + self.data.close
# This 3rd Moving Average operates using something as "data"
# 随意计算的结果作为第三次SMA数据载入,使用参数3
sma3 = btind.SimpleMovingAverage(something, period=self.p.period3)
# Comparison operators work too ...
# 比较后取大值 ,有点疑问 ?
greater = sma3 > sma1
# Pointless Moving Average of True/False values but valid
# This 4th Moving Average operates using greater as "data"
# 比较后结果第四次载入SMA指示器,使用参数4
sma3 = btind.SimpleMovingAverage(greater, period=self.p.period4)
...
总而言之,所有的数据转换变化后,都可以作为数据载入,再次进行运算。
在backtrader中,所有的类都按照如下方法来使用参数:
1、声明一个带有缺省值的参数作为类的一个属性(元组或者字典结构)。
2、关键字类型参数(kwargs)会扫描匹配的参数,将值赋值给对应的参数,完成后从kwargs删除。
3、这些参数都可以在类实例中通过访问成员变量self.params(可以简写为self.p)来使用。
使用元组 tuple
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
使用字典dict
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
从使用用户(通常是strategy)的角度来说,就是包括一个或多个line,这些line是一系列的数据,在图中可以形成一条线(line)。line是数组,不是pd.series ,没有index 。
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
def next(self):
if self.movav.lines.sma[0] > self.data.lines.close[0]:
print(round(self.movav.lines.sma[0],2),self.data.lines.close[0],'Simple Moving Average is greater than the closing price')
执行结果:
83.34 74.4 Simple Moving Average is greater than the closing price
83.16 75.1 Simple Moving Average is greater than the closing price
83.01 76.6 Simple Moving Average is greater than the closing price
82.92 80.1 Simple Moving Average is greater than the closing price
82.82 79.64 Simple Moving Average is greater than the closing price
82.69 78.52 Simple Moving Average is greater than the closing price
82.36 76.1 Simple Moving Average is greater than the closing price
81.87 74.28 Simple Moving Average is greater than the closing price
... ...
self.movav:这个是一个SimpleMovingAverage的指标(indicator),本身就包含一个具有lines属性的sma。这里特殊注意一下,计算SimpleMovingAverage使用的self.data,没有指定具体Line的话,缺省用的是close价进行计算。
简单的方法访问lines:
xxx.lines 可以简化为 xxx.l
xxx.lines.name可以简化为xxx.lines_name
一些复杂的对象也可以通过如下方法访问:
self.data_name 等于 self.data.lines.name
如果有多个变量的话,也可以self.data1_name 替代self.data1.lines.name
此外,Line的名字也可以通过如下方式访问:
self.data.close and self.movav.sma
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
def next(self):
# 数据集0 收盘价在110和120
if (self.datas[0].close[0] > 110.0) & (self.datas[0].close[0] < 120.0):
print(bt.num2date(self.datas[0].datetime[0]),'self.datas[0].close[0] > 110.0')
# 数据集1 收盘价在110和120
if self.datas[1].close[0] > 9.0:
print(bt.num2date(self.datas[1].datetime[0]),'self.datas[1].close[0] > 9.0')
# 数据集SMA 收盘价在88和90
if (self.movav.lines.sma[0] > 88) & (self.movav.sma[0] < 90) :
print(round(self.movav.lines.sma[0],2),'self.movav.lines.sma[0] > 88')
print(self.movav.getlinealiases())
#print(cerebro.datas[0].getlinealiases())
结果如下:
2018-04-18 00:00:00 self.datas[1].close[0] > 9.0
2018-04-24 00:00:00 self.datas[1].close[0] > 9.0
2018-04-25 00:00:00 self.datas[1].close[0] > 9.0
2018-04-26 00:00:00 self.datas[1].close[0] > 9.0
2019-04-09 00:00:00 self.datas[0].close[0] > 110.0
88.78 self.movav.lines.sma[0] > 88
('sma',)
89.64 self.movav.lines.sma[0] > 88
('sma',)
2019-06-20 00:00:00 self.datas[0].close[0] > 110.0
2019-06-21 00:00:00 self.datas[0].close[0] > 110.0
2019-06-24 00:00:00 self.datas[0].close[0] > 110.0
2019-06-25 00:00:00 self.datas[0].close[0] > 110.0
2019-06-26 00:00:00 self.datas[0].close[0] > 110.0
2019-06-27 00:00:00 self.datas[0].close[0] > 110.0
2019-06-28 00:00:00 self.datas[0].close[0] > 110.0
2019-07-24 00:00:00 self.datas[0].close[0] > 110.0
2019-08-01 00:00:00 self.datas[0].close[0] > 110.0
2019-08-02 00:00:00 self.datas[0].close[0] > 110.0
2019-08-05 00:00:00 self.datas[0].close[0] > 110.0
2019-08-07 00:00:00 self.datas[0].close[0] > 110.0
2019-08-09 00:00:00 self.datas[0].close[0] > 110.0
需要好好说明一下:
if (self.movav.lines.sma[0] > 88) & (self.movav.sma[0] < 90) :
两种方式引用
self.movav.lines.sma[0] = self.movav.sma[0]
cerebro载入两个股票数据。
特别注意:调用datas ,有s
self.datas[0].close[0]
self.datas[0].close[0]
self.datas[0].close[0]
print(bt.num2date(self.movav.datetime[0]) 无日期
只有一列
print(self.movav.getlinealiases())
('sma',)
未完待续!!!
data = btfeeds.BacktraderCSVData(dataname='mydata.csv')
...
class MyStrategy(bt.Strategy):
...
def next(self):
if self.data.close[0] > 30.0:
...
两个表达式等价
if self.data.close[0] > 30.0:
if self.data.lines.close[0] > 30.0:
Lines是随时变化的,run的时候,next不断改变Lines的长度,在数据载入,策略,指示器应用中,需要测量Lines的长度。
两个函数:len和buflen之间的区别:
class MyStrategy1(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.movav0 = btind.SimpleMovingAverage(self.data0, period=self.p.period)
self.movav1 = btind.SimpleMovingAverage(self.data1, period=self.p.period)
print('self.p.period:',self.p.period)
def next(self):
print('self.datas[0].lines.buflen()',self.datas[0].lines.buflen())
print('self.datas[1].buflen()',self.datas[1].buflen())
print('len(self.datas[0])',len(self.datas[0]))
print('len(self.datas[1])',len(self.datas[1]))
cerebro.addstrategy(MyStrategy1,period=30)
# Run over everything
cerebro.run()
结果如下:
self.p.period: 30
self.p.period: 30
self.datas[0].lines.buflen() 244
self.datas[1].buflen() 244
len(self.datas[0]) 30
len(self.datas[1]) 30
self.datas[0].lines.buflen() 244
self.datas[1].buflen() 244
len(self.datas[0]) 31
len(self.datas[1]) 31
... ...
len(self.datas[0]) 243
len(self.datas[1]) 243
self.datas[0].lines.buflen() 244
self.datas[1].buflen() 244
len(self.datas[0]) 244
len(self.datas[1]) 244
分析说明:
print('self.datas[0].lines.buflen()',self.datas[0].lines.buflen()) print('self.datas[1].buflen()',self.datas[1].buflen())
lines还有什么方法属性:
class MyStrategy2(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.movav0 = btind.SimpleMovingAverage(self.data0, period=self.p.period)
self.movav1 = btind.SimpleMovingAverage(self.data1, period=self.p.period)
print('self.p.period:',self.p.period)
obj_str = ''
for i in dir(self.datas[0].lines):
if i[:1] != '_' :
obj_str += i + ','
print(obj_str)
def next(self):
pass
cerebro.addstrategy(MyStrategy2,period=30)
# Run over everything
cerebro.run()
结果如下:
self.p.period: 30
advance,backwards,buflen,close,datetime,extend,extrasize,forward,fullsize,get,getlinealiases,high,home,itersize,lines,low,open,openinterest,reset,rewind,size,volume,
重点:
0指的是系统当前正在处理的数据,而不是第一个数据。
strategy类只会进行取值操作,而indicator只会进行赋值操作。
在backtrader中,-1指的是当前处理数据(索引为0)的上一个数据。
def next(self):
if self.data.close[0] > self.data.close[-1]:
print('Closing price is higher today')
以当前值0为基准,上一个值索引-1,上上一个值为-2,还可以继续-3,-4…
BackTrader的切片和Python的概念不同:
用Python的list切片从头到尾的切片,在BackTrader不能用。
myslice = self.my_sma[0:] # slice from the beginning til the end
myslice = self.my_sma[0:-1] # slice from the beginning til the end
按逆序也不行
myslice = cerebro.datas[0].close[-1:-3] # from last value backwards to the 3rd last value
myslice = cerebro.datas[0].close[-3:-1] # from last value backwards to the 3rd last value
BackTrader的切片用函数:
myslice = self.my_sma.get(ago=0, size=1) # default values shown
测试一下:
cerebro.datas[1].close.get(ago=0, size=3)
结果:
array('d', [5.82, 5.85, 5.78])
遍历处理日期:
for i in cerebro.datas[1].datetime.get(ago=0, size=3) :
print(bt.num2date(i))
结果:
2019-12-27 00:00:00
2019-12-30 00:00:00
2019-12-31 00:00:00
数组是支持Python的切片:
cerebro.datas[1].datetime.get(ago=0, size=5)[0:3]
结果:
array('d', [737418.0, 737419.0, 737420.0])
需要注意返回值的顺序:
最左的值对应离ago最远的值,最右的是ago索引对应的值。
例如如下是返回5最新的个值(不包括正在处理的值),通过下图理解一下:
文档上的有点小瑕疵
self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
定义变量应该是 self.sma
class MyStrategy4(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.sma = btind.SimpleMovingAverage(self.datas[1], period=self.p.period)
self.cmpval = self.datas[1].close(-1) > self.sma
def next(self):
if self.cmpval[0]:
print(self.cmpval[0],self.sma[0],self.datas[1].close[0],self.datas[1].close[-1])
cerebro.addstrategy(MyStrategy4)
# Run over everything
cerebro.run()
分析说明:
关键是close(-1) 是圆括号,不是取值的方括号!!!
对象类型是:<backtrader.linebuffer._LineDelay object at 0x7f616a25e1c0>
self.datas[1].close(-1)
重新简化,测试:
class MyStrategy5(bt.Strategy):
params = dict(period=20)
def __init__(self):
self.cmpval = self.datas[1].close(-1)
def next(self):
print(self.datas[1].close[0],self.cmpval[0])
cerebro.addstrategy(MyStrategy5)
# Run over everything
cerebro.run()
结果 ,第一列第一个 = 第二列第二个,以此类推,
5.12 5.03
5.49 5.12
5.79 5.49
5.79 5.79
5.8 5.79
5.84 5.8
应用场景:
耦合主要用于将时间窗口不同的两个line建立关系。比如:
不同时间窗口的数据源具有不同的长度,indcator在使用这些数据的时候会复制这个长度。
股票的日线数据,每年大约250个(bar,对应250个工作日)
股票的周线数据,每年大约52个(bar,对应52周)
原文:
The reader could imagine a date comparison taking place in the background to find out a day - week correspondence, but:
- Indicators are just mathematical formulas and have no datetime information
They know nothing about the environment, just that if the data provides enough values, a calculation can take place.
读者可以想象一个日期比较的场景,找出日和星期的通信 ,但是:
指示器可以调整数学公式,没有(不考虑)日期信息
读者对于场景一无所知,如能够提供足够的数据,就可以计算 。
测试一下效果:
class MyStrategy6(bt.Strategy):
params = dict(period=20)
def __init__(self):
# data0 是日线数据
self.sma0 = btind.SMA(self.data1.close, period=5) # 5 日线的平均
# data1 是周线数据
self.sma1 = btind.SMA(self.data1.close, period=5) # 5 周线的平均
self.couplesma = self.sma1()
self.buysig = self.sma0 > self.couplesma
#print(type(sma1())) # <class 'backtrader.metabase.LinesCoupler_14'>
#print(self.sma1.get(ago=0, size=5)) # <class 'backtrader.indicators.sma.SMA'>
def next(self):
print('sma1:',self.sma1.get(ago=0,size = len(self.sma1)))
print('self.couplesma:',self.couplesma.get(ago=0,size = len(self.sma1)))
if self.buysig[0] :
print(self.buysig[0],'日均线大于周均线!')
# 初始化一个空的cerebor
cerebro = declare_cerebar()
# 加入策略
cerebro.addstrategy(MyStrategy6)
# Run over everything
cerebro.run()
sma1通过加一个括号()将数据适配到每日的时间窗口
程序做了调整,说明如下:
#print(type(sma1())) # <class ‘backtrader.metabase.LinesCoupler_14’>
sma1()就是耦合,数据类型:<class 'backtrader.metabase.LinesCoupler> ,是一个新的数据类型 !
self.couplesma也应该是<class 'backtrader.metabase.LinesCoupler>
没有触发判断语句
按说明补齐长度,应该能够进行比较,有是1的值。
输出结果,报错,超出:IndexError: array index out of range
日线的bar远远大于周线的bar,做SMA ,都用5个周期做,效果一样,还是应该长度不一致。
改日再看看,是数据问题,还是没有理解 line耦合的概念
在Indicators(指标)和strategy(策略)的初始化阶段init函数,通过操作符创建对象 。
class MyStrategy7(bt.Strategy):
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=20)
close_over_sma = self.data.close > sma
sma_dist_to_high = self.data.high - sma
sma_dist_small = sma_dist_to_high < 3.5
# Unfortunately "and" cannot be overridden in Python being
# a language construct and not an operator and thus a
# function has to be provided by the platform to emulate it
sell_sig = bt.And(close_over_sma, sma_dist_small)
print('sell_sig',type(sell_sig))
print('close_over_sma',type(close_over_sma),'sma_dist_small',type(sma_dist_small))
cerebro = declare_cerebar()
# 加入策略
cerebro.addstrategy(MyStrategy7)
cerebro.run()
结果:
sell_sig <class 'backtrader.functions.And'>
close_over_sma <class 'backtrader.linebuffer.LinesOperation'> sma_dist_small <class 'backtrader.linebuffer.LinesOperation'>
还有<class ‘backtrader.functions.And’>数据类型!
if self.sma > 30.0: 比较的是self.sma[0] to 30.0 (第一个Line 的当前值)
if self.sma > self.data.close: 比较 self.sma[0] 和self.data.close[0]。
class MyStrategy7(bt.Strategy):
def __init__(self):
self.sma = sma = btind.SimpleMovingAverage(self.data0, period=20)
close_over_sma = self.data0.close > sma
self.sma_dist_to_high = self.data0.high - sma
sma_dist_small = self.sma_dist_to_high < 3.5
print(type(sma),type(close_over_sma))
print(type(self.sma_dist_to_high),type(self.data0.high))
# Unfortunately "and" cannot be overridden in Python being
# a language construct and not an operator and thus a
# function has to be provided by the platform to emulate it
self.sell_sig = bt.And(close_over_sma, sma_dist_small)
def next(self):
# Although this does not seem like an "operator" it actually is
# in the sense that the object is being tested for a True/False
# response
if self.sma > 30.0:
print('sma is greater than 30.0!',self.sma[0])
if self.sma > self.data.close:
print('sma is above the close price!',self.sma,self.data.close,self.data.close[0])
if self.sell_sig: # if sell_sig == True: would also be valid
print('sell sig is True!',self.sell_sig[0])
else:
print('sell sig is False!',self.sell_sig[0])
if self.sma_dist_to_high > 5.0:
print('distance from sma to hig is greater than 5.0!',self.sma_dist_to_high[0])
self.sma_dist_to_high = self.data0.high - sma
说明:
LineBuffer 类型 减 SimpleMovingAverage 类型 结果是 LinesOperation 类型,也是数值!
有点迷惑 ?!
self.sma_dist_to_high <class ‘backtrader.linebuffer.LinesOperation’>
self.data0.high <class ‘backtrader.linebuffer.LineBuffer’>
sma <class ‘backtrader.indicators.sma.SimpleMovingAverage’>
结果:
<class 'backtrader.indicators.sma.SimpleMovingAverage'> <class 'backtrader.linebuffer.LinesOperation'>
<class 'backtrader.linebuffer.LinesOperation'> <class 'backtrader.linebuffer.LineBuffer'>
sma is greater than 30.0! 52.5345
sell sig is False! 0.0
distance from sma to hig is greater than 5.0! 6.045499999999997
sma is greater than 30.0! 52.9015
sell sig is False! 0.0
... ...
如下操作符/函数以及对应重写的函数。
操作符:
逻辑控制:
函数:
操作符/函数针对迭代器运行。迭代器中的元素可以是常规的Python数值类型(int、float等),也可以是Lines的对象。
bt.And示例:
class MyStrategy(bt.Strategy):
def __init__(self):
sma1 = btind.SMA(self.data.close, period=15)
self.buysig = bt.And(sma1 > self.data.close, sma1 > self.data.high)
def next(self):
if self.buysig[0]:
pass # do something here
bt.If示例:
class MyStrategy(bt.Strategy):
def __init__(self):
sma1 = btind.SMA(self.data.close, period=15)
high_or_low = bt.If(sma1 > self.data.close, self.data.low, self.data.high)
sma2 = btind.SMA(high_or_low, period=15)