Submit order 30 minutes before market close
My strategy includes submitting orders at 30 minutes before market close. How to achieve it in backtester? Is there some scheduling functionality similar to schedule_function ?
Brad Lloyd last edited by
if your market close is always 16:00, you could do something like this at the top your "next" function:
if self.datas.datetime.time(0) < datetime.time(15, 30):
then nothing happens until after 15:30
but if you are processing signals intraday then you can just put your order statements inside of this if statement
if self.datas.datetime.time(0) >= datetime.time(15, 30):
either way you would need add some logic so you are not sending order after order
There is a little not so well known functionality to simplify the comparison. Assuming you operate on something which closes at
16:00in the local trading time.
class MyStrategy(bt.Strategy): def next(self): if self.data.datetime == datetime.time(15, 30): do_something_here()
This can even be packed as an indicator (and hence as a signal):
class TimeSignal(bt.Indicator): lines = ('mytime',) params = (('when', datetime.time(15, 30),) def __init__(self): self.lines.mytime = (self.data.datetime == self.p.when)
Which can then be used in your strategy as:
class MyStrategy(bt.Strategy): def __init__(self): self.timesignal = TimeSignal() def next(self): if self.timesignal: # equivalent to if self.timesignal do_something_here()
In any case the scheduling of functions seems to be a sought topic (someone also wanted a post-market scheduled function call)
@Brad-Lloyd I'm trading US stock market. It's not always closes at 16:00, I'm afraid.
Brad Lloyd last edited by
the bulk of the time you have 16:00 as you close, 16:15 for some of the index ETFs,
you can download the exchange calendars and then put the holidays in where you early close
if you have some timezone issues then try using pytz to manage that, I think there is some functionality in backtrader for it
another option would be to count minutes from the first trade of the day, but you still have to manage the holidays
How do closing times look like? Do you have a couple of examples?
@Brad-Lloyd The main issue with this is caused by early closes. I ended up using pandas_market_calendars to detect them:
import backtester as bt from pandas_market_calendars import get_calendar class Strategy(bt.Strategy): def __init__(self): calendar = get_calendar('NYSE') schedule = calendar.schedule(start_date=self.p.start_date, end_date=self.p.end_date) self.early_closes = calendar.early_closes(schedule).index ... def eod(self): """ Calculate time of eod actions. """ if self.data0.datetime.date() in self.early_closes: return datetime.time(12, 30) else: return datetime.time(15, 30) ... def next(self): ... if self.data0.datetime.time() >= self.eod(): self.eod_actions() return ...
Just wondering if backtester has better way to do it and I missed it.
@backtrader > How do closing times look like? Do you have a couple of examples?
pandas_market_calendars shows it this way:
In : from datetime import date In : from pandas_market_calendars import get_calendar In : nyse = get_calendar('NYSE') In : nyse.early_closes(nyse.schedule(start_date=date(2016, 1, 1), end_date=date(2017, 12, 31))) Out: market_open market_close 2016-11-25 2016-11-25 14:30:00+00:00 2016-11-25 18:00:00+00:00 2017-07-03 2017-07-03 13:30:00+00:00 2017-07-03 17:00:00+00:00 2017-11-24 2017-11-24 14:30:00+00:00 2017-11-24 18:00:00+00:00
You seem to be using this:
Which is a Python 3 only package, or at least can only be installed directly with
pipunder Python 3
The introduction of a trading calendar has been discussed, specifically when dealing with live data and the need to deliver a resampled daily bar in sync with the latest minute bar which closes the day.
A potential usage pattern could be:
- Adding a
calendarparameter to the construction of data feeds
- If a calendar is present, do a continuous adjustment of the
Such an approach would (without deeping looking into it) theoretically transparently integrate into backtrader.
A package like
pandas_market_calendarswould be wrapped to convert the
datetime.datetimeinstances, adjusted to the exchange local time, if a
timezonehas been provided to the data feed (or one has been learnt like in the case of Interactive Brokers)
Your code could be simplified to:
dnow = self.data.datetime.date().isoformat() schedule = self.calendar.schedule(start_date=dnow, end_date=dnow).tz_convert(self.calendar.tz) eos = schedule.iloc[0, 1].tz_convert(tz=self.calendar.tz).to_datetime().time()
You can even pack that in an indicator again:
class BeforeEoS(self): lines = ('beos',) params = ( ('exchange', 'NYSE'), ('before', 30), # in minutes ) def __init__(self): self.calendar = pandas_market_calendars.get_calendar(self.p.exchange) self.tdbefore = datetime.timedelta(minutes=self.p.before) self.lastdt = datetime.date.min def next(self): curdate = self.data.datetime.date() if curdate > self.lastdt: self.lastdt = curdate dnow = curdate.isoformat() schedule = self.calendar.schedule(start_date=dnow, end_date=dnow).tz_convert(self.calendar.tz) cureos = schedule.iloc[0, 1].tz_convert(tz=self.calendar.tz).to_datetime() curbeos = cureos - self.tdbefore self.curbeos = self.data.date2num(curbeos) self.lines.beos = self.curbeos
And later in the strategy is simply about comparing self.data.datetime with self.beosindicator
if self.data.datetime == self.beosindicator:
- Adding a
That sounds great! Any chance to have it implemented/added to TODO list?
The idea is always to have a generic model, like it is the case with the timezones, in which you may pass
pytzinstances or something that, more or less, complies to the interface of
A similar approach will be taken.