Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
How would I modify this Moving Average Algo to execute on today's closing price instead of the next day's close

I have a simple moving average algorithm that analyzes the prevailing price of the SPY versus its 10d moving average---it sells a different security (e.g. AAPL) if the price of the SPY falls below its 10d moving average.

One thing I dont like about the standard definition of moving averages is they require "waiting" until a close value has occurred, and then execute on the next days closing price. But say around 3:59 you've got a great idea of what the closing price is....and could enter/exit your trade at that point if you wanted to (I am a small investor; my volume wouldnt impact anything).

For example, On February 10, 2009, the SPY closing price was below the 10d MA (and the day before it was previously above). As a result, my backtest algorithm executed a sell order on AAPL, but the AAPL share price in the sell order is $96.80 -- which is the closing price of AAPL on February 11th. (see the transaction line below)

2009-02-10 16:00:00 AAPL SELL -51 $96.80 ($4,936.80)

How can/would I modify the algorithm so that when the SPY cross-over occured (based on the closing prices on February 10th), it executes the sell order for AAPL on February 10th (instead of 11th)?

def initialize(context):  
    context.spy = sid(8554)  
    context.aapl = sid(24)  
    context.invested = False


# Will be called on every trade event for the securities you specify.  
def handle_data(context, data):  
    mavg = data[context.spy].mavg(10)  
    price = data[context.spy].price  
    traded_shares = 5000/data[context.aapl].price

    if (price < mavg) and context.invested == False:  
        order(context.aapl, traded_shares * -1)  
        context.invested = True  
    elif (price > mavg) and context.invested == True:  
        holder = -1 * context.portfolio.positions[sid(24)].amount  
        order(context.aapl, holder)  
        context.invested = False  
6 responses

Have a look at a recent thread on trading different time intervals. I posted some code that breaks up the day into "opening", "5 minute chunks", and "closing".

https://www.quantopian.com/posts/how-to-create-different-time-intervals

You should be able to modify that to suit your needs. Note that it doesn't have any awareness of when the market will close early (e.g. the day before a holiday).

Also, numerous people have requested the official implementation of market-on-close orders, so I expect they will eventually implement them!

So, you want to use minute data, but only for the current day. If I understand correctly, you want to store past days' closing prices but work with the current days' minute prices. One way to do this is to make a dictionary that links days to the last price recorded during that day, like this. This is meant to be run in minute mode. With this, you can trigger an order the minute whatever event involving the average happens.

# Insert most recent price for each day into the dictionary  
context.past_prices[get_datetime().date()] = data[context.security].price

# If the dictionary's length is over what we want to average over  
if len(context.past_prices) > 10:  
    # Find and remove the oldest entry  
    last = sorted(context.past_prices.items(), key=lambda t: t[0])[0]  
    del context.past_prices[last[0]]

# The 10-day moving average including most recent price from today  
mavg = sum(context.past_prices.values())/len(context.past_prices)

log.info(mavg)  
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.

@Gus, I think you could achieve a rolling window of daily closing prices just a tad easier using a deque.

Also, when working in minute-mode it's important to recognize that data[stock].price refers to the current minute bar, not yesterday's close.

from collections import deque  
import numpy as np

# in initialize()

# initialize deque for 10 days of daily close prices  
context.past_prices = deque( [], maxlen=10 )

# remember price from one minute bar to the next  
context.last_price = None

# remember the date of the price we remembered  
context.last_date = None

# in handle_data()

# check for first minute bar of the day  
if get_datetime().date() <> context.last_date and context.last_price <> None:  
    # Insert most recent closing price for each day into the deque  
    context.past_prices.appendleft( context.last_price )

# update remembered price and date  
context.last_price = data[context.security].price  
context.last_date = get_datetime().date()

# If the deque's length is equal what we want to average over  
if len(context.past_prices) == 10:  

    # The 10-day moving average  
    mavg = np.mean(context.past_prices)

    log.info(mavg)  

Interesting Dennis, deques seem really useful, I hadn't heard of them before. BTW, I insert the most recent price into the dict with data[stock].price for a reason. It just overwrites the most recent one every minute until the new day begins when it starts a new dict entry. That way when it stops overwriting the past day, we have effectively stored that last day's closing price, and can store and work it with other days prices and the current day's current price.

@Gus, I missed that implication. Your solution should work just as well.