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/

    Help on Optimization code and Looping Opt.

    General Code/Help
    1
    1
    98
    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.
    • F
      FrankieC last edited by

      Hello everybody,

      I'm trying to set up a code to run in order optimizations (changing two parameters on a single indicator.

      I'm trying to set up the code to have the optimization running for different timeframes during the day (I'm using 1min data frame on Nasdaq Futures).

      This is my BacktraderOPT .py file.

      import backtrader.indicators as btind
      
      import matplotlib
      import os
      import datetime  # For datetime objects
      import os.path  # To manage paths
      import sys  # To find out the script name (in argv[0])
      import pytz
      import numpy as np
      from pandas import DataFrame
      
      ## SuperTrend Indicator Import ##
      from SupertrendBacktrader import *
      
      
      # Create a Strategy
      class TestStrategy(bt.Strategy):
          params = (('period', 18), ('multiplier', 2.8))
      
      # The first data in the list self.datas[0] is the default data for trading operations and to keep all strategy elements synchronized (it’s the system clock)
          def log(self, txt, dt=None):
              ''' Logging function fot this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              dt1 = self.data0.datetime.time(0)
              print('%s,%s, %s' % (dt.isoformat(), dt1.isoformat(), txt))
      
          def __init__(self):
              init_time = time.time()
              self.startcash = self.broker.getvalue()
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
              self.Superbands = SuperTrendBand(period=self.params.period, multiplier=self.params.multiplier)
              self.Supertrend = SuperTrend(period=self.params.period, multiplier=self.params.multiplier)
              # To keep track of pending orders and buy price/commission
              self.order = None
              self.buyprice = None
              self.buycomm = None
      
      
              # Indicators for the plotting show
              #bt.indicators.ExponentialMovingAverage(self.datas[0], period=25)
              #bt.indicators.WeightedMovingAverage(self.datas[0], period=25,subplot=True)
      
              #bt.indicators.ATR(self.datas[0], plot=False)
              self.buyp_sellm = bt.ind.CrossOver(self.dataclose,self.Supertrend)
      
          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, Size: %.2f, OpenPrice: %.2f, Closeprice: %.2f, Comm %.2f' %
                          (order.executed.size,
                           order.executed.price,
                           order.executed.value,
                           order.executed.comm))
      
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                      self.opsize = order.executed.size
                  else:  # Sell
                      self.log(
                          'SELL EXECUTED, Size: %.2f, OpenPrice: %.2f, Closeprice: %.2f, Comm %.2f' %
                               (order.executed.size,
                                order.executed.price,
                                order.executed.value,
                                order.executed.comm))
      
      
              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 notify_trade(self, trade):
      
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
      
              if self.data.datetime.time() < Session_begin:
                  self.close()# don't operate until x
                  return  #
              if self.data.datetime.time() > Session_end:
                  self.close()# don't operate after y
                  return  #
              # Simply log the closing price of the series from the reference
              #self.log('Close, %.2f' % self.dataclose[0])
      
              # 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:
                      #CB0=self.dataclose[0] > self.Supertrend[0]
                      #CB1=self.dataclose[-1] < self.Supertrend [-1]
                          # Not yet ... we MIGHT BUY if ...
      
              if self.buyp_sellm==1:
      
                  # BUY, BUY, BUY!!! (with all possible default parameters)
                  self.close()
                  self.log('BUY CREATE, %.2f' % self.dataclose[0])
      
                  # Keep track of the created order to avoid a 2nd order
                  self.order = self.buy()
      
      
              elif self.buyp_sellm==-1:
      
                  # SELL, SELL, SELL!!! (with all possible default parameters)
                  self.close()
                  self.log('SELL CREATE, %.2f' % self.dataclose[0])
      
                      # Keep track of the created order to avoid a 2nd order
                  self.order = self.sell()
      
          def stop(self):
              pnl = round(self.broker.getvalue() - self.startcash, 3)
              print('SuTR Period: {} SuTR Mult: {}Final PnL: {}'.format(
                  self.params.period,self.params.multiplier, pnl))
      
      if __name__ == '__main__':
          # Variable for our starting cash
          startcash = 100000
      
          # Create a cerebro entity
          cerebro = bt.Cerebro(optreturn=False)
      
          # Add a strategy
          cerebro.optstrategy(TestStrategy, period=range(10, 41, 1), multiplier=np.linspace(1.0,4.0,31))
      
      
          data = btfeeds.GenericCSVData(
              dataname='CME_MINI_NQ1!Date.csv',
      
              fromdate=fromdate,
              todate=todate,
              sessionstart=datetime.time(14, 00),
              sessionend=datetime.time(19, 00),
      
              dtformat=('%Y-%m-%d %H:%M:%S'),
              datetime=1,
              high=3,
              low=4,
              open=2,
              close=5,
              volume=8,
              openinterest=-1,
      
              timeframe=bt.TimeFrame.Minutes,
              compression=1
          )
      
          # Add the Data Feed to Cerebro
          cerebro.adddata(data)
      
          # Set our desired cash start
          cerebro.broker.setcash(startcash)
          # Set the commission
          cerebro.broker.setcommission(commission=0.00014, mult=20)
          # Run over everything
          opt_runs = cerebro.run()
      
          # Generate results list
          final_results_list = []
          for run in opt_runs:
              for strategy in run:
                  value = round(strategy.broker.get_value(), 2)
                  PnL = round(value - startcash, 2)
                  period = strategy.params.period
                  multiplier= round(strategy.params.multiplier,2)
                  final_results_list.append([period,multiplier, PnL])
      
          # Sort Results List
          by_period = sorted(final_results_list, key=lambda x: x[0])
          by_PnL = sorted(final_results_list, key=lambda x: x[2], reverse=False)
      
          # Print results
      
          print('Results: Ordered by Profit:')
          for result in by_PnL:
              print('SuTR Period: {}, SuTR Mult: {},Final PnL: {}'.format(result[0], result[1], result[2]))
          print("Opt Start on ",fromdate, "and ends on",todate)
      
      
      #print(fromdate,todate, Session_begin,Session_end)
      print("Total script time is --- %s minutes ---" % ((time.time() - start_time)/60))
      

      My code recalls SuperTrend custom indicator from another file and gives as an output a pivot data frame as .csv with period as rows and multiplier as columns with PnL as values.

      ResultsListdf = DataFrame(final_results_list)
      print(ResultsListdf)
      ResultsListdf=ResultsListdf.pivot(index=0,columns=1,values=2)
      
      fromdate_Time=fromdate.strftime("%H:%M-")
      fromdate_Date=fromdate.strftime("%d:%m-")
      fromdate_Year=fromdate.strftime("%Y-")
      fromdate_DateTime = fromdate.strftime("%d-%m-%Y<%H:%M")
      todate_Time=todate.strftime("%H:%M<")
      todate_Date=todate.strftime("%d-%m<")
      todate_Year=todate.strftime("%Y")
      todate_DateTime = todate.strftime("%d-%m-%Y>%H:%M")
      
      outFileName=("SXTR-"+fromdate_Time+todate_Time+fromdate_Date+todate_Date+fromdate_Year+todate_Year+'.csv')
      ResultsListdf.to_csv(r'/PycharmProjects/pythonProject3/'+outFileName,sep=',')
      

      So far my code runs smoothly and each optimization takes roughly 28min for 18 days of 1 min data with a filter to open positions only between 14:00 and 19:00. The strategy open a long/short position when signal is given by closing previous (if any) and opening a new one to follow the trend.

      What I'm trying to do is to set different session times and run in loop optimization to get different .csv files. This way I can see for different time of the day which set of parameters performs better. This by just clicking Run and leave the computer doing calculations (while the fans start to sound like a jet engine).

      #%%
      
      import matplotlib
      import os
      import datetime  # For datetime objects
      import os.path  # To manage paths
      import sys  # To find out the script name (in argv[0])
      import pytz
      import numpy as np
      from pandas import DataFrame
      
      #%%.  ERROR
      #DataImportVar
      fromdate = datetime.datetime(2021, 3, 3, 14, 00)
      todate = datetime.datetime(2021, 3, 3, 19, 00)
      #SessionTimeFilter
      Session_begin = datetime.time(14, 0)
      Session_end = datetime.time(19, 0)
      
      exec(open('BacktraderOPT.py').read())
      
      #Divide two parts with cell (Not Working)
      
      #%%
          #DataImportVar
      fromdate = datetime.datetime(2021, 3, 3, 15, 00)
      todate = datetime.datetime(2021, 3, 3, 19, 00)
          #SessionTimeFilter
      Session_begin = datetime.time(16, 0)
      Session_end = datetime.time(19, 0)
      
      exec(open('BacktraderOPT.py').read())
      

      To get faster result I've set to optimize only one day.
      Whenever I run the second cell I get the following error.
      Tried to run this in Jupyter but it really takes forever.

      AttributeError: Can't get attribute 'TestStrategy' on <module 'main' (built-in)>

      Any suggestion on how to solve this and save time by running this only one time?

      Have posted whole code for suggestions on how to improve it. I'm not really good at coding and I reckon that this code has plenty of room for improvement.

      Thanks in advance

      F.C

      1 Reply Last reply Reply Quote 0
      • 1 / 1
      • First post
        Last post
      Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors