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

Backtest perpetually running, can't interrupt kernel/pandas data



  • I'm running into an issue where upon running a backtest, ipython will keep in a state of running with the asterisk [*] and no amount of spamming the interrupt kernel button will stop it. Restarting the kernel works, but I don't understand where the issue is originating. One idea of origin is that I am trying to feed pandas data, and it's fully possible that I'm not implementing it correctly. The strategy isn't anything special, it's simply the moving average cross taken from the quickstart page. My dataframe (ps) looks like this:
    0_1533256293649_dataframe.png

    And the rest of my code is:

    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 MySQLdb
    import pandas as pd
    
    # Import the backtrader platform
    import backtrader as bt
    import backtrader.feeds as btfeeds
    
    
    # Create a Stratey
    class TestStrategy(bt.Strategy):
        params = (
        ('maperiod', 15),
        ('printlog', False),
        )
    
        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)
    
    
    if __name__ == '__main__':
    # Create a cerebro entity
    cerebro = bt.Cerebro()
    
    # Add a strategy
    strats = cerebro.optstrategy(
        TestStrategy,
        maperiod=range(10, 31))
    
    # Datas are in a subfolder of the samples. Need to find where the script is
    # because it could have been called from anywhere
    #modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
    #datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
    
    
    # Create a Data Feed
    data = btfeeds.PandasData(dataname=ps)
    
    # Add the Data Feed to Cerebro
    cerebro.adddata(data)
    
    # Set our desired cash start
    cerebro.broker.setcash(1000000.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()
    

    If anybody has experienced this before or has any suggestions I'd love to hear about it, I'll be working all night. Thanks.

    EDIT: I have additionally tried setting the index to the datetime and running again, still no change


  • administrators

    In your description you have omitted the most important point: "You are optimizing the strategy". Even if you see it so, it is no longer the sample script with just a change in the data feed.

    The Kernel is known to hijack the start process of Python and have problems with multiprocessing

    This is a known problem and has nothing to do with backtrader: https://community.backtrader.com/topic/744/optstrategy-not-working-in-jupyter



  • @backtrader, Thank you for the explanation. I was just getting ready to post an update saying that it's working now. I started over from scratch, converted my data to csv, copy & pasted through the quickstart page, and everything has been going smoothly.