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 genericDataBase
subclass example, which could be passed into strategy and later used asdata[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. -
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 thedatetime
rows like on the main datafeed. -
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 theearnings
data feed produces a valued. Because at that precise moment in time, the data feed meets its minimum period requirement (actually1
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.
-
Try running
cerebro
withrunonce=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.
- Wouldn't it be better to have those
-
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