Back to Community
Pausing my trading until n-many days into the backtest

Hi All - I had an issue previously with an algorithm that focused on moving averages. Specifically, the 126 day MA was incorrect for the first 125 days of the backtest due to lack of data to properly calculate the MA. So my object was to hold trading until the 126th day of the backtest. To accomplish this I attempted to create two datetime objects and one timedelta object. However, the program does not seem to be handling them correctly.

#Buy and sell SPY when 15 day MA is above 126 day MA


def initialize(context):  
    #Define and initialize globals  
    global i  
    i=0    

    global startdate  
    startdate= None  

    #Add SPDR SPY  
    context.SPY = sid(8554)

    #Set min/max notional  
    context.max_notional = 1000000.0  
    context.min_notional = -1000000.0

def handle_data(context, data):  
    #Get the first date  
    global startdate  
    if startdate==None:  
        startdate=get_datetime()  
    #Get the change in date time  
    global newdate  
    newdate=get_datetime()  
    #Get the difference in time  
    timedelta=newdate-startdate  
    if timedelta.days>126:  
        print ("Time to trade")  
    else:  
        print ("timedelta.days = "+str(timedelta.days))  
    #compute a notional value where short positions require 2x cash  
    notional = abs(context.portfolio.positions[context.SPY].amount * data[context.SPY].price)  
    #test the market MA  
    MAR_SPY = data[context.SPY].vwap(15) / data[context.SPY].vwap(126)  
    if MAR_SPY >= 1.0 and notional < context.max_notional:  
        order(context.SPY,+100)  
#        print("MAR_SPY>=1 and Notional="+str(notional))  
    elif MAR_SPY < 1.0 and notional > context.min_notional:  
        order(context.SPY,-100)  
#        print("MAR_SPY<1 and Notional="+str(notional))  

So the program runs but timedelta.days =0 for all timesteps in the backtest. Any ideas how to rectify this? Thanks.

13 responses

You probably need to import the datetime class.

http://docs.python.org/2/library/datetime.html

import datetime  

Ahhh.... well that was easy. (Sorry bout that). Side question - anyone know if vwap() computes the volume weighted average price for a security for the trailing number of trading days or is it actual calendar days? I'd think the former but I could be wrong.

I'm fairly certain it's trading days.

Which could make things a lot easier for you.

# initialize  
context.daycounter = 0

# handle_data  
context.daycounter += 1  
if context.daycounter >= 126:  
    # do stuff

Correct me if I'm wrong Dennis but #handle_data is called more than daily, no? Maybe there is a way to switch to daily data in the backtest? Right now I am using minute data and counting 390 calls per day (60 per hour from 930am-4pm) so maybe just

if context.daycounter >= 126*390  

thanks for the tip

Sorry, you didn't share a backtest so I didn't know you were using minute data.

You will get events outside of trading hours (especially if you use Fetcher). And some trading days close early at 1pm. So I don't think it's wise to count on 390 events per day.

In that case I would check for a new day using get_datetime() and update the counter once per day.

# initialize  
context.date = None  
context.daycounter = 0

#handle_data  
if get_datetime().date <> context.date:  
    context.date = get_datetime().date  
    context.daycounter += 1  

Yeah thats good. Just curious, how do I switch to daily data from minute data?

EDIT: Also, are there pre-defined variables within context (e.g. context.date, context.daycounter) or can you just append anything after context?

You should be able to switch between daily and minute with the dropdown right next to where you change your starting cash and beginning/end dates.

And you can just append anything after context. FYI, the reason context.blah should be used instead of just blah is so the variable can be passed between days/minutes easily. If you use the latter, your variable will just be erased at the end of the day since the function ends.

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.

Sorry for my ignorance but I see only one dropdown menu on the backtest screen, to the right of "Share Results" and there are two options in that dropdown: View Code and Backtest Details. Neither seem to offer the ability to edit the backtest settings.

As far as context.blah I've been using

#initialize  
Global myvar  
myvar=0

#handle_data  
myvar=something_new  

which seems to work but is less elegant. Thanks alot for the help Gus.

@Daniel, look on the Algorithm page to set the mode (daily/minute) before you run the backtest.

Yup, found it.

@Dennis - I tried to implement your algorithm (see below) to count the days but the program seems to count each minute as a new day

#Buy and sell SPY when 15 day MA is above 126 day MA



import datetime  
import math

def initialize(context):  
    #  
    context.date=None  
    context.timestep=0  
    #  
    #Add SPDR SPY  
    context.SPY = sid(8554)

    #  
    #Set min/max notional  
    context.max_notional = 1000000.0  
    context.min_notional = -1000000.0

def handle_data(context, data):

    #Handle assigning the timestep number  
    if get_datetime().date <> context.date: #look for a new day  
        context.date=get_datetime().date  
        context.timestep += 1  
        #Handle the first timestep (buy and hold SPY until we start using the algorithm  
        if context.timestep==1:  
            nshares = math.floor ( context.max_notional/(data[context.SPY].price) )  
            order(context.SPY,+nshares)  
        #Exit the loop if timestep is less than the longer MA  
        if context.timestep < 126:  
            print("Exiting because context.timestep="+str(context.timestep))  
            return()  
    print("Did not exit loop because context.timestep = "+str(context.timestep))   

    #compute a notional value where short positions require 2x cash  
#    notional = abs(context.portfolio.positions[context.SPY].amount * data[context.SPY].price)  
    #test the market MA  
#    MAR_SPY = data[context.SPY].vwap(15) / data[context.SPY].vwap(126)  

Log:

2012-01-03PRINTExiting because context.timestep=1
2012-01-03PRINTExiting because context.timestep=2
2012-01-03PRINTExiting because context.timestep=3
2012-01-03PRINTExiting because context.timestep=4
2012-01-03PRINTExiting because context.timestep=5
2012-01-03PRINTExiting because context.timestep=6
2012-01-03PRINTExiting because context.timestep=7
2012-01-03PRINTExiting because context.timestep=8
2012-01-03PRINTExiting because context.timestep=9
2012-01-03PRINTExiting because context.timestep=10
... ...

NOTE: if get_datetime().date is changed to get_datetime().day the program works correctly.

@Daniel, it seems I left the parentheses off .date()

if get_datetime().date() <> context.date: #look for a new day  
        context.date=get_datetime().date()  
Clone Algorithm
7
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 51e5b766731ebc06d14507c6
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.