Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Simple Ideas for a Mean Reversion Strategy with Good Results

One recent post from Alvarez Quant Trading caught my attend because of it good result. I spend two days to implement most of this strategy, however, I might need an expert to help me finish it. I completed all screening pipeline except for ordering logic. I would like to share with this community if anyone is interesting in it.

Here are some background info
Setup:
1. Close greater than 100-day moving average
2. Close less than the 5-day moving average
3. 21-day moving average of dollar-volume greater than $10 million
4. Price as trade greater than 1
5. 3 lower lows. (Not lower closes)
6. Member of the Russell 3000

Buy:
Set a limit buy order for the next day if price falls another .5 times 10-day average true range.

Sell:
Close is greater than the previous day’s close
Sell on the next open

Ref: http://alvarezquanttrading.com/2014/08/11/simple-ideas-for-a-mean-reversion-strategy-with-good-results/


import numpy as np  
from operator import itemgetter  
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline import CustomFactor  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data import morningstar  
from quantopian.pipeline.factors import SimpleMovingAverage


# Create custom factor #1 to calculate a market cap based on yesterday's close  
class MarketCap(CustomFactor):  
    inputs = [USEquityPricing.close, morningstar.valuation.shares_outstanding]  
    window_length = 1

    # Compute market cap value  
    def compute(self, today, assets, out, close, shares):  
        out[:] = close[-1] * shares[-1]

# AvgDailyDollarVolumeTraded will calculate average daily dollar volume in trailing window.  
class AvgDailyDollarVolumeTraded(CustomFactor):  
    inputs = [USEquityPricing.close, USEquityPricing.volume]  
    window_length = 20  
    def compute(self, today, assets, out, close_price, volume):  
        out[:] = np.mean(close_price * volume, axis=0)

# ConsecutiveLowerValues will calculate consecutive lower low  
class ConsecutiveLowerValues(CustomFactor):  
    window_length = 10  
    inputs = [USEquityPricing.low]

    def compute(self, today, assets, out, input1):  
        for a in range(len(assets)):  
            consecutive = 0  
            for i in range(-1,-self.window_length,-1):  
                if input1[i-1,a] > input1[i,a]:  
                    consecutive = abs(i)  
                else:  
                    break  
            out[a] = consecutive  
# DollarVolume will calculate yesterday's dollar volume for each stock in the universe.  
class DollarVolume(CustomFactor):  
    # We need close price and trade volume for this calculation.  
    inputs = [USEquityPricing.close, USEquityPricing.volume]  
    window_length = 1  
    # Dollar volume is volume * closing price.  
    def compute(self, today, assets, out, close, volume):  
        out[:] = (close[0] * volume[0])


def initialize(context):

    context.stock_target = []  
    context.stock_target_diff = []  
    context.stock_list = []  
    pipe = Pipeline()  
    attach_pipeline(pipe, 'example')

    # Note that we don't call add_factor on these Factors.  
    # We don't need to store intermediate values if we're not going to use them  
    sma_1 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=1)  
    sma_5 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=5)  
    sma_100 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=100)  
    consec_lowers = ConsecutiveLowerValues(inputs=[USEquityPricing.low], window_length=3)  
    pipe.add(consec_lowers, "consec_lowers")  
    pipe.add(consec_lowers.rank(), 'consec_lowers_rank')  
    pipe.add(sma_1, 'sma_1')  
    pipe.add(sma_1.rank(), 'sma_1_rank')

    # Construct the custom factor  
    mkt_cap = MarketCap()

    # Create and apply a filter representing the top 500 equities by MarketCap  
    # every day.  
    mkt_cap_top_3000 = mkt_cap.top(3000)  
    # Screen down averaged at least $10M of daily trading dollar volume over the past 21 days.  
    dollar_volume = AvgDailyDollarVolumeTraded(window_length=21)  
    # Use multiple screens to narrow the universe  
    pipe.set_screen((sma_1 >= sma_100) & (sma_1 <= sma_5) & (dollar_volume >= 10 * 10**6) & (sma_1 >= 1.00) & (consec_lowers >= 2) & mkt_cap_top_3000)


def before_trading_start(context, data):  
    context.output = pipeline_output('example')  
    context.long_list = context.output.sort(['sma_1_rank'], ascending=True)  
    update_universe(context.long_list.index)  
    # update_universe(context.long_list.index.union(context.short_list.index))


def handle_data(context, data):

    cash = context.portfolio.cash  
    previous_close = history(1, '1d', 'close_price')  
    # Buy: Set a limit buy order for the next day if price falls another .5 times 10-day average true range.  
    # Sell: Close is greater than the previous day’s close     Sell on the next open  
    for i in range(0, len(context.long_list)):  
        average_price_10 = data[context.long_list.index[i]].mavg(10)  
        current_price = data[context.long_list.index[i]].price  
        target_price = previous_close[context.long_list.index[i]][0] - 0.5 * (previous_close[context.long_list.index[i]][0] - average_price_10)  
        price_diff = (target_price - current_price)/current_price  
        if current_price < target_price:  
            context.stock_target.append(context.long_list.index[i].symbol)  
            context.stock_target_diff.append(price_diff)  
    temp = zip(context.stock_target, context.stock_target_diff)  
    stock_list = sorted(temp, key=itemgetter(1))[-10:]  
    for i in range(0, len(stock_list)):  
        temp = str(stock_list[i][0])  
        order_target_percent(symbol(temp), 0.1)