Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    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?

    General Code/Help
    2
    3
    754
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • exu
      exu last edited by

      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?

      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        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
        1 Reply Last reply Reply Quote 0
        • exu
          exu last edited by

          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!

          1 Reply Last reply Reply Quote 0
          • 1 / 1
          • First post
            Last post
          Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
          $(document).ready(function () { app.coldLoad(); }); }