Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
how to detect the last bar of a backtest? (for generating a summary report)

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?

6 responses

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'  

Thanks to Grant's revelation of the strange (maybe just unexpected?) output from the "dir" command in another thread, I think I solved this problem for you. It uses a regex to grab the last date set in the simulation. It then looks up this date in the zipline utilities to find the closing time.

Hey great! works like a charm. Thx.