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
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)