Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Days Rules for Moving Average

Hi Everyone, I am new to Quantopian and coding and am stuck on figuring out how to add a conditional rule to the trading logic. Basically I am trying to make the trading decision off whether the sma_20 > sma_10 for 3 days. Does anyone know what the proper syntax is to achieve the 3 day rule? Thank you!

8 responses

This may help:

import talib  
# -----------------------------------------------------  
stock, ma_f, ma_s, days_rule = symbol('SPY'), 10, 20, 3  
# -----------------------------------------------------  
def initialize(context):  
    schedule_function(trade, date_rules.every_day(), time_rules.market_close())

def trade(context,data):  
    bars = ma_s + days_rule

    prices = data.history(stock, 'close', bars, '1d')  
    mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
    mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
    diff = mavg_f - mavg_s   

    if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0):  
        signal = 1  
    elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0):  
        signal = -1  
    else:  
        return

    record(diff = diff[-1], signal = signal, zero = 0)

Hi Vladimir, this was very helpful. I was successfully able to implement this when testing a singular future but keep getting the below error when trying to use multiple futures in the algo. Can you only test one symbol with this function? Thanks again!

AssertionError: real has wrong dimensions

Hi John,
Try something like this:

import talib  
# --------------------------------------------------------------------------  
stock, bond, ma_f, ma_s, days_rule = symbol('SPY'), symbol('TLT'), 10, 20, 3  
# --------------------------------------------------------------------------  
def initialize(context):  
    schedule_function(trade, date_rules.every_day(), time_rules.market_close())

def trade(context,data):  
    assets = [stock, bond]  
    bars = ma_s + days_rule  
    signal = {}

    for sec in assets:  
        prices = data.history(sec, 'close', bars, '1d')  
        mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
        mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
        diff = mavg_f - mavg_s 

        if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0):  
            signal[sec] = 1  
        elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0):  
            signal[sec] = -1  
        else :  
            return

    record(signal_spy = signal[stock] , signal_tlt = signal[bond], zero = 0)  

Hello Vlad, thank you so much for your continued help on this. The below code is working for Corn futures but one thing I can't figure out is the rebalance. It is running the program everyday but it keeps adding to the position. I'm trying to design it to open a position when the average crosses over and close it when it crosses back. Any ideas?

from quantopian.algorithm import order_optimal_portfolio
import quantopian.optimize as opt
import pandas as pd
import talib

-----------------------------------------------------

-----------------------------------------------------

def initialize(context):

context.corn = continuous_future('CN', offset=0, roll='volume', adjustment='mul')  

schedule_function(trade, date_rules.every_day(), time_rules.market_open())  

def trade(context,data):

future, ma_f, ma_s, days_rule = continuous_future('CN'), 10, 20, 3  

bars = ma_s + days_rule

prices = data.history(context.corn, 'close', bars, '1d')  
mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
diff = mavg_f - mavg_s  

open_orders = get_open_orders()  

primary = data.current(context.corn, 'contract')



if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0) and 'CN' not in open_orders:  
    order(primary, 1)  
elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0) and 'CN' not in open_orders:  
    order(primary, -1)  

Hi John,
Try this:

# 3 days MAC rule NQ LX  
import talib  

def initialize(context):  
    schedule_function(trade, date_rules.every_day(), time_rules.market_open())  

def trade(context,data):  
    if get_open_orders(): return 

    future = continuous_future('NQ', offset = 0, roll = 'volume', adjustment='mul')  
    ma_f = 10; ma_s = 20; days_rule = 3; bars = ma_s + days_rule    

    prices = data.history(future, 'close', bars, '1d').bfill()  
    mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
    mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
    diff = mavg_f - mavg_s  

    primary = data.current(future, 'contract')

    if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0):  
        order_target_percent(primary, 1.)  
    elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0):  
        order_target_percent(primary, 0.)  

Spasiba, Vlad. That last bit of code worked great but only works for a long basis. I also want to have this logic on the short side. IE 20 crosses above 10 for 3 days and we go short - then close the position when the 10 crosses back above the 20.

Hi John,
Is this the one you want?

# 3 days MAC rule NQ SX  
import talib  

def initialize(context):  
    schedule_function(trade, date_rules.every_day(), time_rules.market_open())  

def trade(context,data):  
    if get_open_orders(): return 

    future = continuous_future('NQ', offset = 0, roll = 'volume', adjustment='mul')  
    ma_f = 10; ma_s = 20; days_rule = 3; bars = ma_s + days_rule    

    prices = data.history(future, 'close', bars, '1d').bfill()  
    mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
    mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
    diff = mavg_f - mavg_s  

    primary = data.current(future, 'contract')

    if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0):  
        order_target_percent(primary, 0.)  
    elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0):  
        order_target_percent(primary, -1.)

Hi Vlad, the code you have provided has been incredibly helpful. Do you know if there are any limitations with using the talib.SMA function for multiple futures? I have gotten a dimension error when trying to add more symbols. This is the code I'm currently using but would like to add more symbols to this backtest to see how it performs with other futures.

import talib
from zipline.utils.calendars import get_calendar

EARLY_ROLL_DAYS = 14

def initialize(context):
schedule_function(trade, date_rules.every_day(), time_rules.market_open())

def trade(context,data):
open_orders = get_open_orders()

context.corn = continuous_future('CN', offset = 0, roll = 'calendar', adjustment='mul')  
ma_f = 10; ma_s = 20; days_rule = 3; bars = ma_s + days_rule    

prices = data.history(context.corn, 'close', bars, '1d').bfill()  
mavg_f = talib.SMA( prices[-ma_f-days_rule:], ma_f)[-days_rule:]  
mavg_s = talib.SMA( prices[-ma_s-days_rule:], ma_s)[-days_rule:]  
diff = mavg_f - mavg_s  

primary = data.current(context.corn, 'contract')

long

if (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0) and context.portfolio.positions[primary].amount == 0 and context.corn not in open_orders:  
    order_target_percent(primary, 1.)  
elif (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0) and context.portfolio.positions[primary].amount > 0:  
    order_target_percent(primary, 0.)  

short side

if (diff[-1] < 0 and diff[-2] < 0 and diff[-3] < 0) and context.portfolio.positions[primary].amount == 0 and context.corn not in open_orders:  
    order_target_percent(primary, -1.)  
elif (diff[-1] > 0 and diff[-2] > 0 and diff[-3] > 0) and context.portfolio.positions[primary].amount < 0:  
    order_target_percent(primary, 0.)