Help on Optimization code and Looping Opt.
-
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