Back to Community
example algo showcasing usage of minute data with the new feature Q500US

Attached is an example algo showcasing the usage of minute data with Q500US.

The algo is a long-short momentum strategy that buys stocks with high volume and high return and shorts the other end (30 stocks per leg). Purchased stocks are held in the portfolio for only one minute. As many might expect, turning on the transaction cost kills this simple algo. :)

Kudos to the Quantopian team for pushing out all the features within the past 2 years.

Clone Algorithm
143
Loading...
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
# https://www.quantopian.com/posts/the-q500us-and-q1500us
import copy
import numpy as np    
import pandas as pd
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.filters import Q500US
 
def initialize(context):    
    
    context.num_leg = 30
    context.lev = 2.5
    
    # don't you dare comment these 2 lines... 
    set_commission(commission.PerTrade(cost=0))
    set_slippage(slippage.FixedSlippage(spread=0.00)) 
    
    ##### memory errorahahhh!
    #for offset in np.arange(5,390,5):
    for offset in [5,10,15,370,375,380]:
        schedule_function(
            assign_weights,
            date_rules.every_day(),
            time_rules.market_open(minutes=offset)
        )
        schedule_function(
            rebalance,
            date_rules.every_day(),
            time_rules.market_open(minutes=offset)
        )
        schedule_function(
            purge,
            date_rules.every_day(),
            time_rules.market_open(minutes=offset+1)
        )
        
    # Create our dynamic stock selector.
    attach_pipeline(make_pipeline(), 'my_pipeline')
         
def make_pipeline():
    return Pipeline(screen = Q500US(),)
 
def before_trading_start(context, data):
    context.output = pipeline_output('my_pipeline')
    context.security_list_org = context.output.index
     
def assign_weights(context, data):
    # get data
    volume_m = data.history(context.security_list_org, "volume", 5, "1m")    
    price_m = data.history(context.security_list_org, "price", 5, "1m")
    volume_d = data.history(context.security_list_org, "volume", 200, "1d")      
    
    # calc ret from last 5 min
    log_price = np.log(price_m)
    prct_change = log_price.iloc[-1,:]-log_price.iloc[0,:]
    # normalize volume to relative past history and then among equities
    norm_volume = volume_m.sum()/volume_d.mean()
    norm_volume = (norm_volume-np.min(norm_volume))/(np.max(norm_volume)-np.min(norm_volume))
    
    # we long and short the extreme movement as defined by `indicator`
    indicator = prct_change*norm_volume
    indicator_pos = copy.deepcopy(indicator)
    indicator_pos[indicator_pos<=0] = np.nan
    indicator_neg = copy.deepcopy(indicator)
    indicator_neg[indicator_neg>=0] = np.nan
    
    # get the ones going up
    pos = indicator_pos.rank(ascending=False,method='average')
    pos_index = pos.where(pos<context.num_leg).dropna().index
    # get the ones going down
    neg = indicator_neg.rank(ascending=True,method='average')
    neg_index = neg.where(neg<context.num_leg).dropna().index
    
    context.security_list = []
    context.weight_list = []
    context.security_list.extend(pos_index)
    context.weight_list.extend([1.0]*pos_index.size)
    context.security_list.extend(neg_index)
    context.weight_list.extend([-1.0]*neg_index.size)
    
    context.weight_list = np.array(context.weight_list)
    context.weight_list = context.lev*context.weight_list/(np.sum(np.abs(context.weight_list)))
    
    context.weights_pd = pd.DataFrame(context.weight_list,
                                   index=context.security_list)
    
def rebalance(context,data):
    
    print_out = []
    for stock in context.security_list:
        if len(context.weights_pd.loc[stock]) != 1:
            continue
        weight = context.weights_pd.loc[stock][0]
        if data.can_trade(stock):
            order_target_percent(stock,weight)
            print_out.append((stock.symbol,weight))
        else:
            log.warn('wtwhat %r' % stock.symbol)

def purge(context,data):
    for stock in context.portfolio.positions.keys():
        if data.can_trade(stock):
            order_target_percent(stock,0)
                
There was a runtime error.
1 response

Lee, Charles, and Bhaskaran Swaminathan. "Price momentum and trading volume." the Journal of Finance 55.5 (2000): 2017-2069.
http://onlinelibrary.wiley.com/doi/10.1111/0022-1082.00280/full

Volume might be something worth looking into.

Clone Algorithm
143
Loading...
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
# https://www.quantopian.com/posts/the-q500us-and-q1500us
# http://onlinelibrary.wiley.com/doi/10.1111/0022-1082.00280/full
# http://technicalanalysis.org.uk/volume/LeSw00.pdf

