For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

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 :

    1. declared parameters to be optimized
    2. referenced them under self.params.x
    3. added the “Strategy” hook stop method
    4. 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!


  • administrators

    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!