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:
-
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 thenotify_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.
The issue was printing from self.datetime.date() - not sure why there's a discrepancy?