For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
opt strategy consumes so much RAM
-
Hello everyone, i'm trying to optimize my strategy by using the following code:
import backtrader as bt from backtrader.feeds import PandasData import pandas as pd from datetime import datetime as dt from pandas import DataFrame as df class Equity(bt.Analyzer): def __init__(self): self.equity = [] def start(self): # Not needed ... but could be used self.init_cash = self.strategy.broker.cash self.num_trades = 0 self.record_equity() def stop(self): self.record_equity() def record_equity(self): self.equity.append(self.strategy.broker.getvalue()) def get_analysis(self): return self.equity # Create your strategy class MyStrategy(bt.Strategy): params = (('bb_period', 20), ('bb_devfactor', 2), ('rsi_period', 14), ('rsi_upper', 70), ('rsi_lower', 30), ('position_size', 1), ('stop_loss', 0.02), ('take_profit', 0.06)) def __init__(self): # Add indicators to the strategy self.bb = bt.indicators.BollingerBands(self.data.close, period=self.params.bb_period, devfactor=self.params.bb_devfactor) self.rsi = bt.indicators.RSI(self.data.close, period=self.params.rsi_period) self.order = None def log(self, txt): dt=self.datas[0].datetime.datetime(0) print('%s, %s' % (dt.isoformat(), txt)) #executes every datapoint def next(self): # Define the size of the position we will enter cash = self.broker.get_cash() if self.order: # If an order is pending, don't do anything return # Check if we are currently in a position if not self.position: if self.data.close[0] < self.bb.lines.bot[0] and self.rsi[0] < self.params.rsi_lower: size = cash * self.params.position_size / self.data.close[0] self.buy(size=size) self.log('buy order opened at: , %.2f' % self.data.close[0]) elif self.data.close[0] > self.bb.lines.top[0] and self.rsi[0] > self.params.rsi_upper: size = cash * self.params.position_size / self.data.close[0] self.sell(size=size) self.log('sell order opened at: , %.2f' % self.data.close[0]) else: size = self.position.size if size > 0 and (self.data.close[0] > self.bb.lines.mid[0] or self.rsi[0] > self.params.rsi_upper): self.sell(size=size) self.log('sold at: , %.2f' % self.data.close[0]) elif size > 0 and (self.data.close[0] < self.bb.lines.mid[0] or self.rsi[0] < self.params.rsi_lower): self.log('bought at: , %.2f' % self.data.close[0]) self.buy(size=size) #Order status change def notify_order(self, order): if order.status in [order.Submitted, order.Accepted] or not self.position: return # We have entered the market if order.status in [order.Completed]: self.close(exectype=bt.Order.StopTrail, price=order.executed.price,trailPercent = self.params.stop_loss) self.log('trailing stop at: , %.2f' % self.data.close[0]) self.analyzers.equity.record_equity() elif order.status in [order.Canceled, order.Margin, order.Rejected]: print('Order Cancelled/Margin/Rejected') self.order = None if __name__ == '__main__': # Split your data into a training set and a test set data_split_date = dt(2023, 5, 1) today = dt.today().strftime('%Y-%m-%d') df = pd.read_csv(f'data/data_2023-07-29.csv') # Load data from your csv file df = df[['open_time', 'open', 'high', 'low', 'close', 'volume']] df['open_time'] = pd.to_datetime(df['open_time'], unit='ms') # Assuming the 'open_time' is in Unix timestamp format (milliseconds) df.index = df['open_time'] df.set_index('open_time', inplace=True) # Set date as index train_data = df[df.index < data_split_date] test_data = df[df.index >= data_split_date] # Add your data to Backtrader data_feed_train = bt.feeds.PandasData(dataname=train_data) data_feed_test = bt.feeds.PandasData(dataname=test_data) # Create a Cerebro engine cerebro = bt.Cerebro(maxcpus=8, live=False, runonce=True, exactbars=False, optdatas=True, optreturn=False, stdstats=False, quicknotify=True) # Add your strategy to the Cerebro engine cerebro.broker.setcash(1000.0) cerebro.broker.setcommission(commission=0.002) cerebro.adddata(data_feed_train) # Optimize the strategy cerebro.optstrategy(MyStrategy, bb_period=range(10, 31), bb_devfactor=[x * 0.1 for x in range(1, 3)], rsi_period=range(10, 21), position_size=[x * 0.1 for x in range(1, 11)], stop_loss=[0.01, 0.02], take_profit=[0.04, 0.05, 0.06]) # Run the backtest on the training data cerebro.addanalyzer(Equity, _name='equity') print('<START> Brokerage account: $%.2f' % cerebro.broker.getvalue()) results = cerebro.run() print('<FINISH> Brokerage account: $%.2f' % cerebro.broker.getvalue()) # Find the best strategy best_strategy = None best_value = None for run in results: for strategy in run: portfolio_value = strategy.broker.get_value() if best_value is None or portfolio_value > best_value: best_strategy = strategy.params best_value = portfolio_value with open("best_strategy_params.txt", "w") as file: file.write(f"""Best Strategy Parameters: bb_period: {best_strategy.bb_period} \n bb_devfactor: {best_strategy.bb_devfactor}\n rsi_period: {best_strategy.rsi_period}\n rsi_upper: {best_strategy.rsi_upper} \n rsi_lower: {best_strategy.rsi_lower}\n positiion_size: {best_strategy.position_size}\n stop_loss: {best_strategy.stop_loss} \n take_profit: {best_strategy.take_profit}""") # Create a new Cerebro engine cerebro = bt.Cerebro(maxcpus=8, live=False, runonce=True, exactbars=False, optdatas=True, optreturn=False, stdstats=False, quicknotify=True) cerebro.broker.setcash(1000.0) cerebro.broker.setcommission(commission=0.002) # Add the best strategy to the Cerebro engine cerebro.addstrategy(strategy=MyStrategy, bb_period=best_strategy.bb_period, bb_devfactor= best_strategy.bb_devfactor, rsi_period= best_strategy.rsi_period, rsi_upper= best_strategy.rsi_upper, rsi_lower= best_strategy.rsi_lower, position_size= best_strategy.position_size, stop_loss= best_strategy.stop_loss, take_profit= best_strategy.take_profit) # Adds data for the feed test cerebro.adddata(data_feed_test) # Adds the analyzer declared in the first lines of this code. cerebro.addanalyzer(Equity, _name='equity') # Run the backtest on the test data print('<START> Brokerage account: $%.2f' % cerebro.broker.getvalue()) results = cerebro.run() print('<FINISH> Brokerage account: $%.2f' % cerebro.broker.getvalue()) equity_curve = results[0].analyzers.equity.get_analysis() equity_df = pd.DataFrame(data = equity_curve, columns= ['equity']) equity_df.to_csv(f'equity_{today}.csv')
Unfortunately, the process of optimization consumes all my 15Gb of available RAM. Do i really need to rent a rig for this use case or i'm doing something really wrong? Thanks beforehand. Notice that the optimization dataset has data of 1 month only with 1 hour each data point.