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

Timer monthday reports trading on days prior to target



  • Trying a fairly boilerplate application of the timer, rebalancing and carrying on the 15th of every quarter. My issue is that trades are being made on the 14th and occasionally the 12th or 13th, never the 15th. What's going on here?

    class St(bt.Strategy):
        params = (
            ('topn', 10),
            ('perctarget', 0.10),
            ('timer', True),
            ('when', bt.timer.SESSION_START),
            ('monthdays', [15]),
            ('monthcarry', True),
            ('cheat', True),
    
        def __init__(self):
            self.ranks = [data: data.ranking for data in self.datas]
            self.rtop = dict()
            self.rbot = dict()
            if self.p.timer:
                self.add_timer(
                    when=self.p.when,
                    monthdays=self.p.monthdays,
                    monthcarry=self.p.monthcarry,
                    cheat=self.p.cheat,
                    )
    
        def next(self):
            self.ranks_sorted = sorted(
                ranks.items(),
                key=lambda x: x[1][0],
                reverse=True,
            )
                    
            self.rtop = dict(self.ranks_sorted[:self.topn])
            self.rbot = dict(self.ranks_sorted[self.topn:])
    
        def notify_timer(self, timer, when, *args, **kwargs):
            date = self.datetime.date()
            if date.month in [3, 6, 9, 12]:
                        
                posdata = [d for d, pos in self.getpositions().items() if pos]
    
                #self.rbot[d][0][1]
                # Sell off old rank n
                for d in (d for d in posdata if d not in self.rtop):
                    self.log('Exit {} - Rank {:.2f}'.format(d._name, self.rbot[d][0]))
                    self.order_target_percent(d, target=0.0)
    
                for d in (d for d in posdata if d in self.rtop):
                    self.log('Rebal {} - Rank {:.2f}'.format(d._name, self.rtop[d][0]))
                    self.order_target_percent(d, target=self.p.perctarget)
                    del self.rtop[d]
    
                for d in self.rtop:
                    self.log('Enter {} - Rank {:.2f}'.format(d._name, self.rtop[d][0]))
                    self.order_target_percent(d, target=self.p.perctarget)
    
    

    Resulting output:
    Screen Shot 2020-10-19 at 12.55.07 AM.png



  • I'm not very experienced with timers but here's what I think might be happening:

    Since you have cheat =True, it uses the data from the previous day.

    2015-03-15 was a sunday, so it uses friday's data.
    06-15 was a monday, again using friday's data.
    09-15 was a tuesday so using monday's data..



  • Unfortunately that's not it; the same trading days are reported regardless of cheat.



  • Could you please share the code for your log method? It seems you are printing the date from the first data only - right ?



  • The logging method is the very basic one used in the sample rebalancing article.

        def log(self, arg):
            print('{} {}'.format(self.datetime.date(), arg))
    
    


  • Could you log the when argument to the notify_timer instead of the date reported by the first data. Will it still print the same dates ?

    as a reference, I was running the following test:

    import os
    import backtrader as bt
    
    class TestStrategy(bt.Strategy):
        def __init__(self):
            self.add_timer( 
                when=bt.timer.SESSION_START, 
                monthdays=[15], 
                monthcarry=True, 
                cheat=True)
    
        def notify_timer(self, timer, when, *args, **kwargs):
            print(f'Data time: {self.datas[0].datetime.date()}. When: {when}')
    
    def runstrat():
        cerebro = bt.Cerebro()
        datapath = os.path.join(
            bt.__file__, 
            '../../datas/yhoo-1996-2015.txt')
        data = bt.feeds.GenericCSVData( 
            dataname=datapath, 
            dtformat='%Y-%m-%d')
        cerebro.adddata(data)
        cerebro.addstrategy(TestStrategy)
        cerebro.run()
    
    if __name__ == '__main__':
        runstrat()
    

    and I've got the different reported dates:

    ...
    Data time: 2015-01-15. When: 2015-01-15 00:00:00
    Data time: 2015-02-17. When: 2015-02-17 00:00:00
    Data time: 2015-03-16. When: 2015-03-16 00:00:00
    Data time: 2015-04-15. When: 2015-04-15 00:00:00
    Data time: 2015-05-15. When: 2015-05-15 00:00:00
    Data time: 2015-06-15. When: 2015-06-15 00:00:00
    Data time: 2015-07-15. When: 2015-07-15 00:00:00
    Data time: 2015-08-17. When: 2015-08-17 00:00:00
    Data time: 2015-09-15. When: 2015-09-15 00:00:00
    Data time: 2015-10-15. When: 2015-10-15 00:00:00
    Data time: 2015-11-16. When: 2015-11-16 00:00:00
    Data time: 2015-12-15. When: 2015-12-15 00:00:00
    


  • No, both self.data[0].datetime.date() and when log correctly. Thanks.

    Screen Shot 2020-10-26 at 10.10.08 AM.png

    The issue was printing from self.datetime.date() - not sure why there's a discrepancy?


Log in to reply
 

});