Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Pass dates to strategy

    General Code/Help
    2
    8
    2167
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Maxim Korobov
      Maxim Korobov last edited by Maxim Korobov

      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.

      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

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

        1 Reply Last reply Reply Quote 0
        • Maxim Korobov
          Maxim Korobov last edited by

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

          1 Reply Last reply Reply Quote 0
          • Maxim Korobov
            Maxim Korobov last edited by Maxim Korobov

            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.

            1 Reply Last reply Reply Quote 0
            • B
              backtrader administrators last edited by

              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)

              1 Reply Last reply Reply Quote 0
              • Maxim Korobov
                Maxim Korobov last edited by Maxim Korobov

                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.

                1 Reply Last reply Reply Quote 0
                • B
                  backtrader administrators last edited by backtrader

                  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.

                  1 Reply Last reply Reply Quote 0
                  • Maxim Korobov
                    Maxim Korobov last edited by Maxim Korobov

                    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
                    1 Reply Last reply Reply Quote 0
                    • 1 / 1
                    • First post
                      Last post
                    Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                    $(document).ready(function () { app.coldLoad(); }); }