Pass dates to strategy



  • My idea now is to pass earning dates (plus day before than and two after) of particular company into strategy to avoid any trading in that high volatility dates.

    Dates were taken from the public source. So I should pass list of dates into strategy. Note that there is only date column, no OLHC data. Could you please show generic DataBase subclass example, which could be passed into strategy and later used as data[x]?

    Filter looks simpler, but currently the idea isn't proved, maybe it's better to reverse it and trade on earning days only :) . So earning dates could be used in strategy. Also note that length of earning days list is smaller that main data.


  • administrators

    You need to use linesoverride. See: Blog - Escape from OHLC Land



  • What if data is in operating memory, not in csv file on disk?



  • Something like this:

    class EarningFeed(feed.DataBase):
    	linesoverride = True
    	lines = ('earning_date', 'datetime')
    
    	def __init__(self, earning_dates):
    		super().__init__()
    		self.earning_dates = earning_dates
    		self._idx = 0
    
    	def start(self):
    		super().start()
    
    	def _load(self):
    		self._idx += 1
    
    		if self._idx >= len(self.earning_dates):
    			return False
    
    		self.lines.earning_date[0] = date2num(self.earning_dates[0])
    		self.lines.datetime[0] = date2num(self.earning_dates[0])
    
    		return True
    

    One issue I stucked on is cerebro run - it stops too early. Seem like it want all the datetime rows like on the main datafeed.


  • administrators

    Without knowing what too early actually implies/means in that context, the problem with your data feed is that it only delivers something at fixed points in time.

    And without having put it to the test, the first time your strategy's next is called will be the 1st time that the earnings data feed produces a valued. Because at that precise moment in time, the data feed meets its minimum period requirement (actually 1 for data feeds)



  • Roger.

    Fixed by adding fake datetimes from the start data date parameters, which is first date in main data feed:

    class EarningFeed(feed.DataBase):
        linesoverride = True
        lines = ('earning_date', 'datetime')
    
        def __init__(self, earning_dates, start_data_date):
            super().__init__()
            self.start_data_date = start_data_date
            self.earning_dates = earning_dates
            self.idx = 0
    
        def start(self):
            super().start()
    
        def _load(self):
            self.idx += 1
    
            if self.idx >= len(self.earning_dates):
                return False
    
            date = self.start_data_date + dt.timedelta(days=self.idx)
            self.lines.datetime[0] = date2num(date)
            self.lines.earning_date[0] = date2num(self.earning_dates[self.idx])
    
            return True
    

    Next issue is plotting data. Seems like one should provide Y data:

    Traceback (most recent call last):
    ...
      File "C:\Users\Home\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 659, in plot
    	start=start, end=end)
      File "C:\Users\Home\Anaconda3\lib\site-packages\backtrader\plot\plot.py", line 205, in plot
    	self.plotdata(data, self.dplotsover[data])
      File "C:\Users\Home\Anaconda3\lib\site-packages\backtrader\plot\plot.py", line 625, in plotdata
    	color=color, label=datalabel)
      File "C:\Users\Home\Anaconda3\lib\site-packages\backtrader\plot\finance.py", line 594, in plot_lineonclose
    	**kwargs)
      File "C:\Users\Home\Anaconda3\lib\site-packages\backtrader\plot\finance.py", line 534, in __init__
    	ax.add_line(self.loc)
      File "C:\Users\Home\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 1787, in add_line
    	self._update_line_limits(line)
      File "C:\Users\Home\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 1809, in _update_line_limits
    	path = line.get_path()
      File "C:\Users\Home\Anaconda3\lib\site-packages\matplotlib\lines.py", line 989, in get_path
    	self.recache()
      File "C:\Users\Home\Anaconda3\lib\site-packages\matplotlib\lines.py", line 696, in recache
    	raise RuntimeError('xdata and ydata must be the same length')
    RuntimeError: xdata and ydata must be the same length
    

    Hope to solve this tomorrow.


  • administrators

    Try running cerebro with runonce=False.

    In any case and without knowing the use case in detail and seeing that the earning_dates seem to already be in a preprocessed array.

    • Wouldn't it be better to have those earnings as an indicator applied to the data feed?

    With that approach you'd only need to do something like this in next:

    if self.data.datetime[0] == self.earning_dates[self._idx]:  # here earning_dates already contains date2num'd timestamps
        do_something()
        self.lines.mylinename[0] = 1.0  # for example, any other value
        self._idx += 1  # update index
    

    And that would automatically plot synchronized with the target data feed.



  • Thanks for advice and overall help. It was easy to build and use indicator.

    Final result (contains references to external code - main project):

    import backtrader as bt
    from backtrader import num2date
    
    from main.lab.data.earning_dates import EarningDates
    
    
    class EarningIndicator(bt.Indicator):
    
    	params = (
    		("earning", None),
    		("skip_before", 1),
    		("skip_after", 2),
    	)
    
    	lines = ("earning_period",)
    
    	def __init__(self, *args, **kwargs):
    		super().__init__(*args, **kwargs)
    
    		self.skip_days = []
    
    		a = EarningDates(0, self.params.earning, self.params.skip_before, self.params.skip_after)
    
    		self.skip_days = a.get_skip_dates()
    
    	def next(self):
    		current_date = num2date(self.data.datetime[0]).date()
    		if current_date in self.skip_days:
    			self.lines.earning_period[0] = 1.0
    		else:
    			self.lines.earning_period[0] = 0

Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.