CCI on other indicator
-
Hey guys,
I'm trying to put a CCI on the +DI and -DI of an ADX indicator, and implement them in my strategy but I get an error with my code: "array out of range" here
line 17, in init
self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus[0], period=20)My code is the following
import backtrader as bt from datetime import datetime class firstStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): self.dataclose = self.datas[0].close self.order = None self.rsi = bt.indicators.RSI_SMA(self.data.close, period=14) self.ADX = bt.indicators.DirectionalMovementIndex(self.data, period=12) self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus[0], period=20) self.CCIminusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIminus[0], period=20) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enougth cash if order.status in [order.Completed]: if order.isbuy(): self.log( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): self.log('Close, %.2f' % self.dataclose[0]) if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... if self.rsi < 30 and self.CCIplusDI[-1] > 100 and self.CCIminusDI[-1] < 100: self.log('BUY CREATE, %.2f' % self.dataclose[0]) self.order = self.buy() else: if self.rsi > 70 and self.CCIplusDI[-1] < 100 and self.CCIminusDI[-1] > 100: self.log('SELL CREATE, %.2f' % self.dataclose[0]) self.order = self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() startcash = 10000 # Add a strategy cerebro.addstrategy(firstStrategy) # Create a Data Feed data = bt.feeds.YahooFinanceData(dataname='BNO', fromdate=datetime(2016, 1, 1), todate=datetime(2017, 11, 25)) # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(startcash) # Set the commission cerebro.broker.setcommission(commission=0.0005) cerebro.run() # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Get final portfolio Value portvalue = cerebro.broker.getvalue() pnl = portvalue - startcash # Print out the final result print('Final Portfolio Value: ${}'.format(portvalue)) print('P/L: ${}'.format(pnl)) # Finally plot the end results cerebro.plot()
-
I assume it should with no
[0]
in the_init
()':self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus, period=20) self.CCIminusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIminus, period=20)
but it should be indexing in the
next()
:if not self.position: # Not yet ... we MIGHT BUY if ... if self.rsi[whatever_index_you_need] < 30 and self.CCIplusDI[-1] > 100 and self.CCIminusDI[-1] < 100: self.log('BUY CREATE, %.2f' % self.dataclose[0]) self.order = self.buy() else: if self.rsi[whatever_index_you_need] > 70 and self.CCIplusDI[-1] < 100 and self.CCIminusDI[-1] > 100: self.log('SELL CREATE, %.2f' % self.dataclose[0]) self.order = self.sell()
-
@ab_trader Hey thanks for your answer
I still get errors
Traceback (most recent call last): File "C:/Users/mm/PycharmProjects/AlgoTrading/Algo09.py", line 97, in <module> cerebro.run() File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\cerebro.py", line 1127, in run runstrat = self.runstrategies(iterstrat) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\cerebro.py", line 1214, in runstrategies strat = stratcls(*sargs, **skwargs) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 88, in __call__ _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 78, in doinit _obj.__init__(*args, **kwargs) File "C:/Users/mm/PycharmProjects/AlgoTrading/Algo09.py", line 17, in __init__ self.CCIplusDI = bt.indicators.CommodityChannelIndex(self.ADX.DIplus, period=20) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\indicator.py", line 53, in __call__ return super(MetaIndicator, cls).__call__(*args, **kwargs) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 88, in __call__ _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\metabase.py", line 78, in doinit _obj.__init__(*args, **kwargs) File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\indicators\cci.py", line 62, in __init__ tp = (self.data.high + self.data.low + self.data.close) / 3.0 File "C:\Users\mm\AppData\Local\Programs\Python\Python36-32\lib\site-packages\backtrader\lineseries.py", line 461, in __getattr__ return getattr(self.lines, name) AttributeError: 'Lines_LineSeries_LineSeriesStub' object has no attribute 'high'
-
As I know
CCI
calculates typical price which requireshigh
,low
andclose
prices. You calculateCCI
onADX
indicator, which doesn't have values required. Probably this is a problem.You may need to re-write this indicator to be applicable in your case. The code is really simple - backtrader - CCI script
-
@Horizion said in CCI on other indicator:
I'm trying to put a CCI on the +DI and -DI of an ADX indicator,
The problem is really here: a commodity channel for 2 values and the code shows attempts at using 1 value
@ab_trader said in CCI on other indicator:
As I know CCI calculates typical price which requires high, low and close prices
Because as quoted here: 3 values are used to calculate the commodity channel
If there were no mismatch between 1, 2 and 3, one could easily foresee a very small custom indicator which wraps the
ADX
and copies the needed values into custom lineshigh
,low
andclose
, which can be fed into theCCI
-
@Paska-Houso @ab_trader Hey guys,
Thanks for your answers. I have to admit that I am a little lost, as I don't know much about Python. I was trying to recreate what I used on an other Charting website (Tradingview) which allowed me to put a CCI on the +DI and -DI of the ADX.
when you say "The problem is really here: a commodity channel for 2 values and the code shows attempts at using 1 value" what exactly do you mean ?
What I was trying to do is get two CCI's on both the +DI and -DI. So I don't understand why the code shows attempts at using 1 value.
Regarding the high, low and close: I don't know how to implement these, since the +DI has only one value, and same for the -DI...
I don't know what to do... And where to look
-
It's not a Python thing ... see
Typical Price
==pt
in the first formula.The calculation is based on averaging the
high
,low
andclose
as pointed out by @ab_trader, and the implementation in backtrader obviously followed that definition (i.e.: you need 3 components)Because the calculation is made later exclusively based on the averaged price, one could do it (as you try in your code) by passing a single value. But with the current implementation, passing a single data feed (or line) is obviously doomed to fail.
-
First
ADX
indicators need to be improved a bit, hence write new indicator (shownADXDIPlus
only):class ADXDIPlus3(bt.Indicator): lines = ('high', 'low', 'close') params = (('period', 20),) def __init__(self): self.ADX = bt.indicators.DirectionalMovementIndex(period=self.p.period) self.lines.high = self.ADX.DIplus self.lines.low = self.ADX.DIplus self.lines.close = self.ADX.DIplus
Then call this indicator in your strategy
__init__
:def __init__(self): self.ADXPlus3 = ADXDIPlus3(period=12) self.CCI_ADXPlus = bt.indicators.CommodityChannelIndex(self.ADXPlus3, period=20)
I didn't check the numbers, but the logic seems right.
ADXMinus
need to be treated the same way. -
linealias
as described in this blog post, could make things even simplerSomething along the lines of
class For_CCI_On_DIplus(bt.indicators.DirectionalMovementIndex) linealias = (('DIplus', 'high'), ('DIplus', 'low'), ('DIplus', 'close'),)
-
Thanks a LOT guys, amazing community here...
I'll try to implement your solutions as soon as I have access to my PC