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?
-
If your signal is based on a
1-Day
timeframe and your orders are executed on the1-Minute
timeframe, the signal is active during all minutes of the day for the1-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 the1-Day
timeframe - Using the
len
of the1-Day
timeframe
- Using the
-
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!