Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- '''
- This is code for the "Connors Research Weekly Mean Reversion" Strategy
- From "The Alpha Formula"
- Rules:
- 1. Long-term Trend Following Regime Filter. SPY’s total return over the last six months (126 trading days) is positive.
- 2. Liquidity Filter. The stock must be one of the 500 most liquid US stocks. Our 500 most liquid US stock universe is determined every month by taking the 500 US stocks with the highest 200-day average dollar volume. This is the Q500US universe.
- 3. The Weekly 2-period RSI of the stock is below 20. This confirms that the stock has overreacted to the downside.
- 4. All stocks that meet these criteria are then ranked by their trailing 100-day historical volatility. We then BUY on the close, in equal weight, the 10 stocks with the LOWEST historical volatility.
- 5. SELL the stock on the close if its weekly 2-period RSI is above 80. This is checked at the end of every business Week.
- 6. SELL the stock on the close if the current price is more than 10% below the entry price. This is checked at the end of every business Day.
- 7. Any capital that is not allocated is put into SHY (1-3-year US Treasuries ETF).
- '''
- import quantopian.algorithm as algo
- from quantopian.pipeline import Pipeline
- from quantopian.pipeline.data.builtin import USEquityPricing
- from quantopian.pipeline.filters import Q500US
- import talib as ta
- from math import sqrt
- def initialize(context):
- #Set slippage and attach the algo
- set_slippage(slippage.FixedSlippage(spread = 0.0))
- algo.attach_pipeline(make_pipeline(), 'pipeline')
- #Schedule our functions
- schedule_function(trade , date_rules.week_end(), time_rules.market_close(minutes=6))
- schedule_function(stops, date_rules.every_day(), time_rules.market_close(minutes=10))
- schedule_function(take_profits, date_rules.week_end(), time_rules.market_close(minutes=10))
- schedule_function(trade_bonds, date_rules.every_day(), time_rules.market_close(minutes=5))
- #Global variables for our TF Regime Filter
- context.spy = sid(8554)
- context.TF_filter = False
- context.TF_Lookback = 126
- #Global Variables for amount of securities, RSI level, RSI lookback, Take Profit level and stop percent
- context.Target_securities_to_buy = 10.0
- context.RSI_level = 20
- context.RSI_lookback = 2
- context.RSI_TP_level = 80
- context.stop_percent = 0.10
- #Global Variable controlling bond fund we rotate into
- context.bonds = sid(23911)
- #Globla variable controlling vol lookback to ranking (if several stocks are oversold)
- context.vol_lookback = 100
- def make_pipeline():
- # Base universe set to the Q500US
- universe = Q500US()
- # This is pipeline code
- # All we are doing is making an object, 'pipe' containing the current 500 most liquid US stocks
- pipe = Pipeline(screen=universe)
- return pipe
- def before_trading_start(context, data):
- #Called every day before market open.
- context.output = algo.pipeline_output('pipeline')
- # These are the securities that we are interested in trading each day.
- context.security_list = context.output.index
- def trade(context, data):
- #This code controls our trend following regime filter
- #If market is trending higher we set "context.TF_filter" to True
- #If not we set "context.TF_filter" to False
- TF_hist = data.history(context.spy , "close", 253, "1d")
- TF_check = TF_hist.pct_change(context.TF_Lookback).iloc[-1]
- if TF_check > 0.0:
- context.TF_filter = True
- print('TF Filter Percentile passed')
- else:
- context.TF_filter = False
- print('TF Filter Percentile not passed')
- ############ Regime Filter code end #################
- #### Grab prices DataFrame, resample to weekly data
- prices = data.history(context.security_list,"close", 253, "1d")
- prices_weekly = prices.resample('w').last()
- ##### Calculate RSI and filter to stocks under an RSI level using boolean filter
- RSI = prices_weekly.apply(lambda c: ta.RSI(c, context.RSI_lookback)).iloc[-1]
- low_RSI = RSI[RSI < context.RSI_level]
- ##### Calculate vol of our stocks that are oversold (for ranking)
- vol = prices[low_RSI.index][-context.vol_lookback:].pct_change().std()
- vol_sorted = vol.sort_values(ascending=True)
- ##### Check current amount of positions (not including bond position
- if context.portfolio.positions[context.bonds].amount == 0:
- num_of_current_positions = len(context.portfolio.positions)
- if context.portfolio.positions[context.bonds].amount > 0:
- num_of_current_positions = len(context.portfolio.positions) - 1
- #### Calculate securities we need to buy
- securities_to_buy = context.Target_securities_to_buy - num_of_current_positions
- #### Loop through our final buy list (sorted by vol) and buy the amount we need
- securities_to_buy_counter = 0
- for x in vol_sorted.index:
- if securities_to_buy_counter < securities_to_buy and x not in context.portfolio.positions and context.TF_filter == True:
- order_percent(x , (1 / context.Target_securities_to_buy))
- print("we bought" , x)
- securities_to_buy_counter = securities_to_buy_counter + 1
- def stops(context,data):
- ## Loop through our portfolio (not including bonds) and see if we need to stop ourselves out
- for x in context.portfolio.positions:
- if (x.sid == context.bonds):
- pass
- else:
- basis = context.portfolio.positions[x].cost_basis
- current_price = data.current(x,'price')
- stop_price = basis * (1.0 - context.stop_percent)
- #Percent Stop
- if current_price < stop_price:
- order_target_percent(x,0)
- print('GOT STOPPED OUT OF' , x , 'curr_price' , current_price , 'stop_price' , stop_price)
- def take_profits(context, data):
- #Grab current positions, grab history, resample to weekly, calculate the RSI
- current_positions = context.portfolio.positions.keys()
- hist_for_TP = data.history(current_positions,"close", 90, "1d") #Get history for RSI calculation - this is only prices
- hist_for_TP_weekly = hist_for_TP.resample('w').last() #Resample to weekly frequency
- RSI_df_for_TP = hist_for_TP_weekly.apply(lambda c: ta.RSI(c, context.RSI_lookback)) #Convert to rolling RSI values
- RSI_for_TP_current = RSI_df_for_TP.iloc[-1] #Get the most current RSI reading for all securities
- ## Loop through our portfolio (not including bonds) and see if RSI is above our TP level, if we sell (take our profit)
- for x in context.portfolio.positions:
- if (x.sid == context.bonds):
- pass
- else:
- if RSI_df_for_TP[x].iloc[-1] > context.RSI_TP_level:
- order_target_percent(x,0)
- print('RSI TP got hit' , x , RSI_df_for_TP[x].iloc[-1])
- def trade_bonds(context , data):
- #Allocate any unsed capital to Bonds
- if context.portfolio.positions[context.bonds].amount == 0:
- amount_of_current_positions = len(context.portfolio.positions)
- if context.portfolio.positions[context.bonds].amount > 0:
- amount_of_current_positions = len(context.portfolio.positions) - 1
- percent_bonds_to_buy = (context.Target_securities_to_buy - amount_of_current_positions) * (1.0 / context.Target_securities_to_buy)
- order_target_percent(context.bonds , percent_bonds_to_buy)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement