The short answer is the ‘start’ and ‘end’ date formats are particular about being in ISO format - and I mean VERY particular. In the example above, the separator ‘T’ was omitted along with the seconds specification. Instead of the start date being start=‘2020-09-24 11:45-04:00’ it should be formatted start=‘2020-09-24T11:45:00-04:00’ (notice the ‘T’ and the ‘:00’ for seconds). So, the following will give the expected result
data = api.get_barset('AAPL',
'15Min',
start='2020-10-09T16:45:00-04:00',
end='2020-09-24T14:45:00-04:00',
)
Now a little longer explanation. The get_barset method unfortunately fails silently. If it encounters an error with either the ‘start’ or ‘end’ parameter (or ‘after’ and ‘until’), it simply uses the default datetimes, doesn’t tell anyone, and goes on its merry way. The default ‘start’ is None and the default ‘end’ is the current datetime. One other peculiarity with the get_barset method is that it begins with the ‘end’ datetime and works backwards. It counts the number of non-empty bars (note this may not be the same as elapsed bars if a stock didn’t trade during a bar). The method then truncates the results when either a) the number of bars specified by the ‘limit’ parameter is reached, or b) the datetime specified by the ‘start’ parameter is reached.
Now, to complicate things, the timezone offset from UTC is specified in the ISO format. The market time offset varies depending on whether it’s daylight saving time or not. It’s sometimes -04 and sometimes -05. For example, in January the market opens at 2020-01-02T09:30:00-05:00 but in October it opens at 2020-10-02T09:30:00-04:00.
Here’s what I do to ensure the ISO format and the timezone offset are correct. There are probably other (better) ways but this works.
import pytz
import datetime
market_timezone = pytz.timezone('America/New_York')
start_dt = datetime.datetime(2020, 1, 24, 11, 45)
start = market_timezone.localize(start_dt).isoformat()
end_dt = datetime.datetime(2020, 1, 24, 14, 45)
end = market_timezone.localize(end_dt).isoformat()
Don’t be tempted to do this
start_dt = datetime.datetime(2020, 1, 24, 11, 45, tzinfo=market_timezone)
For some rather esoteric reasons (in my mind a bug) adding the timezone info will look like it works but won’t always return the correct datatime.
Using the above values for ‘start’ and ‘end’ get_barset will return the expected data
data = api.get_barset('AAPL',
'15Min',
start=start,
end=end,
)
And of course, it’s not entirely that simple. The ‘end’ datetime will always be the last bar returned. However, since the results are limited by the ‘limit’ parameter, the first bar will be either the ‘start’ datetime or potentially sometime after that.
Hope that helps. (edited)