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

No output from Optstrategy



  • There is no output from optstrategy running the example in the docs.

    Running the optstrategy example in Spyder the stop method is never called.

    The code below is taken from the last code example from https://www.backtrader.com/docu/quickstart/quickstart.html

    which I have modified to read data from a local CSV.

    When I run this example replacing
    strats = cerebro.optstrategy( TestStrategy, maperiod=range(10, 31))
    with
    cerebro.addstrategy(TestStrategy)
    I get the expected output as follows:

    '...018-03-23, Close, 301.54
    2018-03-26, Close, 304.18
    2018-03-27, Close, 279.18
    2018-03-27, (MA Period 15) Ending Value 11136.18
    this is stop being called'

    However when I replace the line
    cerebro.addstrategy(TestStrategy)
    with strats = cerebro.optstrategy( TestStrategy, maperiod=range(10, 31))
    I get nothing. No output. This is the only change to the code.

    Code reproduced below in full :

            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 btfeeds
    
    # Create a Stratey
    class TestStrategy(bt.Strategy):
    params = (
        ('maperiod', 15),
        ('printlog', True)
    )
    
    def log(self, txt, dt=None, doprint=False):
        ''' Logging function fot this strategy'''
        if self.params.printlog or doprint:
            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.dataclose = self.datas[0].close
    
        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None
    
        # Add a MovingAverageSimple indicator
        self.sma = bt.indicators.SimpleMovingAverage(
            self.datas[0], period=self.params.maperiod)
    
    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, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order.executed.price,
                     order.executed.value,
                     order.executed.comm))
    
                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))
    
            self.bar_executed = len(self)
    
        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):
        # 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:
    
            # Not yet ... we MIGHT BUY if ...
            if self.dataclose[0] > self.sma[0]:
    
                # BUY, BUY, BUY!!! (with all possible default parameters)
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
    
                # Keep track of the created order to avoid a 2nd order
                self.order = self.buy()
    
        else:
    
            if self.dataclose[0] < self.sma[0]:
                # SELL, SELL, SELL!!! (with all possible default parameters)
                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):
        self.log('(MA Period %2d) Ending Value %.2f' %
                 (self.params.maperiod, self.broker.getvalue()), doprint=True)
        print('this is stop being called')
    
    
    if __name__ == '__main__':
    # Create a cerebro entity
    cerebro = bt.Cerebro()
    
    # Add a strategy
    strats =  cerebro.optstrategy(
        TestStrategy,
        maperiod=range(10, 31))
    
    
      # cerebro.addstrategy(TestStrategy) 
    
    # Datas are in a subfolder of the samples. Need to find where the script is
    # because it could have been called from anywhere
    
    # Create a Data Feed
    modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
    fileName = os.path.join(modpath,'returnsData\\TSLA.csv')
    
    # Create a Data Feed
    
    data = btfeeds.GenericCSVData(dataname=fileName,dtformat=('%Y-%m-%d'),
    datetime=0,
    high=2,
    low=3,
    open=1,
    close=4,
    volume=5,
    openinterest=-1 )
    
    # Add the Data Feed to Cerebro
    cerebro.adddata(data)
    
    # Set our desired cash start
    cerebro.broker.setcash(10000.0)
    
    # Add a FixedSize sizer according to the stake
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)
    
    # Set the commission
    cerebro.broker.setcommission(commission=0.0)
    
    # Run over everything
    cerebro.run()
    

    Any idea why there is no output for the Optstrategy?


  • administrators

    Because you are shooting yourself in the foot by using Spyder, Windows and not using Google. (the 1st of the 3 is the actual real culprit, no matter how much you may hate Microsoft, or not ...)

    See here for the last time someone asked about the same lines: https://community.backtrader.com/topic/821/problem-while-getting-started/



  • Thank you for the answer. However the Optimizer doesn't call the stop method in Ubuntu / native python either.

    The output from the code below is
    0_1523533812868_077991d2-e298-4c5a-8c39-df5574f7274e-image.png
    Do you know why the stop method isn't called?

    Here is the code, based on your example, modified for local data and unix filenames

    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 btfeeds
    
    # Create a Stratey
    class TestStrategy(bt.Strategy):
    params = (
        ('maperiodShort', 10),
        ('maperiodLong', 30),
    )
    
    def log(self, txt, dt=None):
        ''' Logging function for this strategy'''
        dt = dt or self.datas[0].datetime.date(0)
        #print('%s, %s' % (dt.isoformat(), txt))
    
    def __init__(self):
        print ('Starting test strategy', self.params.maperiodShort, " -=- ", self.params.maperiodLong)
        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close
    
        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None
    
        # Add a MovingAverageSimple indicator
        self.smaS = bt.indicators.SimpleMovingAverage(
            self.datas[0], period=self.params.maperiodShort)
        
        self.smaL = bt.indicators.SimpleMovingAverage(
            self.datas[0], period=self.params.maperiodLong)
    
    
    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, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order.executed.price,
                     order.executed.value,
                     order.executed.comm))
    
                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))
    
            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):
        # Simply log the closing price of the series from the reference
    #    self.log('Close, %.2f' % self.dataclose[0]) - commented out as verbose
    
        # 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:
    
            # Not yet ... we MIGHT BUY if ...
            if self.smaS[0] > self.smaL[0]:
    
                # BUY, BUY, BUY!!! (with all possible default parameters)
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
    
                # Keep track of the created order to avoid a 2nd order
                self.order = self.buy()
    
        else:
    
            if self.smaL[0] > self.smaS[0]:
                # SELL, SELL, SELL!!! (with all possible default parameters)
                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):
       self.log('(MA Period %2d) Ending Value %.2f' %
                 (self.params.maperiod, self.broker.getvalue()), doprint=True)
    
    if __name__ == '__main__':
        print ('Starting OPTIMIZER')
        # Create a cerebro entity
    cerebro = bt.Cerebro()
    
    
    # Add a strategy
    strats = cerebro.optstrategy(
        TestStrategy,
        maperiodShort=range(5, 15))
    
    
    # set up paths tp csv data
    modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
    fileName = os.path.join(modpath,'returnsData/TSLA.csv')
    
    # Create a Data Feed
    data = btfeeds.GenericCSVData(dataname=fileName,dtformat=('%Y-%m-%d'),
    datetime=0,
    high=2,
    low=3,
    open=1,
    close=4,
    volume=5,
    openinterest=-1 )
    
    # Add the Data Feed to Cerebro
    cerebro.adddata(data)
    
    # Set our desired cash start
    cerebro.broker.setcash(10000.0)
    
    # Add a FixedSize sizer according to the stake
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)
    
    # Set the commission
    cerebro.broker.setcommission(commission=0.0)
    
       # Run over everything
    cerebro.run()


  • Update:

    The stop method isn't called as the Python spacing/tabs is wrong (This is wrong in the example on your Quickstart page so you might want to fix it). However fixng this causes the stop method to be called which then causes another error:
    <<
    File "C:/Users/Delta/.spyder/optTemplate001.py", line 166, in <module>
    cerebro.run()

    File "C:\ProgramData\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1143, in run
    for r in pool.imap(self, iterstrats):

    File "C:\ProgramData\Anaconda3\lib\multiprocessing\pool.py", line 695, in next
    raise value

    TypeError: log() got an unexpected keyword argument 'doprint'>>

    This error is to be expected as the self.log function doesn't have that argument.

    def log(self, txt, dt=None):
    ''' Logging function for this strategy'''
    dt = dt or self.datas[0].datetime.date(0)
    #print('%s, %s' % (dt.isoformat(), txt))
    

    A workaround is to replace the log in the stop function with a print statement although this isn't ideal.

    With the workaround this program works on Ubuntu/native python and windows/pycharm environments.

    As you correctly pointed out Spyder on Anaconda doesn't work.


  • administrators

    @mhotrx said in No output from Optstrategy:

    This is wrong in the example on your Quickstart page so you might want to fix it

    If you really believe to have found something wrong, you might want to give us a pointer as to where.

    In any case:

    • There are no tabs
    • The log method definition for the optimization is as follows
        def log(self, txt, dt=None, doprint=False):
            ''' Logging function fot this strategy'''
            if self.params.printlog or doprint:
                dt = dt or self.datas[0].datetime.date(0)
                print('%s, %s' % (dt.isoformat(), txt))
    

    which clearly takes parameters, named and unnamed. See it for yourself: Docs - Quickstart and specifically Docs - Quickstart - Let's Optimize

    Plausible explanation: You have mixed content from different files

    And seeing the formatting of the code you have posted, it seems a miracle that it does something at all. Please see the top of the forum for posting code blocks and output blocks. It will make your life a lot easier.