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

Used Timer only works (partially) with _getminperstatus() ?



  • Hello everyone,

    I have a question regarding the momentum strategy example given on the official website:
    https://www.backtrader.com/blog/2019-05-20-momentum-strategy/momentum-strategy/

    I wanted to use it to test Teddy Kokers survivor bias free dataset:
    https://github.com/teddykoker/quant/tree/master/survivorship-free

    In this dataset are some stocks that have limited data, for example only from 2013 to 2015 etc.

    But the code does not use all data sets but only those from the end of 2017 to the very beginning of 2018.
    This boils down to the to the timer I use and the _getminperstatus() method.

    Code:

    import argparse
    import datetime
    import glob
    import os.path
    import pandas as pd
    import backtrader as bt
    import backtrader.analyzers as btanal
    import pyfolio as pf
    import numpy as np
    from scipy.stats import linregress
    import warnings 
    warnings.filterwarnings('ignore')
    
    globalparams = dict(cash=10000,            # if a different strategy is used
                        commission=0.005,                # how many chunks the data should have
                        )
    
    def momentum_func(self, the_array):
        r = np.log(the_array)
        slope, _, rvalue, _, _ = linregress(np.arange(len(r)), r)
        annualized = (1 + slope) ** 252
        return annualized * (rvalue ** 2)
    
    class Momentum(bt.ind.OperationN):
        lines = ('trend',)
        #params = dict(period=50)
        func = momentum_func
       
    class St(bt.Strategy):
        params = dict(
            selcperc=0.50,  # percentage of stocks to select from the universe
            rperiod=1,  # period for the returns calculation, default 1 period
            vperiod=30,  # lookback period for volatility - default 36 periods
            mperiod=30,  # lookback period for momentum - default 90 periods
            momentum=Momentum, # parametrize the momentum and its period
            reserve=0.05,  # 5% reserve capital
            monthdays=[1],
            monthcarry=True,
            when=bt.timer.SESSION_START,
    
        )
    
        def log(self, arg):
            print('{} {}'.format(self.datetime.date(), arg))
    
        def __init__(self):
            # calculate 1st the amount of stocks that will be selected
            self.selnum = int(len(self.datas) * self.p.selcperc)
    
            # allocation perc per stock
            # reserve kept to make sure orders are not rejected due to
            # margin. Prices are calculated when known (close), but orders can only
            # be executed next day (opening price). Price can gap upwards
            self.perctarget = (1.0 - self.p.reserve) / self.selnum
            
            self.add_timer(
                when=self.p.when,
                monthdays=self.p.monthdays,
                monthcarry=self.p.monthcarry
            )
           
            # returns, volatilities and momentums
            rs = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.datas]
            vs = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rs]
            #ms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas]
            ms = [self.p.momentum(d, period=self.p.mperiod) for d in self.datas]
    
            # simple rank formula: (momentum * net payout) / volatility
            # the highest ranked: low vol, large momentum, large payout
            self.ranks = {d: m / v for d, v, m in zip(self.datas, vs, ms)}
            #TODO: does it perform better without the volatility?
      
        def prenext(self):
            # call next() even when data is not available for all tickers
            self.next()     
    
        def notify_timer(self, timer, when, *args, **kwargs):
            print('strategy notify_timer with tid {}, when {} _getminperstatus {}'.
                  format(timer.p.tid, when, int(self._getminperstatus())))
            if self._getminperstatus() < 0:
                
                self.rebalance()
        
        def next(self):
            pass
        def rebalance(self):
            # sort data and current rank
            ranks = sorted(
                self.ranks.items(),  # get the (d, rank), pair
                key=lambda x: x[1][0],  # use rank (elem 1) and current time "0"
                reverse=True,  # highest ranked 1st ... please
            )
            
            # put top ranked in dict with data as key to test for presence
            rtop = dict(ranks[:self.selnum])
    
            # For logging purposes of stocks leaving the portfolio
            rbot = dict(ranks[self.selnum:])
    
            # prepare quick lookup list of stocks currently holding a position
            posdata = [d for d, pos in self.getpositions().items() if pos]
    
            # remove those no longer top ranked
            # do this first to issue sell orders and free cash
            for d in (d for d in posdata if d not in rtop):
                self.log('Leave {} - Rank {:.2f}'.format(d._name, rbot[d][0]))
                self.order_target_percent(d, target=0.0)
    
            # rebalance those already top ranked and still there
            for d in (d for d in posdata if d in rtop):
                self.log('Rebal {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                del rtop[d]  # remove it, to simplify next iteration
    
            # issue a target order for the newly top ranked stocks
            # do this last, as this will generate buy orders consuming cash
            for d in rtop:
                self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
    
    
    def run(args=None):
        cerebro = bt.Cerebro()
    
    
        # Parse from/to-date
        fromdate = datetime.datetime(2013, 3, 1)
        todate = datetime.datetime(2018, 6, 18)
    
        # add all the data files available in the directory datadir
        for fname in glob.glob(os.path.join(r'C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy', '*')):
            df = pd.read_csv(fname, index_col=0, parse_dates=True)
    
            if len(df)>100:
                cerebro.adddata(bt.feeds.PandasData(dataname=df,name=os.path.basename(fname).replace(".csv", ""), plot=False))
                print(fname)
                
        # add strategy
        cerebro.addstrategy(St)
    
        # set the cash
        cerebro.broker.setcash(globalparams["cash"])
        cerebro.broker.set_coc(True)
        cerebro.broker.setcommission(commission=globalparams["commission"])
        
        #Analysers such as Sharpe Ratio
        cerebro.addanalyzer(bt.analyzers.SharpeRatio, riskfreerate=0.0)
        cerebro.addanalyzer(bt.analyzers.Returns)
        cerebro.addanalyzer(bt.analyzers.DrawDown)
        cerebro.addanalyzer(btanal.PyFolio)                # Needed to use PyFolio
        cerebro.addanalyzer(btanal.TradeAnalyzer)          # Analyzes individual trades
        cerebro.addanalyzer(btanal.SharpeRatio_A)          # Gets the annualized Sharpe ratio
        cerebro.addanalyzer(btanal.AnnualReturn)          # Annualized returns (does not work?)
        
        results = cerebro.run(stdstats=True, tradehistory=True)
        #cerebro.plot()
        #print(f"Sharpe: {results[0].analyzers.sharperatio.get_analysis()['sharperatio']:.3f}")
        print(f"Norm. Annual Return: {results[0].analyzers.returns.get_analysis()['rnorm100']:.2f}%")
        print(f"Max Drawdown: {results[0].analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%")
    
        # Basic performance evaluation ... final value ... minus starting cash
        pnl = cerebro.broker.get_value() - globalparams["cash"]
        print('Profit ... or Loss: {:.2f}'.format(pnl))
        
        
        returns, positions, transactions, gross_lev = results[0].analyzers.pyfolio.get_pf_items()
        benchmark_rets = pd.Series([0.00004] * len(returns.index), index=returns.index)     
        pf.create_full_tear_sheet(returns, positions, transactions, benchmark_rets=benchmark_rets)
        
    if __name__ == '__main__':
        run()
    

    This is the current result:

    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ACE.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ALGN.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ALK.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\AMD.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ANDV.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ANF.csv
    C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy\ANSS.csv
    strategy notify_timer with tid 0, when 2013-02-28 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-03-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-04-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-05-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-06-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-07-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-08-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-09-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-10-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-11-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2013-12-02 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2014-11-28 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2014-12-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-01-02 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-02-02 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-03-02 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-04-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-05-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-06-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-07-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-08-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-09-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-10-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-11-02 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2015-12-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-01-04 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-05-31 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-06-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-07-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-08-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-09-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-10-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-11-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2016-12-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-01-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-02-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-03-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-04-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-05-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-06-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-07-03 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-08-01 00:00:00 _getminperstatus 31
    strategy notify_timer with tid 0, when 2017-09-01 00:00:00 _getminperstatus 29
    strategy notify_timer with tid 0, when 2017-10-02 00:00:00 _getminperstatus 9
    strategy notify_timer with tid 0, when 2017-11-01 00:00:00 _getminperstatus -13
    2017-10-31 Enter ANSS - Rank 381.55
    2017-10-31 Enter ALGN - Rank 111.90
    2017-10-31 Enter ANDV - Rank 42.54
    strategy notify_timer with tid 0, when 2017-12-01 00:00:00 _getminperstatus -33
    2017-11-30 Leave ANDV - Rank 3.54
    2017-11-30 Rebal ALGN - Rank 342.50
    2017-11-30 Rebal ANSS - Rank 161.41
    2017-11-30 Enter ANF - Rank 12.86
    strategy notify_timer with tid 0, when 2018-01-02 00:00:00 _getminperstatus -53
    2017-12-29 Leave ALGN - Rank 6.34
    2017-12-29 Leave ANF - Rank 12.86
    2017-12-29 Rebal ANSS - Rank 17.96
    2017-12-29 Enter ALK - Rank 216.27
    2017-12-29 Enter ANDV - Rank 209.17
    strategy notify_timer with tid 0, when 2018-02-01 00:00:00 _getminperstatus -74
    2018-01-31 Leave ALK - Rank 8.05
    2018-01-31 Leave ANDV - Rank 3.20
    2018-01-31 Rebal ANSS - Rank 265.25
    2018-01-31 Enter ALGN - Rank 309.81
    2018-01-31 Enter AMD - Rank 222.55
    Norm. Annual Return: -1.74%
    Max Drawdown: 20.90%
    Profit ... or Loss: -629.08
    

    If I get rid of the timer alltogether, it works @.@... but I want that timer.

    If I delete the _getminperstatus() <0 condition I have another "IndexError: array index out of range" Error...

    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-23-79b3013d2f54> in <module>
        169 
        170 if __name__ == '__main__':
    --> 171     run()
    
    <ipython-input-23-79b3013d2f54> in run(args)
        153     cerebro.addanalyzer(btanal.AnnualReturn)          # Annualized returns (does not work?)
        154 
    --> 155     results = cerebro.run(stdstats=True, tradehistory=True)
        156     #cerebro.plot()
        157     #print(f"Sharpe: {results[0].analyzers.sharperatio.get_analysis()['sharperatio']:.3f}")
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in run(self, **kwargs)
       1125             # let's skip process "spawning"
       1126             for iterstrat in iterstrats:
    -> 1127                 runstrat = self.runstrategies(iterstrat)
       1128                 self.runstrats.append(runstrat)
       1129                 if self._dooptimize:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata)
       1291                     self._runonce_old(runstrats)
       1292                 else:
    -> 1293                     self._runonce(runstrats)
       1294             else:
       1295                 if self.p.oldsync:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in _runonce(self, runstrats)
       1690                 return
       1691 
    -> 1692             self._check_timers(runstrats, dt0, cheat=False)
       1693 
       1694             for strat in runstrats:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in _check_timers(self, runstrats, dt0, cheat)
       1705                 continue
       1706 
    -> 1707             t.params.owner.notify_timer(t, t.lastwhen, *t.args, **t.kwargs)
       1708 
       1709             if t.params.strats:
    
    <ipython-input-23-79b3013d2f54> in notify_timer(self, timer, when, *args, **kwargs)
         80         if self._getminperstatus() < 100:
         81 
    ---> 82             self.rebalance()
         83 
         84     def next(self):
    
    <ipython-input-23-79b3013d2f54> in rebalance(self)
        116         # do this last, as this will generate buy orders consuming cash
        117         for d in rtop:
    --> 118             self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
        119             self.order_target_percent(d, target=self.perctarget)
        120 
    
    <ipython-input-23-79b3013d2f54> in log(self, arg)
         42 
         43     def log(self, arg):
    ---> 44         print('{} {}'.format(self.datetime.date(), arg))
         45 
         46     def __init__(self):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\linebuffer.py in date(self, ago, tz, naive)
        389 
        390     def date(self, ago=0, tz=None, naive=True):
    --> 391         return num2date(self.array[self.idx + ago],
        392                         tz=tz or self._tz, naive=naive).date()
        393 
    
    IndexError: array index out of range
    

    I don't understand what the _getminperstatus() means and could only find the python function definiton, but that didn't help me...
    https://github.com/mementum/backtrader/blob/master/backtrader/strategy.py

    Thank you so much in advance!



  • ok it is not the timer...

    Hello everyone,

    I am puzzled by the point my algorithm starts to trade:

    Strategy:

    import datetime
    import glob
    import webbrowser
    import os.path
    import pandas as pd
    import backtrader as bt
    import backtrader.analyzers as btanal
    import pyfolio as pf
    import numpy as np
    from scipy.stats import linregress
    import quantstats as qs
    
    %matplotlib inline
    import matplotlib.pyplot as plt
    plt.rcParams["figure.figsize"] = (13,13)
    
    import warnings 
    warnings.simplefilter(action='ignore', category=Warning)
    warnings.simplefilter(action='ignore', category=FutureWarning)
    
    globalparams = dict(cash=10000,            
                        commission=0.005,
                        reserve=0.05,
                        )
    
    # <<<Benchmark Strategy section>>>  
    
    class HoldAllStrategy(bt.Strategy):
        """
        HoldAll Strategy.
        Usually, used for benchmarking test.
        Almost same with the HoldStrategy, it tries to buy all provided securities with the same ratio.
        buy_date: iso-format str, buy order will be created the first market day after the buy_date.
        https://github.com/samuel281/qu-ant/blob/master/lib/strategies/hold_all_strategy.py
        """
        params = dict(
            buy_date=datetime.datetime.today().isoformat(),
        )
        
        def __init__(self):
            self.stocks = [i for i in self.getdatanames()] #must filter out bond and spy
            for d in self.stocks:
                self.dnames[d].lengthlist = [0]
    
        def next(self):
            '''
            if self.position:
                return
            '''
            if self.data.datetime.date(0).isoformat() < self.params.buy_date.isoformat(): #buydate must be determined by the first strategy, since it is the date of the first trade?
                return
    
            target_ratio = 1.0 - globalparams["reserve"]
            target_ratio_per_sec = target_ratio / len(self.stocks)
            #print(target_ratio_per_sec, len(self.stocks))
            for d in self.stocks:
                datad = self.dnames[d]
                datad.lengthlist.append(len(datad))
                if len(datad) > 0:
                    if datad.lengthlist[-1] > datad.lengthlist[-2]:  
                        self.order_target_percent(data=d, target=target_ratio_per_sec)
                    else:
                        self.order_target_percent(data=d, target=0.0)
    
        def log(self, arg):
            print('{} {}'.format(self.datetime.date(), arg))            
                
        def on_order_executed(self, order):
            pass
    
        def notify_order(self, order):
            if order.status in [order.Accepted]:
                # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                return
            if order.status in [order.Submitted]:
                if order.isbuy():
    
                    dt, dn = self.datetime.date(), order.data._name
                    print('Buy {} {} {} Price {:.2f} Value {:.2f} Size {} Cash {:.2f} Broker {:.2f}'.format(
                            order.getstatusname(), dt, dn, order.created.price, order.created.size * order.created.price , order.created.size, self.broker.getcash(), self.broker.getvalue()))
                if order.issell():
                    dt, dn = self.datetime.date(), order.data._name
                    print('Sell {} {} {} Price {:.2f} Value {:.2f} Size {} Broker {:.2f}'.format(
                            order.getstatusname(), dt, dn, order.created.price, order.created.size * order.created.price, order.created.size, self.broker.getvalue()))
    
                # 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():
                    dt, dn = self.datetime.date(), order.data._name
                    print('Buy {} {} Price {:.2f} Value {:.2f} Size {}'.format(
                        dt, dn, order.executed.price, order.executed.value, order.executed.size))
    
                if order.issell():# Sell
                    dt, dn = self.datetime.date(), order.data._name
                    print('Sell {} {} Price {:.2f} Value {:.2f} Size {}'.format(
                        dt, dn, order.executed.price, order.executed.value, order.executed.size))
    
            elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                self.log('Order Canceled/Margin/Rejected')
    

    execution and datafeeds:

    def run(args=None):
        cerebro = bt.Cerebro()
    
        # Parse from/to-date
        fromdate = datetime.datetime(2009, 3, 1)
        todate = datetime.datetime(2020, 6, 18)
        
        # Add SPY/QQQ as "Benchmark"
        df0 = pd.read_csv(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\SPY.csv', index_col=0, parse_dates=True)
        benchdata = bt.feeds.PandasData(dataname=df0,name="SPY",fromdate=fromdate, todate=todate,  plot=False)
        cerebro.adddata(benchdata)
    
        # Add TMF as "Bond"
        df1 = pd.read_csv(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\TMF.csv', index_col=0, parse_dates=True)
        bonddata = bt.feeds.PandasData(dataname=df1,name="Bond",fromdate=fromdate, todate=todate, plot=False)
        cerebro.adddata(bonddata)    
        
        # add all the data files available in the directory datadir
        for fname in glob.glob(os.path.join(r'C:/Users/MMD/PycharmProjects/Trading/Data Mining/Data/data - Copy', '*')):
            df = pd.read_csv(fname, index_col=0, parse_dates=True)
    
            if len(df)>100:
                cerebro.adddata(bt.feeds.PandasData(dataname=df,name=os.path.basename(fname).replace(".csv", ""),fromdate=fromdate, todate=todate, plot=False))
                #print(os.path.basename(fname).replace(".csv", "")) #prints the name of the added csv file
                
                
    # 
    
    
        # add strategy
        cerebro.addstrategy(HoldAllStrategy, buy_date=datetime.date(2013, 3, 31))
    
        # set the cash, cheat on close and commission
        cerebro.broker.setcash(globalparams["cash"])
        cerebro.broker.set_coc(True)
        cerebro.broker.setcommission(commission=globalparams["commission"])
        
        # Adding Analysers
        cerebro.addanalyzer(btanal.PyFolio)                # Needed to use PyFolio
        cerebro.addanalyzer(btanal.TradeAnalyzer)          # Analyzes individual trades
        
        # If you want to have all data written into a log file
        #cerebro.addwriter(bt.WriterFile, csv=True, out='log.csv')
        
        cerebro.addobserver(bt.observers.Benchmark,
                            data=benchdata,
                            timeframe=bt.TimeFrame.NoTimeFrame)
        
        results = cerebro.run(stdstats=True, tradehistory=True)
        
        
    # <<<Performance analysing section section>>>
    
        cerebro.plot()
    
        # Basic performance evaluation ... final value ... minus starting cash
        pnl = cerebro.broker.get_value() - globalparams["cash"]
        print('Profit ... or Loss: {:.2f}'.format(pnl))
        
        '''
        # Quantstats thanks to https://algotrading101.com/learn/backtrader-for-backtesting/
        returns, positions, transactions, gross_lev = results[0].analyzers.pyfolio.get_pf_items()
        returns.index = returns.index.tz_convert(None)
        qs.reports.html(returns, output='stats.html', title='Momentum')
        webbrowser.open('stats.html')
        '''
        # Pyfolio if needed
        '''
        returns, positions, transactions, gross_lev = results[0].analyzers.pyfolio.get_pf_items()
        benchmark_rets = pd.Series([0.00004] * len(returns.index), index=returns.index)     
        pf.create_full_tear_sheet(returns, positions, transactions, benchmark_rets=benchmark_rets)
        '''
        
    # <<<Execute starting section>>>    
    if __name__ == '__main__':
        run()
    
    Buy Submitted 2016-06-01 SPY Price 209.84 Value 2308.24 Size 11 Cash 589.06 Broker 9972.98
    Buy Submitted 2016-06-01 Bond Price 23.46 Value 2369.71 Size 101 Cash 589.06 Broker 9972.98
    Buy Submitted 2016-06-01 AA_test_ANF Price 28.65 Value 2349.66 Size 82 Cash 589.06 Broker 9972.98
    Buy Submitted 2016-06-01 ALK Price 64.90 Value 2336.51 Size 36 Cash 589.06 Broker 9972.98
    Buy 2016-06-01 SPY Price 209.84 Value 2308.24 Size 11
    Buy 2016-06-01 Bond Price 23.46 Value 2369.71 Size 101
    Buy 2016-06-01 AA_test_ANF Price 28.65 Value 2349.66 Size 82
    Buy 2016-06-01 ALK Price 64.90 Value 2336.51 Size 36
    Sell Submitted 2016-06-02 Bond Price 23.76 Value -23.76 Size -1 Broker 10019.20
    Sell Submitted 2016-06-02 AA_test_ANF Price 28.65 Value -2349.66 Size -82 Broker 10019.20
    Sell 2016-06-02 Bond Price 23.76 Value 23.46 Size -1
    Sell 2016-06-02 AA_test_ANF Price 28.65 Value 2349.66 Size -82
    Sell Submitted 2016-06-03 Bond Price 24.28 Value -48.56 Size -2 Broker 10076.33
    Sell 2016-06-03 Bond Price 24.28 Value 46.92 Size -2
    ... post was too long...
    Sell 2020-06-12 Bond Price 40.71 Value 171.08 Size -5
    Buy Submitted 2020-06-15 Bond Price 39.63 Value 39.63 Size 1 Cash 7094.28 Broker 13303.45
    Buy 2020-06-15 Bond Price 39.63 Value 39.63 Size 1
    Buy Submitted 2020-06-17 Bond Price 37.97 Value 113.91 Size 3 Cash 6979.80 Broker 13234.54
    Buy 2020-06-17 Bond Price 37.97 Value 113.91 Size 3
    
    

    The weird part is the data:
    Bond and SPY both start ticking before 2010
    AA_test_ANF starts 2013-02-23
    ALK starts 2016-05-31

    So why does the trading start in 2016 and not in 2013?
    I checked the order or loading the data... AA_test_ANF get loaded before ALK.

    So what did i try next?

    class HoldAllStrategy(bt.Strategy):
        """
        HoldAll Strategy.
        Usually, used for benchmarking test.
        Almost same with the HoldStrategy, it tries to buy all provided securities with the same ratio.
        buy_date: iso-format str, buy order will be created the first market day after the buy_date.
        https://github.com/samuel281/qu-ant/blob/master/lib/strategies/hold_all_strategy.py
        """
        params = dict(
            buy_date=datetime.datetime.today().isoformat(),
        )
        
        def __init__(self):
            self.stocks = [i for i in self.getdatanames()] #must filter out bond and spy
            for d in self.stocks:
                self.dnames[d].lengthlist = [0]
            
    
        def prenext(self):
            '''
            if self.position:
                return
            '''
            if self.data.datetime.date(0).isoformat() < self.params.buy_date.isoformat(): #buydate must be determined by the first strategy, since it is the date of the first trade?
                return
            self.member = []
            self.member_sell = []
    
            for d in self.stocks:
                datad = self.dnames[d]
                datad.lengthlist.append(len(datad))
                posdata = [d for d, pos in self.getpositions().items() if pos]
                #print(len(datad))
                if len(datad) > 0:
                    if datad.lengthlist[-1] > datad.lengthlist[-2]:  
                        self.member.append(d)
                        print(self.data.datetime.date(0).isoformat(), datad.lengthlist[-1], datad.lengthlist[-2])
                    elif d in posdata and datad.lengthlist[-1] == datad.lengthlist[-2]:
                        self.member_sell.append(d)
                        print(d)
                        
        def nextstart(self):
            # This is called exactly ONCE, when next is 1st called and defaults to
            # call `next`
            self.member = []
            self.member_sell = []
            self.next()  # delegate the work to next
            
        def next(self):
            target_ratio = 1.0 - globalparams["reserve"]
            target_ratio_per_sec = target_ratio / len(self.member)
                
            posdata = [d for d, pos in self.getpositions().items() if pos]
            for d in self.member:
                if d in self.member and not d in posdata:
                    self.order_target_percent(data=self.getdatabyname(d), target=target_ratio_per_sec)
            for d in self.member_sell:
                self.order_target_percent(data=self.getdatabyname(d), target=0.0)
                
        
        def log(self, arg):
            print('{} {}'.format(self.datetime.date(), arg))            
                
        def on_order_executed(self, order):
            pass
    
        def notify_order(self, order):
            if order.status in [order.Accepted]:
                # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                return
            if order.status in [order.Submitted]:
                if order.isbuy():
    
                    dt, dn = self.datetime.date(), order.data._name
                    print('Buy {} {} {} Price {:.2f} Value {:.2f} Size {} Cash {:.2f} Broker {:.2f}'.format(
                            order.getstatusname(), dt, dn, order.created.price, order.created.size * order.created.price , order.created.size, self.broker.getcash(), self.broker.getvalue()))
                if order.issell():
                    dt, dn = self.datetime.date(), order.data._name
                    print('Sell {} {} {} Price {:.2f} Value {:.2f} Size {} Broker {:.2f}'.format(
                            order.getstatusname(), dt, dn, order.created.price, order.created.size * order.created.price, order.created.size, self.broker.getvalue()))
    
                # 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():
                    dt, dn = self.datetime.date(), order.data._name
                    print('Buy {} {} Price {:.2f} Value {:.2f} Size {}'.format(
                        dt, dn, order.executed.price, order.executed.value, order.executed.size))
    
                if order.issell():# Sell
                    dt, dn = self.datetime.date(), order.data._name
                    print('Sell {} {} Price {:.2f} Value {:.2f} Size {}'.format(
                        dt, dn, order.executed.price, order.executed.value, order.executed.size))
    
            elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                self.log('Order Canceled/Margin/Rejected')
    

    taken from here:
    https://community.backtrader.com/topic/1859/tracking-an-index-with-equal-weight-positions/6

    But it failed and I am now very stuck...

    the issue is still the same. how can I have a proper guard that allows only stocks for which there is data into the next level? And what how to implement it if one doesn't use next?

    Thanks a lot for any help in advance!
    @.@



  • Still stuck...
    I gave up the avenue I tried witht he HoldAllStrategy of the previous post.

    instead I tried to understand when and therefore where I have to filter out the stocks going to next().

    Strategy

    class Sur(bt.Strategy):
        params = dict(
                selcperc=0.10,  # percentage of stocks to select from the universe
                rperiod=1,  # period for the returns calculation, default 1 period
                vperiod=55,  # lookback period for volatility - default 36 periods
                mperiod=195,  # lookback period for momentum - default 90 periods
                momentum=Momentum, # parametrize the momentum and its period
                reserve=globalparams["reserve"],  # 5% reserve capital
                monthdays=[1],
                monthcarry=True,
                when=bt.timer.SESSION_START,
                benchmarkstop=False, # If true, no stocks will be bought and no rebalancing will be done if benchmark is below SMAperiod
                SMAperiod=200,
                benchmark_bond=True, # Sell all Stocks and buy Bonds
                jump_momentum=True, # If true, after a time of jump_one (30 days x jump_one) in every month, all the money will be directed to the best performing stock. Rule for that:
                                    # In Excel, this is a 0.6 x month return of fund with best past 3 month return plus 0.4 x return of fund with best return, month to date.
                jump_one=0.6,
                printlog=True,
            )
    
        def __init__(self):
            self.bench = self.data0
            self.bond = self.data1
            self.stocks = self.datas[2:]
            # calculate 1st the amount of stocks that will be selected
            self.selnum = int(len(self.stocks) * self.p.selcperc)
    
            # allocation perc per stock
            # reserve kept to make sure orders are not rejected due to
            # margin. Prices are calculated when known (close), but orders can only
            # be executed next day (opening price). Price can gap upwards
            self.perctarget = (1.0 - self.p.reserve) / self.selnum
            
            # This is the set up of the timer that makes the strategy being executed at the given time
            self.add_timer(
                when=self.p.when,
                monthdays=self.p.monthdays,
                monthcarry=self.p.monthcarry
            )
            
            self.stocks_len = []
            
            jump = True
    
            # returns, volatilities and momentums
            rs = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.stocks]
            vs = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rs]
            #ms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas]
            ms = [self.p.momentum(d, period=self.p.mperiod) for d in self.stocks]
            
            self.bench_sma = bt.ind.SMA(self.data0, period=self.p.SMAperiod)
            
            # simple rank formula: (momentum * net payout) / volatility
            # the highest ranked: low vol, large momentum, large payout
            self.ranks = {d: m / v for d, v, m in zip(self.stocks, vs, ms)}
            #TODO: does it perform better without the volatility?
    
            self.bench_filter = self.bench < self.bench_sma
    
    
        def log(self, arg):
            if self.p.printlog:
                print('{} {}'.format(self.datetime.date(), arg))
            
    
        # This is the function using the timer to execute the rebalance 
        def notify_timer(self, timer, when, *args, **kwargs):
            print('strategy notify_timer with tid {}, when {} _getminperstatus {}'.
                  format(timer.p.tid, when, int(self._getminperstatus())))
            print("timer")
            if self._getminperstatus() < 0:
                self.rebalance()
        
        def nextstart(self):
            self.ranks_filter = self.ranks
            print("nextstart")
            self.next()
            
        def prenext(self):
            self.stocks_len = [d for d in self.stocks if len(d)]
            self.ranks_filter = dict(zip(self.stocks_len, [self.ranks[k] for k in self.stocks_len]))        
            self.next()
            
        def next(self):
            print("next")
            pass # must be filled with a pass
    
        
        # Actual order giving by a ranking takes place here
        def rebalance(self):
            print("rebalance")
            #if jump == True:
            # Enter Jump Code here    
            
            # sort data and current rank
            ranks = sorted(
                self.ranks_filter.items(),  # get the (d, rank), pair
                key=lambda x: x[1][0],  # use rank (elem 1) and current time "0"
                reverse=True,  # highest ranked 1st ... please
            )
            
            # put top ranked in dict with data as key to test for presence
            rtop = dict(ranks[:self.selnum])
    
            # For logging purposes of stocks leaving the portfolio
            rbot = dict(ranks[self.selnum:])
    
            # prepare quick lookup list of stocks currently holding a position
            posdata = [d for d, pos in self.getpositions().items() if pos]
            
    
            if self.p.benchmarkstop:
                for d in (d for d in posdata):
                    if "Bond" == d._name and self.bench_filter:
                        return
                    else:
                        if "Bond" == d._name and not self.bench_filter:
                            self.order_target_percent("Bond", target=0.0)
                            self.log('Leave {} due to end of down period'.format(d._name))
                            return
            
            # Triple Momentum: If Benchmark index is below SMA, nothing will be bought or rebalanced
            if self.p.benchmarkstop:
                if self.bench_filter:
                    #print('SMA {} - Bench {}'.format(self.bench_sma[0], self.bench[0]))
                    if self.p.benchmark_bond:
                        for d in posdata:
                            self.log('Leave {} due to switch to Bonds'.format(d._name))
                            self.order_target_percent(d, target=0.0)
                        self.order_target_percent("Bond", target=0.95)
                        self.log('Buy Bond')
                        bond_flag = True
                        return #Code stops here and skips rebalancing und buying
    
            # remove those no longer top ranked
            # do this first to issue sell orders and free cash
            for d in (d for d in posdata if d not in rtop):
                self.log('Leave {} - Rank {:.2f}'.format(d._name, rbot[d][0]))
                self.order_target_percent(d, target=0.0)
            
            # rebalance those already top ranked and still there
            for d in (d for d in posdata if d in rtop):
                self.log('Rebal {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                del rtop[d]  # remove it, to simplify next iteration
    
            # issue a target order for the newly top ranked stocks
            # do this last, as this will generate buy orders consuming cash
            for d in rtop:
                self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                
        def stop(self):
            pnl = round(self.broker.getvalue() - globalparams["cash"],2)
            print('Final PnL: {}'.format(
                pnl))
    

    Error Message

    strategy notify_timer with tid 0, when 2014-11-03 00:00:00 _getminperstatus 199
    timer
    next
    
    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-7-8fb965d11696> in <module>
        312 # <<<Execute starting section>>>
        313 if __name__ == '__main__':
    --> 314     run()
    
    <ipython-input-7-8fb965d11696> in run(args)
        284                         timeframe=bt.TimeFrame.NoTimeFrame)
        285 
    --> 286     results = cerebro.run(maxcpus=1)#maxcpu=1 otherwise pickling multiprocessing errors
        287 
        288 # <<<Performance analysing section section>>>
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in run(self, **kwargs)
       1125             # let's skip process "spawning"
       1126             for iterstrat in iterstrats:
    -> 1127                 runstrat = self.runstrategies(iterstrat)
       1128                 self.runstrats.append(runstrat)
       1129                 if self._dooptimize:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata)
       1296                     self._runnext_old(runstrats)
       1297                 else:
    -> 1298                     self._runnext(runstrats)
       1299 
       1300             for strat in runstrats:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in _runnext(self, runstrats)
       1628                 self._check_timers(runstrats, dt0, cheat=False)
       1629                 for strat in runstrats:
    -> 1630                     strat._next()
       1631                     if self._event_stop:  # stop if requested
       1632                         return
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\strategy.py in _next(self)
        348 
        349         minperstatus = self._getminperstatus()
    --> 350         self._next_analyzers(minperstatus)
        351         self._next_observers(minperstatus)
        352 
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\strategy.py in _next_analyzers(self, minperstatus, once)
        386                 analyzer._nextstart()  # only called for the 1st value
        387             else:
    --> 388                 analyzer._prenext()
        389 
        390     def _settz(self, tz):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in _prenext(self)
        148     def _prenext(self):
        149         for child in self._children:
    --> 150             child._prenext()
        151 
        152         self.prenext()
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in _prenext(self)
        150             child._prenext()
        151 
    --> 152         self.prenext()
        153 
        154     def _notify_cashvalue(self, cash, value):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in prenext(self)
        227         The default behavior for an analyzer is to invoke ``next``
        228         '''
    --> 229         self.next()
        230 
        231     def nextstart(self):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzers\positions.py in next(self)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzers\positions.py in <listcomp>(.0)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\brokers\bbroker.py in get_value(self, datas, mkt, lever)
        413             return self._value if not lever else self._valuelever
        414 
    --> 415         return self._get_value(datas=datas, lever=lever)
        416 
        417     getvalue = get_value
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\brokers\bbroker.py in _get_value(self, datas, lever)
        437                 dvalue = comminfo.getvalue(position, data.close[0])
        438             else:
    --> 439                 dvalue = comminfo.getvaluesize(position.size, data.close[0])
        440 
        441             dunrealized = comminfo.profitandloss(position.size, position.price,
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\linebuffer.py in __getitem__(self, ago)
        161 
        162     def __getitem__(self, ago):
    --> 163         return self.array[self.idx + ago]
        164 
        165     def get(self, ago=0, size=1):
    
    IndexError: array index out of range
    
    

    So here I think the issue is something that doesn't have data gets into next.
    But since no prenext or nextstart is printed, I have no clue how to filter the inputs of next before next starts...



  • This is a wild guess. Try turning off your analyzers, in particular pyfolio.



  • @run-out
    Thank you for the idea. Unfortunately, it didn't help.
    I have the feeling that these code examples do not work well together^^:
    https://www.backtrader.com/blog/2019-05-20-momentum-strategy/momentum-strategy/
    https://www.backtrader.com/blog/2019-07-19-rebalancing-conservative/rebalancing-conservative/



  • @Jonny8 Did you get the same error message? Or a different one?



  • Current Strategy & Execution

    class Sur(bt.Strategy):
        params = dict(
                selcperc=0.10,  # percentage of stocks to select from the universe
                rperiod=1,  # period for the returns calculation, default 1 period
                vperiod=55,  # lookback period for volatility - default 36 periods
                mperiod=195,  # lookback period for momentum - default 90 periods
                momentum=Momentum, # parametrize the momentum and its period
                reserve=globalparams["reserve"],  # 5% reserve capital
                monthdays=[1],
                monthcarry=True,
                when=bt.timer.SESSION_START,
                benchmarkstop=False, # If true, no stocks will be bought and no rebalancing will be done if benchmark is below SMAperiod
                SMAperiod=200,
                benchmark_bond=True, # Sell all Stocks and buy Bonds
                jump_momentum=True, # If true, after a time of jump_one (30 days x jump_one) in every month, all the money will be directed to the best performing stock. Rule for that:
                                    # In Excel, this is a 0.6 x month return of fund with best past 3 month return plus 0.4 x return of fund with best return, month to date.
                jump_one=0.6,
                printlog=True,
            )
    
        def __init__(self):
            self.bench = self.data0
            self.bond = self.data1
            self.stocks = self.datas[2:]
            # calculate 1st the amount of stocks that will be selected
            self.selnum = int(len(self.stocks) * self.p.selcperc)
    
            # allocation perc per stock
            # reserve kept to make sure orders are not rejected due to
            # margin. Prices are calculated when known (close), but orders can only
            # be executed next day (opening price). Price can gap upwards
            self.perctarget = (1.0 - self.p.reserve) / self.selnum
            
            # This is the set up of the timer that makes the strategy being executed at the given time
            self.add_timer(
                when=self.p.when,
                monthdays=self.p.monthdays,
                monthcarry=self.p.monthcarry
            )
            
            self.stocks_len = []
            
            jump = True
    
            # returns, volatilities and momentums
            rs = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.stocks]
            vs = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rs]
            #ms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas]
            ms = [self.p.momentum(d, period=self.p.mperiod) for d in self.stocks]
            
            self.bench_sma = bt.ind.SMA(self.data0, period=self.p.SMAperiod)
            
            # simple rank formula: (momentum * net payout) / volatility
            # the highest ranked: low vol, large momentum, large payout
            self.ranks = {d: m / v for d, v, m in zip(self.stocks, vs, ms)}
            #TODO: does it perform better without the volatility?
    
            self.bench_filter = self.bench < self.bench_sma
    
    
        def log(self, arg):
            if self.p.printlog:
                print('{} {}'.format(self.datetime.date(), arg))
            
        
        # This is the function using the timer to execute the rebalance 
        def notify_timer(self, timer, when, *args, **kwargs):
            print('strategy notify_timer with tid {}, when {} _getminperstatus {}'.
                  format(timer.p.tid, when, int(self._getminperstatus())))
            print("timer")
            if self._getminperstatus() < 0:
                self.rebalance()
        
        def nextstart(self):
            self.ranks_filter = self.ranks
            print("nextstart")
            self.next()
            
        def prenext(self):
            self.stocks_len = [d for d in self.stocks if len(d)]
            self.ranks_filter = dict(zip(self.stocks_len, [self.ranks[k] for k in self.stocks_len]))        
            self.next()
            
        def next(self):
            print("next")
            pass # must be filled with a pass
    
        
        # Actual order giving by a ranking takes place here
        def rebalance(self):
            print("rebalance")
            #if jump == True:
            # Enter Jump Code here    
            
            # sort data and current rank
            ranks = sorted(
                self.ranks_filter.items(),  # get the (d, rank), pair
                key=lambda x: x[1][0],  # use rank (elem 1) and current time "0"
                reverse=True,  # highest ranked 1st ... please
            )
            
            # put top ranked in dict with data as key to test for presence
            rtop = dict(ranks[:self.selnum])
    
            # For logging purposes of stocks leaving the portfolio
            rbot = dict(ranks[self.selnum:])
    
            # prepare quick lookup list of stocks currently holding a position
            posdata = [d for d, pos in self.getpositions().items() if pos]
            
    
            if self.p.benchmarkstop:
                for d in (d for d in posdata):
                    if "Bond" == d._name and self.bench_filter:
                        return
                    else:
                        if "Bond" == d._name and not self.bench_filter:
                            self.order_target_percent("Bond", target=0.0)
                            self.log('Leave {} due to end of down period'.format(d._name))
                            return
            
            # Triple Momentum: If Benchmark index is below SMA, nothing will be bought or rebalanced
            if self.p.benchmarkstop:
                if self.bench_filter:
                    #print('SMA {} - Bench {}'.format(self.bench_sma[0], self.bench[0]))
                    if self.p.benchmark_bond:
                        for d in posdata:
                            self.log('Leave {} due to switch to Bonds'.format(d._name))
                            self.order_target_percent(d, target=0.0)
                        self.order_target_percent("Bond", target=0.95)
                        self.log('Buy Bond')
                        bond_flag = True
                        return #Code stops here and skips rebalancing und buying
    
            # remove those no longer top ranked
            # do this first to issue sell orders and free cash
            for d in (d for d in posdata if d not in rtop):
                self.log('Leave {} - Rank {:.2f}'.format(d._name, rbot[d][0]))
                self.order_target_percent(d, target=0.0)
            
            # rebalance those already top ranked and still there
            for d in (d for d in posdata if d in rtop):
                self.log('Rebal {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                del rtop[d]  # remove it, to simplify next iteration
    
            # issue a target order for the newly top ranked stocks
            # do this last, as this will generate buy orders consuming cash
            for d in rtop:
                self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                
        def stop(self):
            pnl = round(self.broker.getvalue() - globalparams["cash"],2)
            print('Final PnL: {}'.format(
                pnl))
    
    # Execution starts here
    
    def run(args=None):
        #optreturn=False otherwise the heatmap doesn't work
        cerebro = bt.Cerebro(maxcpus=1,
                             preload=False,
    		                 optdatas=False,
    		                 optreturn=False,
    		                 stdstats=True) 
    
        
    # <<<Data loading section>>>
        
        # Parse from/to-date
        fromdate = datetime.datetime(2014, 11, 3)
        todate = datetime.datetime(2020, 6, 18)
        
        # Add SPY/QQQ as "Benchmark"
        df0 = pd.read_csv(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\QQQ.csv', index_col=0, parse_dates=True)
        benchdata = bt.feeds.PandasData(dataname=df0,name="QQQ",fromdate=fromdate, todate=todate,  plot=False)
        cerebro.adddata(benchdata)
    
        # Add TMF as "Bond"
        df1 = pd.read_csv(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\TMF.csv', index_col=0, parse_dates=True)
        bonddata = bt.feeds.PandasData(dataname=df1,name="Bond",fromdate=fromdate, todate=todate, plot=False)
        cerebro.adddata(bonddata)    
        
        # add all the data files available in the directory datadir
        for fname in glob.glob(os.path.join(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\data', '*')):
            df = pd.read_csv(fname, index_col=0, parse_dates=True)
    
            if len(df)>200:
                cerebro.adddata(bt.feeds.PandasData(dataname=df,name=os.path.basename(fname).replace(".csv", ""),fromdate=fromdate, todate=todate, plot=False))
                #print(os.path.basename(fname).replace(".csv", "")) #prints the name of the added csv file
                
                
    # <<<Cerebro loading section>>>
    
    
        # Optimization by Optunity (usually partical swarm if i remember correctly)
        def runstrat(p1, p2):
            cerebro = bt.Cerebro(maxcpus=0,stdstats=True)
            cerebro.addstrategy(St, selcperc=p1, weeks_between=int(p2),printlog=False) #change the parameters that should be depicted in heatmap
            cerebro.broker.setcash(globalparams["cash"])
            cerebro.broker.setcommission(commission=globalparams["commission"])
            cerebro.adddata(benchdata)
            cerebro.adddata(bonddata)  
            for fname in glob.glob(os.path.join(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\Momentum', '*')):
                df = pd.read_csv(fname, index_col=0, parse_dates=True)
                if len(df)>200:
                    cerebro.adddata(bt.feeds.PandasData(dataname=df,name=os.path.basename(fname).replace(".csv", ""),fromdate=fromdate, todate=todate, plot=False))        
            
            cerebro.broker.set_coc(True)
            cerebro.run(maxcpus=0)
            return cerebro.broker.getvalue() #can be switched to whatever should be maximized/minimized
       
        #Either use Optunity for quick search of optimum
        if globalparams["optunity"]:
            opt = optunity.maximize(runstrat, num_evals=200, p1 = [1, 300], p2=[2, 100])
    
            optimal_pars, details, _ = opt
            print('Optimal Parameters:')
            print('maperiod1 = %.4f' % optimal_pars['p1'])
            print('maperiod2 = %.4f' % optimal_pars['p2'])
        
        
        # Heatmap showing how variables i = (y axis/ p1) and j = (x axis /p2) impact strategy outcome
        if globalparams["heatmap"]:
            results_list = []
            for i in np.arange(0.25, 0.75, 0.25):
                for j in np.arange(1, 9, 1):
                    PnL = runstrat(p1=i, p2=j)
                    results_list.append([i, j, i,PnL])
            my_heatmap(results_list)
        
        
        # add strategy
        if globalparams["optunity"]:
            cerebro.addstrategy(eval(globalparams["strategy"]), mperiod=int(optimal_pars['p1']), vperiod=int(optimal_pars['p2']))
        elif globalparams["strategy"] == "HSt":
            cerebro.addstrategy(HSt, buy_date=datetime.date(2015, 8, 31))
        else:    
            cerebro.addstrategy(eval(globalparams["strategy"]))
            
        
        # set the cash, cheat on close and commission
        cerebro.broker.setcash(globalparams["cash"])
        cerebro.broker.set_coc(True)
        cerebro.broker.setcommission(commission=globalparams["commission"])
        
        # Adding Analysers
        #cerebro.addanalyzer(bt.analyzers.SharpeRatio, riskfreerate=0.0, _name='sharpe')
        '''
        cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annual_return')
        cerebro.addanalyzer(CashMarket, _name='cashmarket')
        
        cerebro.addanalyzer(btanal.PyFolio)                # Needed to use PyFolio & Quanstat
        cerebro.addanalyzer(btanal.TradeAnalyzer)          # Analyzes individual trades
        
        
        
        # If you want to have all data written into a log file
        #cerebro.addwriter(bt.WriterFile, csv=True, out='log.csv')
        
        cerebro.addobserver(bt.observers.Benchmark,
                            data=benchdata,
                            timeframe=bt.TimeFrame.NoTimeFrame)
        '''
        results = cerebro.run(maxcpus=1)#maxcpu=1 otherwise pickling multiprocessing errors
        
    # <<<Performance analysing section section>>>
    
        cerebro.plot()
    
        # Basic performance evaluation ... final value ... minus starting cash
        pnl = cerebro.broker.get_value() - globalparams["cash"]
        print('Profit ... or Loss: {:.2f}'.format(pnl))
        '''
        # Quantstats thanks to https://algotrading101.com/learn/backtrader-for-backtesting/
        # Does not work with optstrategy
        
        returns, positions, transactions, gross_lev = results[0].analyzers.pyfolio.get_pf_items()
        returns.index = returns.index.tz_convert(None)
        qs.reports.html(returns, output='stats.html', title='Momentum '+ globalparams["strategy"])
        webbrowser.open('stats.html')
        '''
        
        # Pyfolio if needed
        '''
        returns, positions, transactions, gross_lev = results[0].analyzers.pyfolio.get_pf_items()
        benchmark_rets = pd.Series([0.00004] * len(returns.index), index=returns.index)     
        pf.create_full_tear_sheet(returns, positions, transactions, benchmark_rets=benchmark_rets)
        '''
        
    # <<<Execute starting section>>>    
    if __name__ == '__main__':
        run()
    

    Error Message with analyszers on:

    strategy notify_timer with tid 0, when 2014-11-03 00:00:00 _getminperstatus 199
    timer
    next
    
    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-7-e00561d472b3> in <module>
        324 # <<<Execute starting section>>>
        325 if __name__ == '__main__':
    --> 326     run()
    
    <ipython-input-7-e00561d472b3> in run(args)
        296                         timeframe=bt.TimeFrame.NoTimeFrame)
        297 
    --> 298     results = cerebro.run(maxcpus=1)#maxcpu=1 otherwise pickling multiprocessing errors
        299 
        300 # <<<Performance analysing section section>>>
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in run(self, **kwargs)
       1125             # let's skip process "spawning"
       1126             for iterstrat in iterstrats:
    -> 1127                 runstrat = self.runstrategies(iterstrat)
       1128                 self.runstrats.append(runstrat)
       1129                 if self._dooptimize:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata)
       1296                     self._runnext_old(runstrats)
       1297                 else:
    -> 1298                     self._runnext(runstrats)
       1299 
       1300             for strat in runstrats:
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\cerebro.py in _runnext(self, runstrats)
       1628                 self._check_timers(runstrats, dt0, cheat=False)
       1629                 for strat in runstrats:
    -> 1630                     strat._next()
       1631                     if self._event_stop:  # stop if requested
       1632                         return
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\strategy.py in _next(self)
        348 
        349         minperstatus = self._getminperstatus()
    --> 350         self._next_analyzers(minperstatus)
        351         self._next_observers(minperstatus)
        352 
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\strategy.py in _next_analyzers(self, minperstatus, once)
        386                 analyzer._nextstart()  # only called for the 1st value
        387             else:
    --> 388                 analyzer._prenext()
        389 
        390     def _settz(self, tz):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in _prenext(self)
        148     def _prenext(self):
        149         for child in self._children:
    --> 150             child._prenext()
        151 
        152         self.prenext()
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in _prenext(self)
        150             child._prenext()
        151 
    --> 152         self.prenext()
        153 
        154     def _notify_cashvalue(self, cash, value):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzer.py in prenext(self)
        227         The default behavior for an analyzer is to invoke ``next``
        228         '''
    --> 229         self.next()
        230 
        231     def nextstart(self):
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzers\positions.py in next(self)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\analyzers\positions.py in <listcomp>(.0)
         76 
         77     def next(self):
    ---> 78         pvals = [self.strategy.broker.get_value([d]) for d in self.datas]
         79         if self.p.cash:
         80             pvals.append(self.strategy.broker.get_cash())
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\brokers\bbroker.py in get_value(self, datas, mkt, lever)
        413             return self._value if not lever else self._valuelever
        414 
    --> 415         return self._get_value(datas=datas, lever=lever)
        416 
        417     getvalue = get_value
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\brokers\bbroker.py in _get_value(self, datas, lever)
        437                 dvalue = comminfo.getvalue(position, data.close[0])
        438             else:
    --> 439                 dvalue = comminfo.getvaluesize(position.size, data.close[0])
        440 
        441             dunrealized = comminfo.profitandloss(position.size, position.price,
    
    c:\users\mmd\appdata\local\programs\python\python36\lib\site-packages\backtrader\linebuffer.py in __getitem__(self, ago)
        161 
        162     def __getitem__(self, ago):
    --> 163         return self.array[self.idx + ago]
        164 
        165     def get(self, ago=0, size=1):
    
    IndexError: array index out of range
    
    

    Analyzers off:

    strategy notify_timer with tid 0, when 2014-11-03 00:00:00 _getminperstatus 199
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2014-12-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-01-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-02-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-03-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-04-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-05-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-06-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-07-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-08-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-09-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-10-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-11-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-12-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-01-04 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-02-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-03-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-04-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-05-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-06-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-07-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-08-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-09-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-10-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-11-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2016-12-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-01-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-02-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-03-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-04-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-05-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-06-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-07-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-08-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-09-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-10-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-11-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2017-12-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-01-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-02-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-03-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-04-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-05-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    
    next
    next
    strategy notify_timer with tid 0, when 2018-06-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-07-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-08-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-09-04 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-10-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-11-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2018-12-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-01-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-02-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-03-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-04-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-05-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-06-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-07-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-08-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-09-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-10-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-11-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2019-12-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-01-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-02-03 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-03-02 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-04-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-05-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2020-06-01 00:00:00 _getminperstatus 195
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    Final PnL: 0.0
    

    It is different but only because it doesn't do anything ...



  • Actually this was good news. You had two errors. The first you turned off, and as I suggest to you, was likely in pyfolio anaylzer. It's a bit sensitive to working well.

    Your second error is easy to see...

    @Jonny8 said in Used Timer only works (partially) with _getminperstatus() ?:

    if self._getminperstatus() < 0:
    self.rebalance()

    You can't run self.rebalance() under this condition since your self._getminperstatus() is always greater than zero.

    strategy notify_timer with tid 0, when 2014-12-01 00:00:00 _getminperstatus 195
    strategy notify_timer with tid 0, when 2015-01-02 00:00:00 _getminperstatus 195
    strategy notify_timer with tid 0, when 2015-02-02 00:00:00 _getminperstatus 195```


  • @run-out
    That I am aware of.
    However, I don't see how to get it fixed.
    The get min per status doesn't change much and to my knowledge if it is above 0 some data streams are not available for next. Hence I tried to filter out non available datas but failed in doing so?



  • @Jonny8 Just a general answer here overall.

    I built a similar algo over a year ago. The trouble with your set up is that backtrader needs all lines to be loaded up front with some sort of data from beginning to end. I was working with the S&P data and like you are experiencing, some stocks were available at different times.

    This creates endless index out of range since data lines won't be availabe at all times if they were delisted etc.

    To deal with this, do one of two things:

    1. using pandas, load all the csv files into one large dataframe, setup the dataframe so that you have dates in the index, and multi index columns [stockname, ohlcv]. This will allow you to now fillna() (or zeros, I can't remember) so that all stocks have filled entries for all time frames. Next unstack your columns and save to one csv.

    2. Alternatively, you can open each csv file and reindex to a full time frame index, fillna, and re-save each csv.

    Hope this helps. Let us know how you get on.



  • @run-out

    Thank you so much!
    I tried the second way... but somehow Backtrader has its issues with empty rows
    I converted the csvs as advised:

    import pandas as pd
    import glob, os, datetime
    pathh = r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\data/'
    idx = pd.date_range('2013-02-28', '2018-02-28')
    for fname in glob.glob(os.path.join(pathh, '*')):
        df = pd.read_csv(fname, index_col=0, parse_dates=True)
        df1 = df.reindex(idx,fill_value=float("nan"))
        df1.to_csv(r'C:\Users\MMD\PycharmProjects\Trading\Data Mining\Data\data2/' + os.path.basename(fname).replace(".csv", "") + '_1.csv')
        print(df1)
    

    however the above posted strategy led to weird results:

    1. lots of "nan"s
    2. it still started way later than I would expect it to start since a lot of data is complete at the end of Feb 2013.
    strategy notify_timer with tid 0, when 2014-11-03 00:00:00 _getminperstatus 199
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2014-12-01 00:00:00 _getminperstatus 180
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-01-01 00:00:00 _getminperstatus 159
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-02-01 00:00:00 _getminperstatus 139
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-03-01 00:00:00 _getminperstatus 120
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-04-01 00:00:00 _getminperstatus 97
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-05-01 00:00:00 _getminperstatus 76
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-06-01 00:00:00 _getminperstatus 56
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-07-01 00:00:00 _getminperstatus 34
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-08-01 00:00:00 _getminperstatus 13
    timer
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    nextstart
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-09-01 00:00:00 _getminperstatus -9
    timer
    rebalance
    2015-08-31 Enter AABA_1 - Rank nan
    2015-08-31 Enter AAL_1 - Rank nan
    2015-08-31 Enter AAPL_1 - Rank nan
    2015-08-31 Enter AAP_1 - Rank nan
    2015-08-31 Enter AA_1 - Rank nan
    2015-08-31 Enter ABBV_1 - Rank nan
    2015-08-31 Enter ABC_1 - Rank nan
    2015-08-31 Enter ABT_1 - Rank nan
    2015-08-31 Enter ACE_1 - Rank nan
    2015-08-31 Enter ACN_1 - Rank nan
    2015-08-31 Enter ADBE_1 - Rank nan
    2015-08-31 Enter ADI_1 - Rank nan
    2015-08-31 Enter ADM_1 - Rank nan
    2015-08-31 Enter ADP_1 - Rank nan
    2015-08-31 Enter ADSK_1 - Rank nan
    2015-08-31 Enter ADS_1 - Rank nan
    2015-08-31 Enter ADT_1 - Rank nan
    2015-08-31 Enter AEC_1 - Rank nan
    2015-08-31 Enter AEE_1 - Rank nan
    2015-08-31 Enter AEP_1 - Rank nan
    2015-08-31 Enter AES_1 - Rank nan
    2015-08-31 Enter AET_1 - Rank nan
    2015-08-31 Enter AFL_1 - Rank nan
    2015-08-31 Enter AGN_1 - Rank nan
    2015-08-31 Enter AIG_1 - Rank nan
    2015-08-31 Enter AIV_1 - Rank nan
    2015-08-31 Enter AIZ_1 - Rank nan
    2015-08-31 Enter AJG_1 - Rank nan
    2015-08-31 Enter AKAM_1 - Rank nan
    2015-08-31 Enter ALB_1 - Rank nan
    2015-08-31 Enter ALD_1 - Rank nan
    2015-08-31 Enter ALGN_1 - Rank nan
    2015-08-31 Enter ALK_1 - Rank nan
    2015-08-31 Enter ALLE_1 - Rank nan
    2015-08-31 Enter ALL_1 - Rank nan
    2015-08-31 Enter ALTR_1 - Rank nan
    2015-08-31 Enter ALXN_1 - Rank nan
    2015-08-31 Enter AMAT_1 - Rank nan
    2015-08-31 Enter AMD_1 - Rank nan
    2015-08-31 Enter AME_1 - Rank nan
    2015-08-31 Enter AMGN_1 - Rank nan
    2015-08-31 Enter AMG_1 - Rank nan
    2015-08-31 Enter AMP_1 - Rank nan
    2015-08-31 Enter AMT_1 - Rank nan
    2015-08-31 Enter AMZN_1 - Rank nan
    2015-08-31 Enter ANDV_1 - Rank nan
    2015-08-31 Enter ANF_1 - Rank nan
    2015-08-31 Enter ANSS_1 - Rank nan
    2015-08-31 Enter ANTM_1 - Rank nan
    2015-08-31 Enter AN_1 - Rank nan
    2015-08-31 Enter AON_1 - Rank nan
    2015-08-31 Enter AOS_1 - Rank nan
    2015-08-31 Enter APA_1 - Rank nan
    2015-08-31 Enter APC_1 - Rank nan
    2015-08-31 Enter APD_1 - Rank nan
    2015-08-31 Enter APH_1 - Rank nan
    2015-08-31 Enter APOL_1 - Rank nan
    2015-08-31 Enter APTV_1 - Rank nan
    2015-08-31 Enter ARE_1 - Rank nan
    2015-08-31 Enter ARG_1 - Rank nan
    2015-08-31 Enter ARNC_1 - Rank nan
    2015-08-31 Enter ATI_1 - Rank nan
    2015-08-31 Enter ATVI_1 - Rank nan
    2015-08-31 Enter AVB_1 - Rank nan
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-10-01 00:00:00 _getminperstatus -30
    timer
    rebalance
    2015-09-30 Enter AABA_1 - Rank nan
    2015-09-30 Enter AAL_1 - Rank nan
    2015-09-30 Enter AAPL_1 - Rank nan
    2015-09-30 Enter AAP_1 - Rank nan
    2015-09-30 Enter AA_1 - Rank nan
    2015-09-30 Enter ABBV_1 - Rank nan
    2015-09-30 Enter ABC_1 - Rank nan
    2015-09-30 Enter ABT_1 - Rank nan
    2015-09-30 Enter ACE_1 - Rank nan
    2015-09-30 Enter ACN_1 - Rank nan
    2015-09-30 Enter ADBE_1 - Rank nan
    2015-09-30 Enter ADI_1 - Rank nan
    2015-09-30 Enter ADM_1 - Rank nan
    2015-09-30 Enter ADP_1 - Rank nan
    2015-09-30 Enter ADSK_1 - Rank nan
    2015-09-30 Enter ADS_1 - Rank nan
    2015-09-30 Enter ADT_1 - Rank nan
    2015-09-30 Enter AEC_1 - Rank nan
    2015-09-30 Enter AEE_1 - Rank nan
    2015-09-30 Enter AEP_1 - Rank nan
    2015-09-30 Enter AES_1 - Rank nan
    2015-09-30 Enter AET_1 - Rank nan
    2015-09-30 Enter AFL_1 - Rank nan
    2015-09-30 Enter AGN_1 - Rank nan
    2015-09-30 Enter AIG_1 - Rank nan
    2015-09-30 Enter AIV_1 - Rank nan
    2015-09-30 Enter AIZ_1 - Rank nan
    2015-09-30 Enter AJG_1 - Rank nan
    2015-09-30 Enter AKAM_1 - Rank nan
    2015-09-30 Enter ALB_1 - Rank nan
    2015-09-30 Enter ALD_1 - Rank nan
    2015-09-30 Enter ALGN_1 - Rank nan
    2015-09-30 Enter ALK_1 - Rank nan
    2015-09-30 Enter ALLE_1 - Rank nan
    2015-09-30 Enter ALL_1 - Rank nan
    2015-09-30 Enter ALTR_1 - Rank nan
    2015-09-30 Enter ALXN_1 - Rank nan
    2015-09-30 Enter AMAT_1 - Rank nan
    2015-09-30 Enter AMD_1 - Rank nan
    2015-09-30 Enter AME_1 - Rank nan
    2015-09-30 Enter AMGN_1 - Rank nan
    2015-09-30 Enter AMG_1 - Rank nan
    2015-09-30 Enter AMP_1 - Rank nan
    2015-09-30 Enter AMT_1 - Rank nan
    2015-09-30 Enter AMZN_1 - Rank nan
    2015-09-30 Enter ANDV_1 - Rank nan
    2015-09-30 Enter ANF_1 - Rank nan
    2015-09-30 Enter ANSS_1 - Rank nan
    2015-09-30 Enter ANTM_1 - Rank nan
    2015-09-30 Enter AN_1 - Rank nan
    2015-09-30 Enter AON_1 - Rank nan
    2015-09-30 Enter AOS_1 - Rank nan
    2015-09-30 Enter APA_1 - Rank nan
    2015-09-30 Enter APC_1 - Rank nan
    2015-09-30 Enter APD_1 - Rank nan
    2015-09-30 Enter APH_1 - Rank nan
    2015-09-30 Enter APOL_1 - Rank nan
    2015-09-30 Enter APTV_1 - Rank nan
    2015-09-30 Enter ARE_1 - Rank nan
    2015-09-30 Enter ARG_1 - Rank nan
    2015-09-30 Enter ARNC_1 - Rank nan
    2015-09-30 Enter ATI_1 - Rank nan
    2015-09-30 Enter ATVI_1 - Rank nan
    2015-09-30 Enter AVB_1 - Rank nan
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-11-01 00:00:00 _getminperstatus -51
    timer
    rebalance
    2015-10-31 Enter AABA_1 - Rank nan
    2015-10-31 Enter AAL_1 - Rank nan
    2015-10-31 Enter AAPL_1 - Rank nan
    2015-10-31 Enter AAP_1 - Rank nan
    2015-10-31 Enter AA_1 - Rank nan
    2015-10-31 Enter ABBV_1 - Rank nan
    2015-10-31 Enter ABC_1 - Rank nan
    2015-10-31 Enter ABT_1 - Rank nan
    2015-10-31 Enter ACE_1 - Rank nan
    2015-10-31 Enter ACN_1 - Rank nan
    2015-10-31 Enter ADBE_1 - Rank nan
    2015-10-31 Enter ADI_1 - Rank nan
    2015-10-31 Enter ADM_1 - Rank nan
    2015-10-31 Enter ADP_1 - Rank nan
    2015-10-31 Enter ADSK_1 - Rank nan
    2015-10-31 Enter ADS_1 - Rank nan
    2015-10-31 Enter ADT_1 - Rank nan
    2015-10-31 Enter AEC_1 - Rank nan
    2015-10-31 Enter AEE_1 - Rank nan
    2015-10-31 Enter AEP_1 - Rank nan
    2015-10-31 Enter AES_1 - Rank nan
    2015-10-31 Enter AET_1 - Rank nan
    2015-10-31 Enter AFL_1 - Rank nan
    2015-10-31 Enter AGN_1 - Rank nan
    2015-10-31 Enter AIG_1 - Rank nan
    2015-10-31 Enter AIV_1 - Rank nan
    2015-10-31 Enter AIZ_1 - Rank nan
    2015-10-31 Enter AJG_1 - Rank nan
    2015-10-31 Enter AKAM_1 - Rank nan
    2015-10-31 Enter ALB_1 - Rank nan
    2015-10-31 Enter ALD_1 - Rank nan
    2015-10-31 Enter ALGN_1 - Rank nan
    2015-10-31 Enter ALK_1 - Rank nan
    2015-10-31 Enter ALLE_1 - Rank nan
    2015-10-31 Enter ALL_1 - Rank nan
    2015-10-31 Enter ALTR_1 - Rank nan
    2015-10-31 Enter ALXN_1 - Rank nan
    2015-10-31 Enter AMAT_1 - Rank nan
    2015-10-31 Enter AMD_1 - Rank nan
    2015-10-31 Enter AME_1 - Rank nan
    2015-10-31 Enter AMGN_1 - Rank nan
    2015-10-31 Enter AMG_1 - Rank nan
    2015-10-31 Enter AMP_1 - Rank nan
    2015-10-31 Enter AMT_1 - Rank nan
    2015-10-31 Enter AMZN_1 - Rank nan
    2015-10-31 Enter ANDV_1 - Rank nan
    2015-10-31 Enter ANF_1 - Rank nan
    2015-10-31 Enter ANSS_1 - Rank nan
    2015-10-31 Enter ANTM_1 - Rank nan
    2015-10-31 Enter AN_1 - Rank nan
    2015-10-31 Enter AON_1 - Rank nan
    2015-10-31 Enter AOS_1 - Rank nan
    2015-10-31 Enter APA_1 - Rank nan
    2015-10-31 Enter APC_1 - Rank nan
    2015-10-31 Enter APD_1 - Rank nan
    2015-10-31 Enter APH_1 - Rank nan
    2015-10-31 Enter APOL_1 - Rank nan
    2015-10-31 Enter APTV_1 - Rank nan
    2015-10-31 Enter ARE_1 - Rank nan
    2015-10-31 Enter ARG_1 - Rank nan
    2015-10-31 Enter ARNC_1 - Rank nan
    2015-10-31 Enter ATI_1 - Rank nan
    2015-10-31 Enter ATVI_1 - Rank nan
    2015-10-31 Enter AVB_1 - Rank nan
    
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    next
    strategy notify_timer with tid 0, when 2015-12-01 00:00:00 _getminperstatus -72
    timer
    rebalance
    2015-11-30 Enter AABA_1 - Rank nan
    2015-11-30 Enter AAL_1 - Rank nan
    2015-11-30 Enter AAPL_1 - Rank nan
    2015-11-30 Enter AAP_1 - Rank nan
    2015-11-30 Enter AA_1 - Rank nan
    2015-11-30 Enter ABBV_1 - Rank nan
    2015-11-30 Enter ABC_1 - Rank nan
    2015-11-30 Enter ABT_1 - Rank nan
    2015-11-30 Enter ACE_1 - Rank nan
    2015-11-30 Enter ACN_1 - Rank nan
    2015-11-30 Enter ADBE_1 - Rank nan
    2015-11-30 Enter ADI_1 - Rank nan
    2015-11-30 Enter ADM_1 - Rank nan
    2015-11-30 Enter ADP_1 - Rank nan
    2015-11-30 Enter ADSK_1 - Rank nan
    2015-11-30 Enter ADS_1 - Rank nan
    2015-11-30 Enter ADT_1 - Rank nan
    2015-11-30 Enter AEC_1 - Rank nan
    2015-11-30 Enter AEE_1 - Rank nan
    2015-11-30 Enter AEP_1 - Rank nan
    2015-11-30 Enter AES_1 - Rank nan
    2015-11-30 Enter AET_1 - Rank nan
    2015-11-30 Enter AFL_1 - Rank nan
    2015-11-30 Enter AGN_1 - Rank nan
    2015-11-30 Enter AIG_1 - Rank nan
    2015-11-30 Enter AIV_1 - Rank nan
    2015-11-30 Enter AIZ_1 - Rank nan
    2015-11-30 Enter AJG_1 - Rank nan
    2015-11-30 Enter AKAM_1 - Rank nan
    2015-11-30 Enter ALB_1 - Rank nan
    2015-11-30 Enter ALD_1 - Rank nan
    2015-11-30 Enter ALGN_1 - Rank nan
    2015-11-30 Enter ALK_1 - Rank nan
    2015-11-30 Enter ALLE_1 - Rank nan
    2015-11-30 Enter ALL_1 - Rank nan
    2015-11-30 Enter ALTR_1 - Rank nan
    2015-11-30 Enter ALXN_1 - Rank nan
    2015-11-30 Enter AMAT_1 - Rank nan
    2015-11-30 Enter AMD_1 - Rank nan
    2015-11-30 Enter AME_1 - Rank nan
    2015-11-30 Enter AMGN_1 - Rank nan
    2015-11-30 Enter AMG_1 - Rank nan
    2015-11-30 Enter AMP_1 - Rank nan
    2015-11-30 Enter AMT_1 - Rank nan
    2015-11-30 Enter AMZN_1 - Rank nan
    2015-11-30 Enter ANDV_1 - Rank nan
    2015-11-30 Enter ANF_1 - Rank nan
    2015-11-30 Enter ANSS_1 - Rank nan
    2015-11-30 Enter ANTM_1 - Rank nan
    2015-11-30 Enter AN_1 - Rank nan
    2015-11-30 Enter AON_1 - Rank nan
    2015-11-30 Enter AOS_1 - Rank nan
    2015-11-30 Enter APA_1 - Rank nan
    2015-11-30 Enter APC_1 - Rank nan
    2015-11-30 Enter APD_1 - Rank nan
    2015-11-30 Enter APH_1 - Rank nan
    2015-11-30 Enter APOL_1 - Rank nan
    2015-11-30 Enter APTV_1 - Rank nan
    2015-11-30 Enter ARE_1 - Rank nan
    2015-11-30 Enter ARG_1 - Rank nan
    2015-11-30 Enter ARNC_1 - Rank nan
    2015-11-30 Enter ATI_1 - Rank nan
    2015-11-30 Enter ATVI_1 - Rank nan
    2015-11-30 Enter AVB_1 - Rank nan
    next
    ...
    
    


  • Try filling with zeros.



});