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

Multi timeframe indicator plotted twice and in wrong timeframe



  • Hello backtrader community. I just started using backtrader to test a H1 strategy that uses a D1 indicator. The indicator gives two values at the beginning of the day that are valid for all H1 candles until the end of the day. Two horizontal lines (in the H1 TF) similar to a pivot.

    The current implementation of this indicator does not works: it has these two problems:

    • both the H1 and the D1 charts are shown. I only want the H1 chart.
    • the indicator shows the right values in the D1 chart, but it is not plotted in the H1 chart (where I want it as a series of straight lines).

    Here is a screenshot of the problem

    0_1549956795059_mtf2.png

    See? No indicator in the H1 chart and a superfluous D1 chart.

    As you can see in the following code, at the top level I first load the H1 data and then the D1 data. This should make H1 the default data source, right?

    Then, in the strategy, I set up the indicator to use self.data1. This should link its calculations to the D1 timeframe, shouldn't it?

    Here is the code (simplified but working)

    #!/usr/bin/env python
    import backtrader as bt
    import backtrader.indicators as btind
    
    class MyMA(bt.Indicator):
        lines = ('ma',)
        params = dict(period=30)
    
        def __init__(self):
            diff = self.data.high - self.data.open
            self.l.ma = btind.SMA(diff, period=self.p.period)
    
    class Levels(bt.Indicator):
        lines = ('last_close', 'adj_close')
        params = dict(period=30)
    
        def __init__(self):
            ma = MyMA(period=self.p.period)
            self.l.last_close = self.data.close(-1)
            self.l.adj_close = self.data.close(-1) - ma(-1)
    
    class LevelsDisplay(bt.Strategy):
        params = dict(period=30)
    
        def __init__(self):
            # data1 = D1 Timeframe
            self.levels = Levels(self.data1, period=self.p.period)
            self.levels.plotinfo.subplot = False
    
    csv_opts = dict(
        headers=True, separator=';', dtformat='%Y-%m-%d %H:%M:%S %z',
        openinterest=-1)
    h1_opts = dict(dataname='data-h1.csv',
                   timeframe=bt.TimeFrame.Minutes, compression=60)
    d1_opts = dict(dataname='data-d1.csv',
                   timeframe=bt.TimeFrame.Days)
    
    cerebro = bt.Cerebro(stdstats=False)
    data_h1 = bt.feeds.GenericCSVData(**{**csv_opts, **h1_opts})
    data_d1 = bt.feeds.GenericCSVData(**{**csv_opts, **d1_opts})
    cerebro.adddata(data_h1)
    cerebro.adddata(data_d1)
    cerebro.addstrategy(LevelsDisplay, period=3)
    cerebro.run(runonce=False)
    cerebro.plot(style='candle')
    

    And this is data-d1.csv:

    TIME;OPEN;HIGH;LOW;CLOSE;VOLUMES
    2019-02-01 01:00:00 +0100;11198;11218;11116;11180;104846000
    2019-02-04 01:00:00 +0100;11180;11209;11100;11176;76459000
    2019-02-05 01:00:00 +0100;11178;11371;11177;11367;92184000
    2019-02-06 01:00:00 +0100;11337;11347;11297;11324;78242000
    2019-02-07 01:00:00 +0100;11262;11286;11022;11022;111363000
    2019-02-08 01:00:00 +0100;10991;11045;10864;10906;105464736
    

    and data-h1.csv:

    TIME;OPEN;HIGH;LOW;CLOSE;VOLUMES
    2019-02-01 09:00:00 +0100;11198;11218;11159;11197;13547140
    2019-02-01 10:00:00 +0100;11197;11211;11166;11180;7988925
    2019-02-01 11:00:00 +0100;11181;11187;11142;11161;7331403
    2019-02-01 12:00:00 +0100;11161;11177;11147;11150;5334638
    2019-02-01 13:00:00 +0100;11152;11160;11130;11134;6911563
    2019-02-01 14:00:00 +0100;11135;11186;11135;11175;5151842
    2019-02-01 15:00:00 +0100;11175;11181;11118;11119;9776934
    2019-02-01 16:00:00 +0100;11117;11175;11116;11162;10919961
    2019-02-01 17:00:00 +0100;11160;11186;11152;11180;37883752
    2019-02-04 09:00:00 +0100;11180;11209;11131;11143;12075054
    2019-02-04 10:00:00 +0100;11142;11197;11141;11186;6030952
    ...
    

    What am I doing wrong?


  • administrators

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    The current implementation of this indicator does not works: it has these two problems:

    Sorry, but it does work.

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    • both the H1 and the D1 charts are shown. I only want the H1 chart.

    You have not told the system that you only want the H1 chart. It cannot be a problem. You have not configured things to work the way you want.

    See - Docs - Plotting and use plotinfo.plot=False for whatever you don't want plotted.

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    • the indicator shows the right values in the D1 chart, but it is not plotted in the H1 chart

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    data_h1 = bt.feeds.GenericCSVData(**{**csv_opts, **h1_opts})
    data_d1 = bt.feeds.GenericCSVData(**{**csv_opts, **d1_opts})
    

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

            self.levels = Levels(self.data1, period=self.p.period)
    

    Well, you load d1 as the second feed in the system (hence self.data1) and you apply the indicator to self.data1. It should be no surprise that the indicator plots on d1 and not on h1. It would be a surprise if it did otherwise.

    Again. See - Docs - Plotting and use plotinfo.plotmaster=YOUR_DESIRED_DATA to plot on your chosen target.

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    See? No indicator in the H1 chart and a superfluous D1 chart.

    See above. There is nothing superfluous. You have to configure what you want and what you don't want and where you want it and where you don't want it.

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    As you can see in the following code, at the top level I first load the H1 data and then the D1 data. . This should make H1 the default data source, right?

    No idea what you mean with "default data source". There is no such thing in backtrader. The only thing you have achieved is that h1 can be referred as self.data0 or self.datas[0] or self.data. This is described here: Docs - Strategy in the section Member Attributes

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    Then, in the strategy, I set up the indicator to use self.data1. This should link its calculations to the D1 timeframe, shouldn't it?

    Yes. And that's why the indicator obviously plots on d1



  • @backtrader said in Multi timeframe indicator plotted twice and in wrong timeframe:

    @fino said in Multi timeframe indicator plotted twice and in the timeframe:

    The current implementation of this indicator does not works: it has these two problems:

    Sorry, but it does work.

    Hi @backtrader, thank you for your assistance. Yes, the code does work, but it does not do what I want it to do. Obviously the problem is that I'm giving the wrong instructions because I'm new to backtrader and still haven't understood most of it. So I thank you in advance for your help.

    See - Docs - Plotting and use plotinfo.plotmaster=YOUR_DESIRED_DATA to plot on your chosen target.

    I tried with

    self.levels.plotinfo.plotmaster = self.data0
    

    but it failed with the following error: ValueError: x and y must have same first dimension, but have shapes (54,) and (6,).

    I need to replicate the generated indicator values (6) for each H1 candle (9 * 6 = 56), don't I? What is the best way to do this?


  • administrators

    Use coupling: Docs - Mixing Timeframes in Indicators

    This functionality allows to calculate an indicator on a timeframe an automatically apply the indicator to another lower timeframe.



  • @backtrader said in Multi timeframe indicator plotted twice and in wrong timeframe:

    Use coupling: Docs - Mixing Timeframes in Indicators

    This functionality allows to calculate an indicator on a timeframe an automatically apply the indicator to another lower timeframe.

    I tried coupling the D1 indicator with the following code as suggested by the guide, but I still get the same error: ValueError: x and y must have same first dimension, but have shapes (54,) and (6,)

    class LevelsDisplay(bt.Strategy):
        params = dict(period=30)
    
        def __init__(self):
            # self.data1 = D1 Timeframe
            levels = Levels(self.data1, period=self.p.period)
            self.levels = levels()
            self.levels.plotinfo.subplot = False
            self.levels.plotinfo.plotmaster = self.data0
    

    I do not see any other places in the Strategy where I could couple.

    The guide says

    See how the () is executed with no arguments (in the background a None is being supplied). The following is happening:

    pivotpoint.s1() is returning an internal LinesCoupler object which follows the rhythm of the larger scope. This coupler fills itself with the latest delivered value from the real s1 (starting with a default value of NaN)

    How does the Cerebro know which timeframe is the "the larger scope"? Does it analyze all the added data?

    BTW the Mixing Timeframes guide is where I started and it does not mention plotmaster at all. Maybe it could be useful for newbies if it was somehow mentioned. Just a suggestion.


Log in to reply
 

});