I would like to be able to programatically detect the last bar / day of a backtest so I can generate a summary report (via the log api) on that day
is there any way I can detect this?
I would like to be able to programatically detect the last bar / day of a backtest so I can generate a summary report (via the log api) on that day
is there any way I can detect this?
Hi Jason,
I gather that you would prefer not to enter the ending bar datetime stamp manually? This would work but is awkward.
I've attached code that sorta solves the problem. The assumption here is that end_date = context.spy.security_end_date will provide the most recent trading date for SPY, advanced by one trading day. Then, if your backtest ends on a typical Mon. through Thurs. (market open and no early close), you can detect the last call to handle_data. I think that the more general case can be coded, as well, but I have to dig into https://github.com/quantopian/zipline/blob/master/zipline/utils/tradingcalendar.py.
Quantopian folks, it would be handy if security_end_date actually returned the date for the last trade data available to the backtest algorithm. Why is it advanced by one trading day? Is this for compatibility with live trading?
Grant
from datetime import timedelta
def initialize(context):
context.spy = sid(8554)
end_date = context.spy.security_end_date
context.last_date = end_date - timedelta(days=1)
print context.last_date
def handle_data(context, data):
if get_datetime() == context.last_date:
print 'last call to handle_data'
Thanks for the suggestion Grant! I will give this a try. Just looking at the code though, it seems a bit strange that it would work? I though security_end_date was for the current bar (if the security isn't delisted ) so really seems strange that should be detectable as the end date....
also, I am assuming this only works in daily mode? I do all my work in minute mode so I will give this a try to verify, then dig through tradigncalendar.py and try to figure out a solution as you suggest.
Grant,
Firstly, I am a big fan - thank you so much for your contributions to this forum.
However, I can't seem to get your code to do what I think is intended. Context.last_date always ends up being one day before the security_end_date without regard to the backtester dates. So it will only print 'last call to handle_data' if the backtester end date is set to the most recent (ie today's) date. I thought the timedelta function would somehow magically calculate the delta of the security_end_date and the backtester end-date so then context.last_date would be the last backtesting date. Am i misunderstanding the point of the thing?
Currently, I manually set a date to run final performance metrics. In practice this means I do every backtest twice - the first time just to realize that i forgot to set the final date in the code. Any help would be great appreciated!
Hello Robby,
The assumption here is that you'll be running the backtest up to the most recent date for which data are available. As you can see from the attached backtest, sometimes the value of 'days' in timedelta(days=3) will need to be adjusted upward, when the security_end_date is advanced by more than one calendar day (e.g. the backtest ends on a Friday).
This is not ideal, and buried within the backtester is the datetime stamp of the last bar (daily/minute). If this could be accessed, then testing for the last call to handle_data would be straightforward.
The code here should work, so long as you tweak the 'days' value. For minute bars, it'd have to be modified to include the last minute bar datetime stamp. If you need this, just let me know.
Grant
from datetime import timedelta
def initialize(context):
context.spy = sid(8554)
end_date = context.spy.security_end_date
context.last_date = end_date - timedelta(days=3) # adjust value of days
print 'context.last_date = ' + str(context.last_date)
def handle_data(context, data):
print get_datetime()
if get_datetime() == context.last_date:
print 'last call to handle_data'