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 ?



  • if your market close is always 16:00, you could do something like this at the top your "next" function:
    if self.datas[0].datetime.time(0) < datetime.time(15, 30):
    return

    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[0].datetime.time(0) >= datetime.time(15, 30):
    self.buy(self.datas[0])

    either way you would need add some logic so you are not sending order after order


  • administrators

    There is a little not so well known functionality to simplify the comparison. Assuming you operate on something which closes at 16:00 in 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[0]
                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.



  • @Ed-Bartosh
    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


  • administrators

    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?

    Sure: https://www.wallstreetdaily.com/nyse-stock-market-holiday-closings-schedule/

    pandas_market_calendars shows it this way:

    In [1]: from datetime import date
    
    In [2]: from pandas_market_calendars import get_calendar
    
    In [3]: nyse = get_calendar('NYSE')
    
    In [4]: nyse.early_closes(nyse.schedule(start_date=date(2016, 1, 1), end_date=date(2017, 12, 31)))
    Out[4]: 
                             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
    

  • administrators

    You seem to be using this:

    Which is a Python 3 only package, or at least can only be installed directly with pip under 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 calendar parameter to the construction of data feeds
    • If a calendar is present, do a continuous adjustment of the self.p.sessionend (and self.p.sessionstart) parameters

    Such an approach would (without deeping looking into it) theoretically transparently integrate into backtrader.

    A package like pandas_market_calendars would be wrapped to convert the pandas.Timestamps to datetime.datetime instances, adjusted to the exchange local time, if a timezone has 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[0] = self.curbeos
    

    And later in the strategy is simply about comparing self.data.datetime with self.beosindicator

        if self.data.datetime == self.beosindicator:
    


  • That sounds great! Any chance to have it implemented/added to TODO list?


  • administrators

    The idea is always to have a generic model, like it is the case with the timezones, in which you may pass pytz instances or something that, more or less, complies to the interface of pytz.

    A similar approach will be taken.


Log in to reply
 

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