Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Print an array after the backtest completes

Hi

I'm trying to print an array of data collected after the backtest has completed. Basically I'm trying to create a price to volume histogram and trying in an associative array. I would like to print the results after the backtest has completed. Is there any way to print this array 'once' after the backtest has completed?

Thanks!

9 responses

In the code I've written over the last 20 years I've always strived to create symmetry. With every Start there is a Stop; with every Connect there is a Disconnect. And with every Initialize there is a Deinitialize (or Terminate or Completed or something!) But alas, here, symmetry seems a luxury oft overlooked.

A recourse is to play date match; when you reach a terminal date stamp - ding! You have a Test Complete opportunity.

def initialize(context):  
    context.CompletedDate = datetime.date(2015,4,1) #Pick your end date here  
def handle_data(context, data):  
    if (get_datetime().date() == context.CompletedDate):  
        PrintArrayHere()  

You can't rely upon "sid(12345).security_end_date" as you may not be driving your test through to the end of the time series. Why Q can't provide a TestCompleted event (there have been numerous requests for it...) we'll never know.

A more extravagant version to log some info when done, right now just prints elapsed time, add your array.
At logging limit, try loop, printing in smaller chunks.

def handle_data(context, data):  
    wrap_up(context, data)

def wrap_up(context, data):  
    '''  
    Output stuff on the last bar/frame of the run.  
    '''  
    import datetime as _dt # Presumably Python won't bother trying to import twice.  
    import pytz as _pytz   # Underscore since has to be unique to not collide  
    import time as _time   #   in case these were already set in someone's algo.

    if 'wrapup' not in context:  
        w = context.wrapup = {}  
        w['my_tz'] = 'US/Eastern'      # You can change to your own timezone  
        w['elapsed_start'] = _time.time()  
        env = get_environment('*')  
        w['last_trading_date'] = str(env['end'].date())  
        w['last_trading_time'] = str(env['end'].time())  
        w['mode'] = env['data_frequency']    # daily or minute

    w = context.wrapup  
    bar_dt = get_datetime()  
    last_bar_now = 0  
    # Flag for output if last bar now  
    if w['last_trading_date'] == str(bar_dt.date()):  
        if w['mode'] == 'daily':  
            last_bar_now = 1  
        elif w['mode'] == 'minute' \  
          and w['last_trading_time'] == str(bar_dt.time()):  
            log.info('Algo time: ' + str(bar_dt.time()))  
            last_bar_now = 1

    if last_bar_now:  
        elapsed = (_time.time() - w['elapsed_start']) / 60  # minutes  
        log.info( '\nRuntime {} hr {} min    End: {} {}'.format(  
            int(elapsed / 60), '%.1f' % (elapsed % 60),  
            _dt.datetime.now(_pytz.timezone(w['my_tz'])).strftime("%Y-%m-%d %H:%M"),  
            w['my_tz']      # Can change my_tz to your own timezone above.  
        ))

        log.info('Your content here')  

Thanks for the replies! I can workaround using the approach you suggested. However, as you pointed out, a handleComplete() method would have been great indeed.

@ Market Tech,

The ways of the Q are mysterious, indeed. From the research platform, we have:

get_backtest?

Type:        function  
String form: <function get_backtest at 0x7fc29f6542a8>  
File:        /home/qexec/src/qexec_repo/qexec/research/api.py  
Definition:  get_backtest(backtest_id)  
Docstring:   Get a backtest  

and

result = get_backtest('536a6d181a4f090716c383b7')

print "Scalars:"  
print result.scalars  
print ""  
print "Frames:"  
print result.frames  
print ""  
print "All Attributes:"  
print result.attrs


Scalars:  
['benchmark_security', 'capital_base', 'end_date', 'start_date']

Frames:  
['cumulative_performance', 'daily_performance', 'orders', 'positions', 'recorded_vars', 'risk', 'transactions']

All Attributes:  
['cumulative_performance', 'daily_performance', 'orders', 'positions', 'recorded_vars', 'risk', 'transactions', 'benchmark_security', 'capital_base', 'end_date', 'start_date']

So, then I scratch my head, asking the question "How might I get custom data out of a backtest and into the research platform? Hmm? Looks like recorded_vars is my only option. I can store up to five scalars there. Rock on." And indeed, it works:

result.recorded_vars  

which gives me all of the recorded values versus time.

But sadly, we have no means to grab, for example, context.my_interesting_stuff and analyze it in the research platform. Perhaps the memory space gets zapped at the end of a backtest?

Grant

Recorded variables is the only way to get this information into research right now. Increasing the number of variables you can record and then access through research is on my list of things to do.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks Karen,

It dawned on me today that the 5 scalars are more than enough for what I have in mind, which is to sample a parameter space randomly, and then pull the backtest results into the research environment for processing.

Grant

This is a very old thread.

Is there still not a way to automatically print summary data at the very end of running an algorithm?
I just want to print the final values of all my context variables to the log after all the time/minute loops finish running.
This would be the corollary to the initilize() function and would be something like on_completion().
There seems to be a ‘cumulative_performance’ function, but it’s not clear how to call that outside of the handle_data loops.

There's no 'built in' user function called at the end of a simulation. However, one can be implemented. There is a method get_environment to check for the begin and end dates of the backtest (among other things) see https://www.quantopian.com/docs/api-reference/algorithm-api-reference#quantopian.algorithm.get_environment.

So, something like this could be done to print variables at the end of the backtest

def initialize(context):  
    # Schedule a function to check for the last day and have it run at market close  
    # Ensure this is the last scheduled function and it will be the last function to run  
    schedule_function(simulation_end, date_rules.every_day(), time_rules.market_close())

def simulation_end(context, data):  
   # Check each day if this is the last day  
    if get_datetime().date() != get_environment(field='end').date():  
        # Not the end of the simulation  
        return  
    else:  
        # Place whatever logic to run at the end here  
        log.info('the end')


Hope that helps.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

VERY useful. Thank you.
Seems like Q should really add a more standard solution for this common scenario however.
It’s also odd that the standard cumulative_performance variables such as pnl and returns aren’t even shown in the results after a full BackTest is run, which would also obviate the need for this to some degree.