import copy
import numpy as np    
import pandas as pd
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.filters import Q1500US,Q500US
from quantopian.pipeline.factors import AverageDollarVolume

def initialize(context):    
    
    context.num_leg = 10
    context.lev = 1
    
    set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1)) # quantopian defaults
    set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1)) # quantopian defaults
    
    offset = 5
    schedule_function(
        purge,
        date_rules.month_start(days_offset=0),
        time_rules.market_open(minutes=offset-1)
    )
    schedule_function(
        assign_weights,
        date_rules.month_start(days_offset=0),
        time_rules.market_open(minutes=offset)
    )
    schedule_function(
        rebalance,
        date_rules.month_start(days_offset=0),
        time_rules.market_open(minutes=offset)
    )
        
    # Create our dynamic stock selector.
    attach_pipeline(make_pipeline(), 'my_pipeline')
lookback = 90
def make_pipeline():
    pipe = Pipeline()
    sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200)
    dollar_volume = AverageDollarVolume(window_length=lookback)
    high_dollar_volume = dollar_volume.top(500)
    low_dollar_volume = dollar_volume.bottom(500)
    #pipe_screen = (longs | shorts)
    pipe.set_screen((sma_200 > 5)&(high_dollar_volume | low_dollar_volume))

    return pipe
    #return Pipeline(screen = Q1500US(),)
 
def before_trading_start(context, data):
    context.output = pipeline_output('my_pipeline')
    context.security_list_org = context.output.index
     
def assign_weights(context, data):
    
    #  stragety
    #               return 
    #              high   low
    #  volume high short  long 
    #         low  long   short
    # 
    # short high volume winners
    # long low volume winners
    # long low volume losers
    # short high volume lowers
    
    # get data
    price = data.history(context.security_list_org, "price", lookback, "1d")
    volume = data.history(context.security_list_org, "volume", lookback, "1d")      
    
    # calc ret from last 5 min
    log_price = np.log(price)
    prct_change = log_price.iloc[-1,:]-log_price.iloc[0,:]
    # normalize volume to relative past history and then among equities
    norm_volume = volume.sum()
    norm_volume = (norm_volume-np.min(norm_volume))/(np.max(norm_volume)-np.min(norm_volume))            
    mul_vol = prct_change*norm_volume
    indicator_pos = copy.deepcopy(mul_vol)
    indicator_pos[indicator_pos<=0] = np.nan
    indicator_neg = copy.deepcopy(mul_vol)
    indicator_neg[indicator_neg>=0] = np.nan
    
    pos = indicator_pos.rank(ascending=False,method='average')
    h_vol_h_ret = pos.where(pos<context.num_leg).dropna().index    
    neg = indicator_neg.rank(ascending=True,method='average')
    h_vol_l_ret = neg.where(neg<context.num_leg).dropna().index
    
    div_vol = prct_change/norm_volume
    indicator_pos = copy.deepcopy(div_vol)
    indicator_pos[indicator_pos<=0] = np.nan
    indicator_neg = copy.deepcopy(div_vol)
    indicator_neg[indicator_neg>=0] = np.nan
    
    pos = indicator_pos.rank(ascending=False,method='average')
    l_vol_h_ret = pos.where(pos<context.num_leg).dropna().index    
    neg = indicator_neg.rank(ascending=True,method='average')
    l_vol_l_ret = neg.where(neg<context.num_leg).dropna().index    
    
    long_list = []
    long_list.extend(l_vol_h_ret)
    long_list.extend(l_vol_l_ret)
    short_list = []
    short_list.extend(h_vol_h_ret)
    short_list.extend(h_vol_l_ret)
    context.security_list = []
    context.weight_list = []
    context.security_list.extend(long_list)
    context.weight_list.extend([1.0]*len(long_list))
    context.security_list.extend(short_list)
    context.weight_list.extend([-1.0]*len(short_list))
    
    context.weight_list = np.array(context.weight_list)
    context.weight_list = context.lev*context.weight_list/(np.sum(np.abs(context.weight_list)))
    
    context.weights_pd = pd.DataFrame(context.weight_list,
                                   index=context.security_list)
    
def rebalance(context,data):
    
    print_out = []
    for stock in context.security_list:
        if len(context.weights_pd.loc[stock]) != 1:
            continue
        weight = context.weights_pd.loc[stock][0]
        if data.can_trade(stock):
            order_target_percent(stock,weight)
            print_out.append((stock.symbol,weight))
        else:
            log.warn('wtwhat %r' % stock.symbol)

def purge(context,data):
    for stock in context.portfolio.positions.keys():
        if data.can_trade(stock):
            order_target_percent(stock,0)
                
There was a runtime error.