Backtrader Strategy with multiple time frames

311 views Asked by At

I am using a strategy which is using 2 time frames (Daily and Weekly) and supposed to generate a buy/sell order on daily time frame whenever condition using daily time frame and weekly time frames are met. I saw that my code executes next() in strategy twice and execute order twice one for daily and one for weekly time frame. How should I control this and make system to generate only on daily time frame when condition with daily and weekly time frames are met.

Below is my strategy:

from future import (absolute_import, division, print_function, unicode_literals)
import backtrader as bt
import backtrader.indicators as btind
import datetime # For datetime objects
import os.path # To manage paths
import sys # To find out the script name (in argv[0])
import pandas as pd
from backtrader.indicators.supertrend import

class supertrend(bt.Strategy): 
   params = dict(
   onlydaily = False
)

def printdata(self,data):
    print(data)

def log(self, txt, dt=None):
  ''' Logging function fot this strategy'''
  dt = dt or self.datas[0].datetime.date(0)
  print('%s, %s' % (dt.isoformat(), txt))


def init(self):
   # Keep a reference to the "close" line in the data[0] dataseries
   self.dataopen = self.datas[0].open
   self.datahigh = self.datas[0].high
   self.datalow = self.datas[0].low
   self.dataclose = self.datas[0].close

  self.dataopen2 = self.datas[1].open
  self.datahigh2 = self.datas[1].high
  self.datalow2 = self.datas[1].low
  self.dataclose2 = self.datas[1].close  

 self.supertrend = SuperTrend(self.data, period = 10, multiplier = 3)
 if not self.p.onlydaily:
    self.supertrend2 = SuperTrend(self.data1, period= 10, multiplier = 1)

 self.crossup = btind.CrossUp(self.dataclose, self.supertrend)
 self.crossdown = btind.CrossDown(self.dataclose, self.supertrend)

 # To keep track of pending orders
 self.order = None
 def notify_order(self, order):
    if order.status in [order.Submitted, order.Accepted]:
    # Buy/Sell order submitted/accepted to/by broker - Nothing to do
    return

  # Check if an order has been completed
  # Attention: broker could reject order if not enough cash
 if order.status in [order.Completed]:
     if order.isbuy():
        self.log('BUY EXECUTED, %.2f' % order.executed.price)
     elif order.issell():
        self.log('SELL EXECUTED, %.2f' % order.executed.price)


  self.bar_executed = len(self)

elif order.status in [order.Canceled, order.Margin, order.Rejected]:
    self.log('Order Canceled/Margin/Rejected')

# Write down: no pending order
self.order = None

def next(self):
    # Check if an order is pending ... if yes, we cannot send a 2nd one
    #if self.order:
    # return

   # Check if we are in the market
  if not self.position:
     if self.crossup[0] == 1: #(self.dataclose[0] > self.supertrend[0]): # and (self.dataclose2[0] > self.supertrend2[0]):
            print('Entry trade')
            self.buy()
            
else:
    # Pattern Long exit
    if self.position.size > 0:
        if self.crossdown[0] == 1: #(self.dataclose[0] > self.supertrend[0]):# and (self.dataclose2[0] < self.supertrend2[0]):
          print('Exit trade')
          self.sell()

`

Below are the trades, it generates:

Entry trade

Entry trade

2008-04-28, BUY EXECUTED, 5112.50

2008-04-28, BUY EXECUTED, 5112.50

Exit trade

2008-05-27, SELL EXECUTED, 4877.15

Exit trade

2008-08-29, SELL EXECUTED, 4230.60

Entry trade

2008-11-05, BUY EXECUTED, 3155.75

Exit trade

2009-01-13, SELL EXECUTED, 2775.00

Entry trade

2009-03-24, BUY EXECUTED, 2923.80

Exit trade

2009-07-07, SELL EXECUTED, 4166.00

Entry trade

Entry trade

2009-07-20, BUY EXECUTED, 4377.90

2009-07-20, BUY EXECUTED, 4377.90

Exit trade

2009-10-28, SELL EXECUTED, 4846.55

Exit trade

Exit trade

2010-01-25, SELL EXECUTED, 5034.55

2010-01-25, SELL EXECUTED, 5034.55

Final Portfolio Value: -573182.64

1

There are 1 answers

0
Mike On

The buy() and sell() methods have a 'data' parameter where you can specifically point for which dataset you want to create the order. It is advisable to always use this feature when working with multiple timeframes to avoid confusion.

if self.crossup[0] == 1:
    print('Entry trade')
    self.buy(data=self.data0)