For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Can't import a custom indicator from default folder.



  • Hi. I'm trying to write a strategy which uses a Stochastic RSI indicator which is not pre-installed in backtrader. I've created my own StochRSI indicator, placed it inside the backtrader/indicators/ folder, and edited the init.py in backtrader/indicators/ to also include the name of my custom indicator. I cannot, however, manage to import the indicator into my strategy successfully ("AttributeError: module 'backtrader.indicators' has no attribute 'StochasticRSI'"). Any help would be greatly appreciated.

    The strategy:

    #boilerplate
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import datetime  # For datetime objects
    import os.path  # To manage paths
    import sys  # To find out the script name (in argv[0])
    import backtrader as bt
    import backtrader.indicators as btind
    from backtrader.indicators.mabase import MovAv
    
    class ExtremeLongs(bt.Strategy):
        """
        Buy Logic:
            -No position is open on the data (one trade at a time)
            
            -Both Stochastic indicator lines are under 10 for last 3 candles
            
            -Candle under bottom the Bollinger bands
            
            -Last 4 candles have been red
            
            -Candle is green
            
            -After buying a target is set and stored as a variable based on Moving Average (9)
            
        Sell Logic
            -Target has been met
            
        """
        
        params = (
            #Stochastic RSI
            ('stoch_k_period', 3),
            ('stoch_d_period', 3),
            ('stoch_rsi_period', 14),
            ('stoch_period', 14),
            ('stoch_upperband', 90.0),
            ('stoch_lowerband', 10.0),
            ('take_profit', 0.04),
            ('stop_loss', 0.01),
            #Bollinger Bands
            ('bbands_period', 20),
            ('bbands_devfactor', 2.0),
            ('bbands_movav', MovAv.Simple)
            )
    
        def __init__(self): #intialising indicators
            
            #intitialise stochastic rsi
            self.stochrsi = btind.StochasticRSI(
                k_period=self.stoch_k_period,
                d_period=self.stoch_d_period,
                rsi_period=self.stoch_rsi_period,
                stoch_period=self.stoch_period,
                upperband=self.p.stoch_upperband,
                lowerband=self.p.stoch_lowerband)
            
            #initialise bollinger bands
            self.bbands = btind.BollingerBands(
                period=self.bbands_period,
                devfactor=self.bbands_devfactor,
                movav=self.bbands_movav)
            
    if __name__ == '__main__':
        
        #start Cerebro and add strategy
        cerebro = bt.Cerebro()
        cerebro.addstrategy(ExtremeLongs)
        
        #find data
        modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
        datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
        
        #intialise data
        data = bt.feeds.YahooFinanceCSVData(
            dataname=datapath,
            fromdate=datetime.datetime(2000, 1, 1),
            todate=datetime.datetime(2000, 12, 31),
            reverse=False)
        cerebro.adddata(data, "Oracle - Year 2000")
        
        #broker settings
        cerebro.broker.setcash(100000.0)
        
        #run cerebro
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
        cerebro.run()
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
        cerebro.plot(style='candle')
    

    The custom indicator:

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    from . import Indicator, MovAv, RelativeStrengthIndex, Highest, Lowest
    
    import backtrader as bt
    
    class StochasticRSI(Indicator):
    	"""
    	K - The time period to be used in calculating the %K. 3 is the default.
    	D - The time period to be used in calculating the %D. 3 is the default.
    	RSI Length - The time period to be used in calculating the RSI
    	Stochastic Length - The time period to be used in calculating the Stochastic
    
    	Formula:
    	%K = SMA(100 * (RSI(n) - RSI Lowest Low(n)) / (RSI HighestHigh(n) - RSI LowestLow(n)), smoothK)
    	%D = SMA(%K, periodD)
    
    	"""
    	alias = ('StochasticRSI')
    	lines = ('fastk', 'fastd',)
    
    	params = (
    		('k_period', 3),
    		('d_period', 3),
    		('rsi_period', 14),
    		('stoch_period', 14),
    		('movav', MovAv.Simple),
    		('rsi', RelativeStrengthIndex),
    		('upperband', 80.0),
    		('lowerband', 20.0),
    	)
    
    	plotlines = dict(percD=dict(_name='%D', ls='--'),
    	percK=dict(_name='%K'))
    
    	def _plotlabel(self):
    		plabels = [self.p.k_period, self.p.d_period, self.p.rsi_period, self.p.stoch_period]
    		plabels += [self.p.movav] * self.p.notdefault('movav')
    		return plabels
    
    	def _plotinit(self):
    		self.plotinfo.plotyhlines = [self.p.upperband, self.p.lowerband]
    
    	def __init__(self):
    		rsi = bt.indicators.RSI(period=self.p.rsi_period)
    		rsi_ll = bt.indicators.Lowest(rsi, period=self.p.rsi_period)
    		rsi_hh = bt.indicators.Highest(rsi, period=self.p.rsi_period)
    		stochrsi = (rsi - rsi_ll) / (rsi_hh - rsi_ll)
    
    		self.l.fastk = k = self.p.movav(100.0 * stochrsi, period=self.p.k_period)
    		self.l.fastd = self.p.movav(k, period=self.p.d_period)
    

    The init.py file in backtrader/indicators/ (with the custom stochasticrsi added underneath stochastic):

    #!/usr/bin/env python
    # -*- coding: utf-8; py-indent-offset:4 -*-
    ###############################################################################
    #
    # Copyright (C) 2015, 2016, 2017 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 <http://www.gnu.org/licenses/>.
    #
    ###############################################################################
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    from backtrader import Indicator
    from backtrader.functions import *
    
    # The modules below should/must define __all__ with the Indicator objects
    # of prepend an "_" (underscore) to private classes/variables
    
    from .basicops import *
    
    # base for moving averages
    from .mabase import *
    
    # moving averages (so envelope and oscillators can be auto-generated)
    from .sma import *
    from .ema import *
    from .smma import *
    from .wma import *
    from .dema import *
    from .kama import *
    from .zlema import *
    from .hma import *
    from .zlind import *
    from .dma import *
    
    # depends on moving averages
    from .deviation import *
    
    # depend on basicops, moving averages and deviations
    from .atr import *
    from .aroon import *
    from .bollinger import *
    from .cci import *
    from .crossover import *
    from .dpo import *
    from .directionalmove import *
    from .envelope import *
    from .heikinashi import *
    from .lrsi import *
    from .macd import *
    from .momentum import *
    from .oscillator import *
    from .percentchange import *
    from .percentrank import *
    from .pivotpoint import *
    from .prettygoodoscillator import *
    from .priceoscillator import *
    from .psar import *
    from .rsi import *
    from .stochastic import *
    from .stochasticrsi import *
    from .trix import *
    from .tsi import *
    from .ultimateoscillator import *
    from .williams import *
    from .rmi import *
    from .awesomeoscillator import *
    from .accdecoscillator import *
    
    
    from .dv2 import *  # depends on percentrank
    
    # Depends on Momentum
    from .kst import *
    
    from .ichimoku import *
    
    from .hurst import *
    from .ols import *
    from .hadelta import *
    


  • Did you check your path is importing your customized bt library and not another version on your system?



  • @Patrick-Mermelstein said in Can't import a custom indicator from default folder.:

    class StochasticRSI(Indicator):

    As a work around you could just put your custom indicator class in your strategy file



  • You an also put the indicator class in a local directory and import it.



  • I've run your code and it is working ok (up to some syntax errors in accessing strategy parameters directly and not through self.params). So your problem seems to be an additional backtrader package installed somewhere, such that you are importing a wrong backtrader package.

    It is easy to check - just print/debug the bt.__file__ var

    stochasticrsi.png



  • @vladisld sorry, I'm fairly new to backtrader. Could you expand on the syntax mistakes you mentioned about the parameters?



  • Basically you may access the strategy parameter either through self.p or self.params.

    Here the code that worked for me (just compare it with yours):

    # boilerplate
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import datetime  # For datetime objects
    import os.path  # To manage paths
    import sys  # To find out the script name (in argv[0])
    import backtrader as bt
    import backtrader.indicators as btind
    from backtrader.indicators.mabase import MovAv
    
    
    class ExtremeLongs(bt.Strategy):
        """
        Buy Logic:
            -No position is open on the data (one trade at a time)
    
            -Both Stochastic indicator lines are under 10 for last 3 candles
    
            -Candle under bottom the Bollinger bands
    
            -Last 4 candles have been red
    
            -Candle is green
    
            -After buying a target is set and stored as a variable based on Moving Average (9)
    
        Sell Logic
            -Target has been met
    
        """
    
        params = (
            # Stochastic RSI
            ('stoch_k_period', 3),
            ('stoch_d_period', 3),
            ('stoch_rsi_period', 14),
            ('stoch_period', 14),
            ('stoch_upperband', 90.0),
            ('stoch_lowerband', 10.0),
            ('take_profit', 0.04),
            ('stop_loss', 0.01),
            # Bollinger Bands
            ('bbands_period', 20),
            ('bbands_devfactor', 2.0),
            ('bbands_movav', MovAv.Simple)
        )
    
        def __init__(self):  # intialising indicators
    
            # intitialise stochastic rsi
            self.stochrsi = btind.StochasticRSI(
                k_period=self.p.stoch_k_period,
                d_period=self.p.stoch_d_period,
                rsi_period=self.p.stoch_rsi_period,
                stoch_period=self.p.stoch_period,
                upperband=self.p.stoch_upperband,
                lowerband=self.p.stoch_lowerband)
    
            # initialise bollinger bands
            self.bbands = btind.BollingerBands(
                period=self.p.bbands_period,
                devfactor=self.p.bbands_devfactor,
                movav=self.p.bbands_movav)
    
    
    if __name__ == '__main__':
        # start Cerebro and add strategy
        cerebro = bt.Cerebro()
        cerebro.addstrategy(ExtremeLongs)
    
        # find data
        modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
        datapath = os.path.join(modpath, 'w:/backtrader/datas/orcl-1995-2014.txt')
    
        # intialise data
        data = bt.feeds.YahooFinanceCSVData(
            dataname=datapath,
            fromdate=datetime.datetime(2000, 1, 1),
            todate=datetime.datetime(2000, 12, 31),
            reverse=False)
        cerebro.adddata(data, "Oracle - Year 2000")
    
        # broker settings
        cerebro.broker.setcash(100000.0)
    
        # run cerebro
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
        cerebro.run()
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
        cerebro.plot(style='candle')
    


  • Is this what you're looking for?

    self.stochRSI = bt.talib.STOCHRSI()
    

    Cause you have these: https://mrjbq7.github.io/ta-lib/funcs.html


Log in to reply
 

});