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 I use daily and 1-minute bars without replaydata?



  • I apologize in advance for newbie confusion, but the code below that works as expected when fed only with a data0 (1-year of daily bars) line:

    from __future__ import (absolute_import, division, print_function, unicode_literals)
    import pandas as pd
    from sqlalchemy import create_engine
    import backtrader as bt
    import backtrader.indicators as btind
    
    # Create a Stratey
    class SMA_CrossOver(bt.Strategy):
    
        params = (('fast', 10), ('slow', 35))
    
        def __init__(self):
    
            sma_fast = btind.SMA(self.data0, period=self.p.fast)
            sma_slow = btind.SMA(self.data0, period=self.p.slow)
    
            self.buysig = btind.CrossOver(sma_fast, sma_slow)
    
        def next(self):
            if self.position.size:
                if self.buysig < 0:
                    limit = self.data0.close[0] * 0.98
                    self.sell(data=self.data0, exectype=bt.Order.Limit, price=limit)
    
            elif self.buysig > 0:
                price = self.data0.close[0] * 1.02
                limit = self.data0.close[0] * 1.04
                self.buy(data=self.data0, exectype=bt.Order.StopLimit, price=price, plimit=limit)
    
        def notify_order(self, order):
    
            if order.status in [order.Submitted, order.Accepted]:
                return
            if order.status in [order.Completed]:
                if order.isbuy():
                    txt = ','.join(
                        ['BUY EXECUTED: ', '%04d' % len(self),
                         '%04d' % len(self.data0),
                         # '%04d' % len(self.data1),
                         self.data.datetime.date(0).isoformat(),
                         '%.2f' % self.data0.close[0],
                         '%.2f' % self.buysig[0]])
                    print(txt)
                else:  # sell
                    txt = ','.join(
                    ['SELL EXECUTED: ', '%04d' % len(self),
                     '%04d' % len(self.data0),
                     # '%04d' % len(self.data1),
                     self.data.datetime.date(0).isoformat(),
                     '%.2f' % self.data0.close[0],
                     '%.2f' % self.buysig[0]])
                    print(txt)
    
    
            elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                print('Order Canceled/Margin/Rejected')
            self.order = None
    
    if __name__ == '__main__':
        # Connecting to PostgreSQL by providing a sqlachemy engine
        DB_TYPE = 'postgresql'
        DB_DRIVER = 'psycopg2'
        DB_USER = 'postgres'
        DB_PASS = 'XXXX'
        DB_HOST = 'localhost'
        DB_PORT = 'XXXX'
        DB_NAME = 'tests'
        POOL_SIZE = 50
        TABLENAME = 'tests'
        SQLALCHEMY_DATABASE_URI = '%s+%s://%s:%s@%s:%s/%s' % (DB_TYPE, DB_DRIVER, DB_USER,
                                                              DB_PASS, DB_HOST, DB_PORT, DB_NAME)
        ENGINE = create_engine(SQLALCHEMY_DATABASE_URI, pool_size=POOL_SIZE, max_overflow=0)
    
        # Create a cerebro entity
        cerebro = bt.Cerebro()
    
        # Add a strategy
        cerebro.addstrategy(SMA_CrossOver)
    
        # Get a pandas dataframe
        PETR4i = pd.read_sql("select day_id, open, high, low, close, volume 
              from vista_minutes where  instrument_id = 1571 order by day_id",  con=ENGINE)
    
        PETR4 = pd.read_sql("select day_id::timestamp , open, high, low, close, ntl_fin_vol 
               from bdins where  instrument_id = 1571 order by day_id ",  con=ENGINE)
    
        # Pass it to the backtrader datafeed and add it to the cerebro
        data1 = bt.feeds.PandasData(dataname=PETR4i,
                                   datetime=0,
                                   open=1,
                                   high=2,
                                   low=3,
                                   close=4,
                                   volume=5,
                                   timeframe=bt.TimeFrame.Minutes
                                   )
    
        # Pass it to the backtrader datafeed and add it to the cerebro
        data0 = bt.feeds.PandasData(dataname=PETR4,
                                   datetime=0,
                                   open=1,
                                   high=2,
                                   low=3,
                                   close=4,
                                   volume=5,
                                   timeframe=bt.TimeFrame.Days
                                   )
    
        # Add the Data Feed to Cerebro
        cerebro.adddata(data0)
        # cerebro.adddata(data1)
    
        # Set our desired cash start
        cerebro.broker.setcash(100000.0)
    
        cerebro.addsizer(bt.sizers.FixedSize, stake=100)
    
        # Set the commission - 0.1% ... divide by 100 to remove the %
        cerebro.broker.setcommission(commission=0.001)
    
        # Print out the starting conditions
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
        # Run over everything
        thestrats = cerebro.run(tradehistory=True)
        thestrat = thestrats[0]
    
        # Print out the final result
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    

    Producing:

    Starting Portfolio Value: 100000.00
    BUY EXECUTED: ,0089,0089,2017-05-12,15.45,1.00
    SELL EXECUTED: ,0100,0100,2017-05-29,13.57,0.00
    BUY EXECUTED: ,0146,0146,2017-08-02,13.51,0.00
    BUY EXECUTED: ,0203,0203,2017-10-24,16.51,0.00
    SELL EXECUTED: ,0222,0222,2017-11-23,16.19,0.00
    Final Portfolio Value: 100018.86
    

    when I add a second line data1 to the cerebro

        cerebro.adddata(data0)
        cerebro.adddata(data1)
    

    and try to make the broker use data1 (1-year of 1-minute bars) to execute the orders:

        def next(self):
            if self.position.size:
                if self.buysig < 0:
                    limit = self.data0.close[0] * 0.98
                    self.sell(data=self.data1, exectype=bt.Order.Limit, price=limit)
    
            elif self.buysig > 0:
                price = self.data0.close[0] * 1.02
                limit = self.data0.close[0] * 1.04
                self.buy(data=self.data1, exectype=bt.Order.StopLimit, price=price, plimit=limit)
    

    the output is nowhere near as what I'd expect:

    Starting Portfolio Value: 100000.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    BUY EXECUTED: ,39855,0089,2017-05-12,15.45,1.00
    Order Canceled/Margin/Rejected
    Order Canceled/Margin/Rejected
    Order Canceled/Margin/Rejected
    Order Canceled/Margin/Rejected
    ...
    

    I am obviously missing something important here, but since I have both daily and intraday data feeds available at once, I'd like to have my swing trades strategies using the daily data0 and once the orders were generated, feed the intraday line to the broker to have the opportunity to issue then a couple hours after the usually volatile opening and more importantly, when using bracket orders, be able to know if I'll get stopped out or take my profit during the day. This is impossible to deduce having only daily OHLC.

    Can I do that without having to resampledata() or replaydata() since I have both feeds at once? Do I need to use coupling, or prenext or something else that I am missing entirely to somehow to avoid the orders to be fired like crazy when I add a second intraday line?


  • administrators

    If your signal is based on a 1-Day timeframe and your orders are executed on the 1-Minute timeframe, the signal is active during all minutes of the day for the 1-Minute timeframe.

    You should keep a market to for example indicate that you already issued an order on the given day or use the absence of the market to execute the entry/exit logic):

    • Using the date of the 1-Day timeframe
    • Using the len of the 1-Day timeframe


  • I think I've got it now after what you said about the signal being active during all minutes...

    So, I'd do something like that I guess, comparing the lower timeframe len as you suggested:

    class SMA_CrossOver(bt.Strategy):
        params = (('fast', 10), ('slow', 35))
        
        def __init__(self):
            sma_fast = btind.SMA(self.data0, period=self.p.fast)
            sma_slow = btind.SMA(self.data0, period=self.p.slow)
    
            self.buysig = btind.CrossOver(sma_fast, sma_slow)
    
            # To keep track of pending orders
            self.order = None
            # to prevent lower TF actions to happen more than one
            self.bar_previous = None
    
        def next(self):
            # lower timeframe becomes active during the whole higer timeframe
            # make sure the strategy does it's thing only once
            if self.bar_previous != len(self.data0):
                self.bar_previous = len(self.data0)
    
                if self.position.size:
                    if self.buysig < 0:
                        limit = self.data0.close[0] * 0.98
                        self.sell(data=self.data0, exectype=bt.Order.Limit, price=limit)
    
                elif self.buysig > 0:
                    price = self.data0.close[0] * 1.02
                    limit = self.data0.close[0] * 1.04
                    self.buy(data=self.data0, exectype=bt.Order.StopLimit, price=price, plimit=limit)
    

    Thanks a lot, I think I can go from there!