Optimize Stop-Trail order values
-
Hi,
after posting "Create orders from CSV file" and getting quick and helpful feedabck. I have started using backtrader again and thanks to the great documentation I have now gotten to the stage where I can push in my own orders. I am now trying to:
Optimize against stop order entry price and trailing stop distance.
I have :
- declared parameters to be optimized
- referenced them under self.params.x
- added the “Strategy” hook stop method
- called the cerebro.optstategy function
However I keep getting the same value back from the broker for all variances of the optimization parameters.
Here is my code:
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv[0]) # Import the backtrader platform import backtrader as bt import backtrader.feeds as btfeed import pandas as pd class PlotScheme(object): def __init__(self): # Default plotstyle for the OHLC bars which (line -> line on close) # Other options: 'bar' and 'candle' self.style = 'line' class dataFeed(btfeed.GenericCSVData): params = ( ('dtformat', '%Y-%m-%d %H:%M:%S'), ('datetime', 0), ('open', 1), ('high', 2), ('low', 3), ('close', 4), ('volume', 5), ('openinterest', -1) ) # Create a Stratey class TestStrategy(bt.Strategy): params = ( ('trail', 10), ('distance', 3),) 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.datavolume = self.datas[0].volume # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = 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 # print('Submitted/Accepted: ', str(self.data.datetime.time(0))) 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, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) print(str(self.data.datetime.time(0))) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) print(str(self.data.datetime.time(0))) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') 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): global i,dt # Get datetime dt = self.datas[0].datetime.datetime() # Check if we are in the market try: # if not self.position: if orders['DATE'][i] == dt.strftime('%Y-%m-%d %H:%M:%S'): if orders['DIRECTION'][i] == 'BUY': self.log('OPEN BUY ORDER, %.2f' % self.dataclose[0]) self.order = self.buy(exectype=bt.Order.StopTrail, price=float(self.dataclose[0] + self.params.distance), trailamount=self.params.trail, valid=bt.Order.DAY) elif orders['DIRECTION'][i] == 'SELL': self.log('OPEN SELL ORDER, %.2f' % self.dataclose[0]) self.order = self.sell(exectype=bt.Order.StopTrail, price=float(self.dataclose[0] - self.params.distance), trailamount=self.params.trail, valid=bt.Order.DAY) i = i + 1 if dt.strftime('%H:%M') == '21:00': self.close() except: pass def stop(self): self.log('(Start distance %2d, Trail distance %2d) Ending Value %.2f' % (self.params.distance, self.params.trail, self.broker.getvalue())) if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() i = 0 state = False # Add a strategy # cerebro.addstrategy(TestStrategy) strats = cerebro.optstrategy(TestStrategy,distance=range(3,8), trail=range(3,8)) datapath = os.path.join('backtrader/deepanalysis/US500/US50015m_bid_chart_data_with_vol.csv') # Create a Data Feed data = dataFeed(dataname=datapath, timeframe=bt.TimeFrame.Minutes, compression=15) # Read Orders orders = pd.read_csv('backtrader/deepanalysis/US500/US500_orders_20180601_to_20180815_Norm_priority.csv') # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(5000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=1) # Set the commission cerebro.broker.setcommission(commission=0.0) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
Here is the output that i get:
C:\Users\jaspa\AppData\Local\conda\conda\envs\backtrader\python.exe C:/Users/jaspa/PycharmProjects/backtrader/US500_backtest_1.py Starting Portfolio Value: 5000.00 2018-08-15, (Start distance 3, Trail distance 6) Ending Value 5000.00 2018-08-15, (Start distance 3, Trail distance 7) Ending Value 5000.00 2018-08-15, (Start distance 6, Trail distance 7) Ending Value 5000.00 2018-08-15, (Start distance 4, Trail distance 6) Ending Value 5000.00 2018-08-15, (Start distance 3, Trail distance 3) Ending Value 5000.00 2018-08-15, (Start distance 3, Trail distance 4) Ending Value 5000.00 2018-08-15, (Start distance 4, Trail distance 3) Ending Value 5000.00 2018-08-15, (Start distance 5, Trail distance 5) Ending Value 5000.00 2018-08-15, (Start distance 4, Trail distance 5) Ending Value 5000.00 2018-08-15, (Start distance 5, Trail distance 6) Ending Value 5000.00 2018-08-15, (Start distance 4, Trail distance 4) Ending Value 5000.00 2018-08-15, (Start distance 3, Trail distance 5) Ending Value 5000.00 2018-08-15, (Start distance 6, Trail distance 4) Ending Value 5000.00 2018-08-15, (Start distance 7, Trail distance 4) Ending Value 5000.00 2018-08-15, (Start distance 5, Trail distance 4) Ending Value 5000.00 2018-08-15, (Start distance 5, Trail distance 3) Ending Value 5000.00 2018-08-15, (Start distance 7, Trail distance 6) Ending Value 5000.00 2018-08-15, (Start distance 6, Trail distance 6) Ending Value 5000.00 2018-08-15, (Start distance 4, Trail distance 7) Ending Value 5000.00 2018-08-15, (Start distance 5, Trail distance 7) Ending Value 5000.00 2018-08-15, (Start distance 6, Trail distance 3) Ending Value 5000.00 2018-08-15, (Start distance 7, Trail distance 5) Ending Value 5000.00 2018-08-15, (Start distance 7, Trail distance 7) Ending Value 5000.00 2018-08-15, (Start distance 6, Trail distance 5) Ending Value 5000.00 2018-08-15, (Start distance 7, Trail distance 3) Ending Value 5000.00 Final Portfolio Value: 5000.00 Process finished with exit code 0
Here is the output I get when I run the strategy with the default parameter values:
C:\Users\jaspa\AppData\Local\conda\conda\envs\backtrader\python.exe C:/Users/jaspa/PycharmProjects/backtrader/US500_backtest_1.py Starting Portfolio Value: 5000.00 2018-06-05, OPEN BUY ORDER, 2748.13 2018-06-05, BUY EXECUTED, Price: 2749.75, Cost: 2749.75, Comm 0.00 19:45:00 2018-06-05, SELL EXECUTED, Price: 2751.51, Cost: 2749.75, Comm 0.00 21:15:00 2018-06-05, OPERATION PROFIT, GROSS 1.76, NET 1.76 2018-06-06, OPEN SELL ORDER, 2755.69 2018-06-07, OPEN BUY ORDER, 2775.99 2018-06-07, BUY EXECUTED, Price: 2771.76, Cost: 2771.76, Comm 0.00 20:30:00 2018-06-07, SELL EXECUTED, Price: 2771.60, Cost: 2771.76, Comm 0.00 21:15:00 2018-06-07, OPERATION PROFIT, GROSS -0.16, NET -0.16 2018-06-08, OPEN SELL ORDER, 2765.90 2018-06-12, OPEN SELL ORDER, 2784.50 2018-06-13, OPEN SELL ORDER, 2788.59 2018-06-13, SELL EXECUTED, Price: 2780.88, Cost: -2780.88, Comm 0.00 19:00:00 2018-06-13, BUY EXECUTED, Price: 2773.30, Cost: -2780.88, Comm 0.00 21:15:00 2018-06-13, OPERATION PROFIT, GROSS 7.58, NET 7.58 2018-06-14, OPEN BUY ORDER, 2783.62 2018-06-15, OPEN BUY ORDER, 2769.40 2018-06-15, BUY EXECUTED, Price: 2776.40, Cost: 2776.40, Comm 0.00 19:15:00 2018-06-15, SELL EXECUTED, Price: 2779.87, Cost: 2776.40, Comm 0.00 21:15:00 2018-06-15, OPERATION PROFIT, GROSS 3.47, NET 3.47 2018-06-18, OPEN SELL ORDER, 2761.90 2018-06-19, OPEN SELL ORDER, 2752.10 2018-06-20, OPEN BUY ORDER, 2770.13 2018-06-21, OPEN BUY ORDER, 2762.47 2018-06-21, BUY EXECUTED, Price: 2760.22, Cost: 2760.22, Comm 0.00 16:45:00 2018-06-21, SELL EXECUTED, Price: 2749.00, Cost: 2760.22, Comm 0.00 21:15:00 2018-06-21, OPERATION PROFIT, GROSS -11.22, NET -11.22 2018-06-25, OPEN SELL ORDER, 2733.98 2018-06-25, SELL EXECUTED, Price: 2720.98, Cost: -2720.98, Comm 0.00 15:00:00 2018-06-25, BUY EXECUTED, Price: 2719.10, Cost: -2720.98, Comm 0.00 21:15:00 2018-06-25, OPERATION PROFIT, GROSS 1.88, NET 1.88 2018-06-26, OPEN BUY ORDER, 2724.19 2018-06-26, BUY EXECUTED, Price: 2730.26, Cost: 2730.26, Comm 0.00 18:00:00 2018-06-26, SELL EXECUTED, Price: 2725.91, Cost: 2730.26, Comm 0.00 21:15:00 2018-06-26, OPERATION PROFIT, GROSS -4.35, NET -4.35 2018-06-27, OPEN SELL ORDER, 2730.00 2018-06-27, SELL EXECUTED, Price: 2734.02, Cost: -2734.02, Comm 0.00 16:00:00 2018-06-27, BUY EXECUTED, Price: 2702.05, Cost: -2734.02, Comm 0.00 21:15:00 2018-06-27, OPERATION PROFIT, GROSS 31.97, NET 31.97 2018-06-28, OPEN BUY ORDER, 2699.73 2018-06-28, BUY EXECUTED, Price: 2707.06, Cost: 2707.06, Comm 0.00 16:00:00 2018-06-28, SELL EXECUTED, Price: 2717.05, Cost: 2707.06, Comm 0.00 21:15:00 2018-06-28, OPERATION PROFIT, GROSS 9.99, NET 9.99 2018-06-29, OPEN BUY ORDER, 2735.20 2018-06-29, BUY EXECUTED, Price: 2743.16, Cost: 2743.16, Comm 0.00 16:00:00 2018-06-29, SELL EXECUTED, Price: 2720.23, Cost: 2743.16, Comm 0.00 21:15:00 2018-06-29, OPERATION PROFIT, GROSS -22.93, NET -22.93 2018-07-30, OPEN BUY ORDER, 2812.63 2018-07-31, OPEN BUY ORDER, 2813.06 2018-07-31, BUY EXECUTED, Price: 2819.25, Cost: 2819.25, Comm 0.00 16:45:00 2018-07-31, SELL EXECUTED, Price: 2822.88, Cost: 2819.25, Comm 0.00 21:15:00 2018-07-31, OPERATION PROFIT, GROSS 3.63, NET 3.63 2018-08-01, OPEN SELL ORDER, 2819.48 2018-08-01, SELL EXECUTED, Price: 2814.76, Cost: -2814.76, Comm 0.00 16:45:00 2018-08-01, BUY EXECUTED, Price: 2809.82, Cost: -2814.76, Comm 0.00 21:15:00 2018-08-01, OPERATION PROFIT, GROSS 4.94, NET 4.94 2018-08-02, OPEN SELL ORDER, 2799.40 2018-08-03, OPEN BUY ORDER, 2830.09 2018-08-03, BUY EXECUTED, Price: 2838.84, Cost: 2838.84, Comm 0.00 20:00:00 2018-08-03, SELL EXECUTED, Price: 2838.85, Cost: 2838.84, Comm 0.00 21:15:00 2018-08-03, OPERATION PROFIT, GROSS 0.01, NET 0.01 2018-08-06, OPEN SELL ORDER, 2837.96 2018-08-07, OPEN SELL ORDER, 2858.17 2018-08-08, OPEN BUY ORDER, 2855.45 2018-08-09, OPEN SELL ORDER, 2856.91 2018-08-09, SELL EXECUTED, Price: 2851.92, Cost: -2851.92, Comm 0.00 20:45:00 2018-08-09, BUY EXECUTED, Price: 2851.81, Cost: -2851.92, Comm 0.00 21:15:00 2018-08-09, OPERATION PROFIT, GROSS 0.11, NET 0.11 2018-08-10, OPEN SELL ORDER, 2838.98 2018-08-10, SELL EXECUTED, Price: 2829.47, Cost: -2829.47, Comm 0.00 18:45:00 2018-08-10, BUY EXECUTED, Price: 2835.86, Cost: -2829.47, Comm 0.00 21:15:00 2018-08-10, OPERATION PROFIT, GROSS -6.39, NET -6.39 2018-08-13, OPEN BUY ORDER, 2837.68 2018-08-13, BUY EXECUTED, Price: 2831.50, Cost: 2831.50, Comm 0.00 19:15:00 2018-08-13, SELL EXECUTED, Price: 2824.10, Cost: 2831.50, Comm 0.00 21:15:00 2018-08-13, OPERATION PROFIT, GROSS -7.40, NET -7.40 2018-08-14, OPEN BUY ORDER, 2831.96 2018-08-14, BUY EXECUTED, Price: 2840.96, Cost: 2840.96, Comm 0.00 15:45:00 2018-08-14, SELL EXECUTED, Price: 2839.56, Cost: 2840.96, Comm 0.00 21:15:00 2018-08-14, OPERATION PROFIT, GROSS -1.40, NET -1.40 2018-08-15, OPEN SELL ORDER, 2822.43 2018-08-15, SELL EXECUTED, Price: 2809.43, Cost: -2809.43, Comm 0.00 15:00:00 2018-08-15, (Start distance 3, Trail distance 10) Ending Value 5010.83 Final Portfolio Value: 5010.83 Process finished with exit code 0
I'm sure it is probably something obvious but we all have to start somewhere :) All help greatly appreciated!
-
You have a
try ... except
that catches all exceptions (you won't even know an error happened) and plays with global variables: doomed to fail. -
@backtrader So obvious (when you know how) got it. Removed the globals and try except and got it to work! Thank you sir!