Back to Community
Mean Reversion Template with B Bands

Line 43: The history method is deprecated. Use data.history instead.
Line 75: Iterating over the assets in data is deprecated.
Line 50: data[sid(N)] is deprecated. Use data.current.
Line 52: data[sid(N)] is deprecated. Use data.current.
Line 52: The stddev method is deprecated.

If someone corrects these errors, can you please comment the old code so I can compare and learn? Thank you

Working through iterations, any assistance to speed up the learning curve would be appreciated:

  1. How to improve [order fill rates] because slippage assumption here is not realistic?

  2. Why trade only once every 20 days? Can this be changed to continuous time based on price v. B Band plots? (Or am I not reading correctly)

  3. Implement a Stop & Reverse overlay to BBands? Perhaps with a ama/ema/sma xover that can have variables adjusted manually (dynamically via pipeline)?

  4. Change from single stock to context.stocks so algo is (e.g.) ranking and trading highest momo stocks in Q500 based on [any momo indicator from TA-lib]?

  5. Use pipeline to continuously optimize context.stocks (and indicators from TA-lib) for multi-factor dynamic optimization? Is this possible?

Clone Algorithm
19
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
'''
    Linear Regression Curves vs. Bollinger Bands  
    If Close price is greater than average+n*deviation, go short  
    If Close price is less than average+n*deviation, go long  
    Both should close when you cross the average/mean  
'''


import numpy as np  
from scipy import stats  
from pytz import timezone, utc  
from datetime import datetime, timedelta  
from zipline.utils.tradingcalendar import get_early_closes

def initialize(context):  
    # Enter sid here to use the algo with a single stock  
    context.stock = sid(40516)

    context.dev_multiplier = 2  
    context.max_notional = 1000000  
    context.min_notional = -1000000

    # Days traded to ensure that we trade only once every twenty days  
    context.days_traded = 0  
    # Using an unimportant date just to initialize current_day  
    context.current_day = 0  
    # Gets all early close dates  
    start = datetime(1993, 1, 1, tzinfo=utc)  
    end = datetime(2050, 1, 1, tzinfo=utc)  
    context.early_closes = get_early_closes(start,end).date  
    # Minutes before close that you want to execute your order, so this will execute at 3:55 PM only  
    context.minutes_early = 5  

    context.past_prices = None

def handle_data(context, data):  
    if context.current_day != get_datetime().day:  
        context.current_day = get_datetime().day  
        context.days_traded += 1    

    dev_mult = context.dev_multiplier  
    notional = context.portfolio.positions_value  
    context.past_prices = history(20, '1d', 'price')  
    # Calls get_linear so that moving_average has something to reference by the time it is called  
    linear = get_linear(context, data)  
    # Only checks every 20 days  
    if context.days_traded%20 == 0:  
        try:  
            # Uses context.stock  
            close = data[context.stock].price  
            moving_average = linear[context.stock]  
            moving_dev = data[context.stock].stddev(20)

            high_band = moving_average + dev_mult*moving_dev

            low_band = moving_average - dev_mult*moving_dev  
            # If close price is greater than band, short 5000 and if less, buy 5000  
            if close > high_band and notional > context.min_notional:  
                order(context.stock, -5000)  
                log.debug("Shorting 5000")  
            elif close < low_band and notional < context.max_notional:  
                order(context.stock, 5000)  
                log.debug("Going long 5000")  
        except:  
            return

# Linear regression curve that returns the intercept the curve  
# Uses the past 20 days  
def get_linear(context, data):  
    days = [i for i in range(1,21)]  
    stocks = {}  
    # Checks if data is emtpty  
    if len(context.past_prices) < 20:  
        return  
    for stock in data:  
        linear = stats.linregress(days, context.past_prices[stock])[1]  
        stocks[stock] = linear  
    return stocks

# Returns True if it's the end of day and False otherwise  
def endofday_check(context, minutes_early):  
    # Converts all time-zones into US EST to avoid confusion  
    loc_dt = get_datetime().astimezone(timezone('US/Eastern'))  
    date = get_datetime().date()  
    # Checks for an early close on special dates such as holidays and the day after thanksgiving  
    # The market closes at 1:00PM EST on those days  
    if date in context.early_closes:  
        # Returns true if it's 1:00PM - minutes so in this case 12:55PM  
        if loc_dt.hour == 12 and loc_dt.minute == (44-minutes_early):  
            return True  
        else:  
            return False  
    # Returns true if it's 4:00PM EST - minutes so in this case at 3:40PM  
    # Daylight savings time are accounted for, so it will automatically adjust to DST  
    elif loc_dt.hour == 15 and loc_dt.minute == (44-minutes_early):  
        return True  
    else:  
        return False  
There was a runtime error.