def before_trading_start(context, data): """ Called every month before market open. """ context.output = pipeline_output('my_pipeline') # Go long in securities for which the 'longs' value is True context.longs = context.output[context.output['longs']].index.tolist() # Go short in securities for which the 'shorts' value is True. context.shorts = context.output[context.output['shorts']].index.tolist() base_universe = Q1500US() returns_past_12_months = Returns(window_length=252, mask=base_universe) returns_past_2_months = Returns(window_length=42, mask=base_universe) returns_relevant = returns_past_12_months - returns_past_2_months returns_relevant_deciles = returns_relevant.deciles() longs = (returns_relevant_deciles.eq(9)) shorts = (returns_relevant_deciles.eq(0)) WML_returns = context.output['returns_relevant'][ context.output['longs']].sum() - context.output['returns_relevant'][ context.output['shorts']].sum() #std_dev = StdDev(inputs=[WML_returns], window_length=126) std_dev = np.std(WML_returns) if std_dev < 0.12: context.long_leverage, context.short_leverage = 0.5, -0.5 else: context.long_leverage, context.short_leverage = .5 ( .12 / std_dev), -.5 (.12 / std_dev)
def pipe_definition(context): context.stocks = symbols('DBA', 'DBC', 'DIA', 'EEM', 'EFA', 'EPP', 'EWA', 'EWJ', 'EWZ', 'FXF', 'FXI', 'GLD', 'IEV', 'ILF', 'IWM', 'IYR', 'MDY', 'QQQ', 'SPY', 'TLT', 'XLE', 'XLF') universe = Filters.StaticAssets(context.stocks) #universe = Fundamentals.total_revenue.latest.top(500) #universe = Q1500US() close_price = USEquityPricing.close.latest m3 = Returns(inputs=[USEquityPricing.close], window_length=67) * 100 m6 = Returns(inputs=[USEquityPricing.close], window_length=137) * 100 blend = m3 * 0.7 + m6 * 0.3 sma_88 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=89, mask=universe) return Pipeline( columns={ 'close_price': close_price, 'm3': m3, 'm6': m6, 'blend': blend, 'sma_88': sma_88, }, screen=universe, )
def make_pipeline(): """ A function to create our dynamic stock selector (pipeline). Documentation on pipeline can be found here: https://www.quantopian.com/help#pipeline-title """ pipe = Pipeline() # Base universe set to the Q1500US. base_universe = Q1500US() # Get returns of base universe stocks starting from 12 months ago (252 trading days ago). returns_12m = Returns(window_length=252, mask=base_universe) # Get returns of base universe stocks starting from 2 months ago (42 trading days ago). returns_2m = Returns(window_length=42, mask=base_universe) # Get returns of base universe stocks starting from 12 months and ending 2 months ago. returns_diff = returns_12m - returns_2m # Divide those returns into deciles. returns_diff_decile = returns_diff.deciles() # Filter to select securities to long longs = (returns_diff_decile.eq(9)) pipe.add(longs, 'longs') # Filter to select securities to short shorts = (returns_diff_decile.eq(0)) pipe.add(shorts, 'shorts') # Filter for all securities that we want to trade securities_to_trade = (longs | shorts) pipe.set_screen(securities_to_trade) return pipe
def make_ml_pipeline(factors, universe, window_length=5, n_fwd_days=2): factors_pipe = OrderedDict() # Create returns over last n days. factors_pipe['Returns'] = Returns(inputs=[USEquityPricing.open], mask=universe, window_length=n_fwd_days) for i in [2, 3, 4, 5, 7, 10, 20, 60, 100, 250]: factors_pipe['Return' + str(i)] = Returns( inputs=[USEquityPricing.open], mask=universe, window_length=i) # Instantiate ranked factors for name, f in factors.iteritems(): factors_pipe[name] = f().zscore(mask=universe) # Create our ML pipeline factor. The window_length will control how much # lookback the passed in data will have. factors_pipe['ML'] = ML(inputs=factors_pipe.values(), window_length=window_length + 1, mask=universe) factors_pipe['ML_zscore'] = factors_pipe['ML'].zscore(mask=universe) factors_pipe['ML_ranked'] = factors_pipe['ML'].rank(mask=universe) pipe = Pipeline(screen=universe, columns=factors_pipe) return pipe
def make_pipeline2(): pipe = Pipeline() '''standards''' book_to_price = 1 / Latest([Fundamentals.pb_ratio]) PE = Latest([Fundamentals.pe_ratio]) #research_and_development = Latest([Fundamentals.research_and_development]) gross_dividend_payment = Latest([Fundamentals.gross_dividend_payment]) value_score = Latest([Fundamentals.value_score]) returns = Returns(inputs=[USEquityPricing.close], window_length=2) growth_score = Latest([Fundamentals.growth_score]) profit_grade = Fundamentals.profitability_grade.latest financial_health_grade = Fundamentals.financial_health_grade.latest '''filter''' #profit_requirement = (profit_grade=='A') | (profit_grade=='B') mask = QTradableStocksUS() mask &= Sector().eq(sector) #mask &= value_score > 30 mask &= PE < 35 mask &= USEquityPricing.volume.latest > 10000 '''pipeline''' pipe = Pipeline(columns={ 'Returns': returns, 'B/P': book_to_price, 'P/E': PE, 'Dividends': gross_dividend_payment, 'Value Score': value_score, 'Growth_Score': growth_score, 'Profit_Grade': profit_grade, 'Financial_Health': financial_health_grade }, screen=mask) return pipe
class Momentum(CustomFactor): inputs = [Returns(window_length=10)] window_length = 10 def compute(self, today, assets, out, lag_returns): out[:] = lag_returns[0]
def make_pipeline(context): """ A function to create our pipeline (dynamic stock selector). The pipeline is used to rank stocks based on different factors, including builtin factors, or custom factors that you can define. Documentation on pipeline can be found here: https://www.quantopian.com/help#pipeline-title """ # Filter for stocks in the Q1500US universe. For more detail, see this post: # https://www.quantopian.com/posts/the-q500us-and-q1500us # universe = Q1500US() # Create a Returns factor with a 5-day lookback window for all # securities in our Q1500US Filter. recent_returns = Returns(window_length=context.returns_lookback,mask=filters.default_us_equity_universe_mask(minimum_market_cap=0)) # Define high and low returns filters to be the bottom 10% and top 10% of # securities in the high dollar-volume group. low_returns = recent_returns.bottom(50) target_sector = context.sector.eq(101) # Add a filter to the pipeline such that only high-return and low-return # securities are kept. securities_to_trade = (low_returns&target_sector) # Create a pipeline object with the defined columns and screen. pipe = Pipeline( columns={ 'low_returns': low_returns, }, screen = securities_to_trade ) return pipe
def make_pipeline(context): """ A function to create our pipeline (dynamic stock selector). The pipeline is used to rank stocks based on different factors, including builtin factors, or custom factors that you can define. Documentation on pipeline can be found here: https://www.quantopian.com/help#pipeline-title """ # Filter for stocks in the QTradableStocksUS universe. For more detail, see this post: # https://www.quantopian.com/posts/working-on-our-best-universe-yet-qtradablestocksus universe = QTradableStocksUS() # Create a Returns factor with a 5-day lookback window for all # securities in our QTradableStocksUS Filter. recent_returns = Returns(window_length=context.returns_lookback, mask=universe) # Define high and low returns filters to be the bottom 10% and top 10% of # securities in the high dollar-volume group. low_returns = recent_returns.percentile_between(0, 10) high_returns = recent_returns.percentile_between(90, 100) # Add a filter to the pipeline such that only high-return and low-return # securities are kept. securities_to_trade = (low_returns | high_returns) # Create a pipeline object with the defined columns and screen. pipe = Pipeline(columns={ 'low_returns': low_returns, 'high_returns': high_returns, }, screen=securities_to_trade) return pipe
def make_fundamentals_pipeline(): base_universe = StaticAssets([asset]) #Fundamentals returns = Returns(window_length=2) pe_ratio = Fundamentals.pe_ratio.latest current_assets = Fundamentals.current_assets.latest current_debt = Fundamentals.current_debt.latest enterprise_value = Fundamentals.enterprise_value.latest eps_earnings = Fundamentals.basic_eps_earnings_reports.latest avg_earnings = Fundamentals.basic_average_shares_earnings_reports.latest accrued_expenses = Fundamentals.current_accrued_expenses.latest current_liabilities = Fundamentals.current_liabilities.latest return Pipeline( screen = base_universe, columns={ 'daily_returns': returns, 'pe_ratio': pe_ratio, 'current_assets' : current_assets, 'current_debt' : current_debt, 'eps_earnings' : eps_earnings, 'enterprise_value' : enterprise_value, 'avg_earnings' : avg_earnings, 'accrued_exspenses' : accrued_expenses, 'liabilities' : current_liabilities})
def make_ml_pipeline(universe, window_length=126, n_forward_days=21): pipeline_columns = OrderedDict() # ensure that returns is the first input pipeline_columns['Returns'] = Returns( inputs=(USEquityPricing.open,), mask=universe, window_length=n_forward_days + 1, ) # rank all the factors and put them after returns pipeline_columns.update({ k: v().zscore(mask=universe) for k, v in features.items() }) # Create our ML pipeline factor. The window_length will control how much # lookback the passed in data will have. pipeline_columns['ML'] = ML( inputs=pipeline_columns.values(), window_length=window_length + 1, mask=universe, ) pipeline_columns['Sector'] = Sector() return Pipeline(screen=universe, columns=pipeline_columns)
class Mean_Reversion_1M(CustomFactor): inputs = [Returns(window_length=21)] window_length = 252 def compute(self, today, assets, out, monthly_rets): out[:] = (monthly_rets[-1] - np.nanmean( monthly_rets, axis=0)) / np.nanstd(monthly_rets, axis=0)
def make_pipeline(): """ A function to create our dynamic stock selector (pipeline). Documentation on pipeline can be found here: https://www.quantopian.com/help#pipeline-title """ base_universe = Q1500US() sector = Sector() # screen is based off of returns returns = Returns(window_length=2) # check if stock price has good strength, but not necessarily overbought rsi = RSI() price = USEquityPricing.close.latest # creating filter by specifying the type of returns desired top_return_stocks = returns.top(1, mask=base_universe, groupby=sector) pipe = Pipeline( columns={ 'rsi': rsi, 'price': price }, # filter top return stocks, and stocks that are not being overbought # but are not too oversold either screen=base_universe & top_return_stocks & (20 < rsi < 80) # the above is equivalent to: choose stocks from the base universe that have had the top returns in their sectors and have a good RSI value ) return pipe
class Returns(CustomFactor): """Equity Momentum""" inputs = [Returns(window_length=20)] window_length = 2 def compute(self, today, assets, out, ret): out[:] = ret[0]
class aa_momentum(CustomFactor): """ Alpha Architect - Momentum factor """ inputs = [USEquityPricing.close, Returns(window_length=126)] window_length = 252 def compute(self, today, assets, out, prices, returns): out[:] = ((prices[-21] - prices[-252])/prices[-252] - (prices[-1] - prices[-21])/prices[-21]) / np.nanstd(returns, axis=0)
class PercentChange(CustomFactor): """ Momentum factor """ inputs = [USEquityPricing.close, Returns(window_length=126)] window_length = 252 def compute(self, today, assets, out, prices, returns): out[:] = ((prices[-1] - prices[-21]) / prices[-21]) / np.nanstd( returns, axis=0)
def make_pipeline(): universe = QTradableStocksUS() # Variables Seleccionadas Del Dataframe de Fundamentals value = Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest working_capital = Fundamentals.working_capital.latest restricted_cash = Fundamentals.restricted_cash.latest cash_and_cash_equivalents = Fundamentals.cash_and_cash_equivalents.latest goodwill = Fundamentals.goodwill.latest capital_stock = Fundamentals.capital_stock.latest total_assets = Fundamentals.total_assets.latest common_stock = Fundamentals.common_stock.latest free_cash_flow = Fundamentals.free_cash_flow.latest recent_returns = Returns(window_length=RETURNS_LOOKBACK_DAYS, mask=universe) # Winsorized - Variables (SIN ATIPICOS) value_winsorized = value.winsorize(min_percentile=0.05, max_percentile=0.95) working_capital = working_capital.winsorize(min_percentile=0.05, max_percentile=0.95) restricted_cash = restricted_cash.winsorize(min_percentile=0.05, max_percentile=0.95) cash_and_cash_equivalents = cash_and_cash_equivalents.winsorize( min_percentile=0.05, max_percentile=0.95) goodwill = goodwill.winsorize(min_percentile=0.05, max_percentile=0.95) capital_stock = capital_stock.winsorize(min_percentile=0.05, max_percentile=0.95) total_assets = total_assets.winsorize(min_percentile=0.05, max_percentile=0.95) common_stock = common_stock.winsorize(min_percentile=0.05, max_percentile=0.95) free_cash_flow = free_cash_flow.winsorize(min_percentile=0.05, max_percentile=0.95) recent_returns = recent_returns.winsorize(min_percentile=0.05, max_percentile=0.95) # FACTOR COMBINADO combined_factor = ( value_winsorized.zscore() * 0.05 + working_capital.zscore() * 0.55 + restricted_cash.zscore() * 0.2 + cash_and_cash_equivalents.zscore() * 0.01 + goodwill.zscore() * 0.01 + capital_stock.zscore() * 0.1 + total_assets.zscore() * 0.01 + common_stock.zscore() * 0.01 + free_cash_flow.zscore() * 0.01 + recent_returns.zscore() * 0.05) longs = combined_factor.top(TOTAL_POSITIONS // 2, mask=universe) shorts = combined_factor.bottom(TOTAL_POSITIONS // 2, mask=universe) long_short_screen = (longs | shorts) pipe = Pipeline(columns={ 'longs': longs, 'shorts': shorts, 'combined_factor': combined_factor }, screen=long_short_screen) return pipe
class Downside_Volatility(CustomFactor): # Use returns as the input inputs = [Returns(window_length=2)] window_length = 10 def compute(self, today, assets, out, returns): # set any returns greater than 0 to NaN so they are excluded from our calculations returns[returns > 0] = np.nan out[:] = np.nanstd(returns, axis=0)
class OBV(CustomFactor): inputs = [Returns(window_length=21)] window_length = 21 def compute(self, today, assets, out, vol): prevDay = vol[-21] current = vol[-1] out[:] = (prevDay - current) / prevDay
class Momentum(CustomFactor): """ Conventional Momentum factor """ inputs = [USEquityPricing.close, Returns(window_length=126)] window_length = 252 # /np.nanstd(returns, axis=0) def compute(self, today, assets, out, prices, returns): out[:] = ((prices[-21] - prices[-252]) / prices[-252] - (prices[-1] - prices[-21]) / prices[-21])
def make_pipeline(): """ Create and return our pipeline. We break this piece of logic out into its own function to make it easier to test and modify in isolation. In particular, this function can be copy/pasted into research and run by itself. """ # Basic momentum metrics. cross_momentum = CrossSectionalMomentum() abs_momentum = Returns(inputs=[USEquityPricing.close], window_length=252) # We only want to trade relatively liquid stocks. # Build a filter that only passes stocks that have $10,000,000 average # daily dollar volume over the last 20 days. dollar_volume = AverageDollarVolume(window_length=20) is_liquid = (dollar_volume > 1e7) # We also don't want to trade penny stocks, which we define as any stock with an # average price of less than $5.00 over the last 200 days. sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200) not_a_penny_stock = (sma_200 > 5) # Before we do any other ranking, we want to throw away the bad assets. initial_screen = (is_liquid & not_a_penny_stock) # By applying a mask to the rank computations, we remove any stocks that failed # to meet our initial criteria **before** computing ranks. This means that the # stock with rank 10.0 is the 10th-lowest stock that passed `initial_screen`. combined_rank = (cross_momentum.rank(mask=initial_screen) + abs_momentum.rank(mask=initial_screen)) # Build Filters representing the top and bottom 5% of stocks by our combined ranking system. # We'll use these as our tradeable universe each day. longs = combined_rank.percentile_between(95, 100) shorts = combined_rank.percentile_between(0, 5) # The final output of our pipeline should only include # the top/bottom 5% of stocks by our criteria. pipe_screen = (longs | shorts) pipe_columns = { 'longs': longs, 'shorts': shorts, 'combined_rank': combined_rank, 'abs_momentum': abs_momentum, 'cross_momentum': cross_momentum } # Create pipe pipe = Pipeline(columns=pipe_columns, screen=pipe_screen) return pipe
def make_history_pipeline(factors, universe, n_fwd_days=5): # Call .rank() on all factors and mask out the universe factor_ranks = {name: f().rank(mask=universe) for name, f in factors.iteritems()} # Get cumulative returns over last n_fwd_days days. We will later shift these. factor_ranks['Returns'] = Returns(inputs=[USEquityPricing.open], mask=universe, window_length=n_fwd_days) pipe = Pipeline(screen=universe, columns=factor_ranks) return pipe
def Asset_Growth_3M(): """ 3-month Asset Growth: Increase in total assets over 3 months https://www.pnc.com/content/dam/pnc-com/pdf/personal/wealth-investments/WhitePapers/FactorAnalysisFeb2014.pdf # NOQA Notes: High value represents good financial health as quantity of assets is increasing """ return Returns(inputs=[bs.total_assets], window_length=63)
def Price_Momentum_12M(): """ 12-Month Price Momentum: 12-month closing price rate of change. https://www.pnc.com/content/dam/pnc-com/pdf/personal/wealth-investments/WhitePapers/FactorAnalysisFeb2014.pdf # NOQA Notes: High value suggests momentum (long term) Equivalent to analysis of returns (12-month window) """ return Returns(window_length=252)
class MeanReversion1M(CustomFactor): inputs = (Returns(window_length=21),) window_length = 252 def compute(self, today, assets, out, monthly_rets): np.divide( monthly_rets[-1] - np.nanmean(monthly_rets, axis=0), np.nanstd(monthly_rets, axis=0), out=out, )
def make_pipeline(): #0. Select top-1500 liquid stocks base_universe = Q1500US() #1. Market Capitalization Filter, select top 1200 out of 1500 market_cap = MarketCap(mask=base_universe) top_market_cap = market_cap.top(1200) #2. B/M Filter, select top 5000 out of all stocks (~8200) btom = morningstar.valuation_ratios.book_value_yield.latest top_btom = btom.top(5000) #3. Interception of 1st and 2nd filters results, on average returns ~1000 stocks top_cap_btom = top_market_cap & top_btom #4. Top Performers filter, select top 100 latest_return_7_1 = Returns( inputs=[USEquityPricing.close], window_length=147, mask=top_cap_btom) / Returns(inputs=[USEquityPricing.close], window_length=21, mask=top_cap_btom) top_performers = latest_return_7_1.top(100) #5. Smoothest Returns filter, select 50 smoothest r_7 = Returns(window_length=21, mask=top_performers) r_6 = (Returns(window_length=42, mask=top_performers) + 1) / (r_7 + 1) - 1 r_5 = (Returns(window_length=63, mask=top_performers) + 1) / ( (r_7 + 1) * (r_6 + 1)) - 1 r_4 = (Returns(window_length=84, mask=top_performers) + 1) / ( (r_7 + 1) * (r_6 + 1) * (r_5 + 1)) - 1 r_3 = (Returns(window_length=105, mask=top_performers) + 1) / ( (r_7 + 1) * (r_6 + 1) * (r_5 + 1) * (r_4 + 1)) - 1 r_2 = (Returns(window_length=126, mask=top_performers) + 1) / ( (r_7 + 1) * (r_6 + 1) * (r_5 + 1) * (r_4 + 1) * (r_3 + 1)) - 1 r_1 = (Returns(window_length=147, mask=top_performers) + 1) / ( (r_7 + 1) * (r_6 + 1) * (r_5 + 1) * (r_4 + 1) * (r_3 + 1) * (r_2 + 1)) - 1 r_mean = (r_1 + r_2 + r_3 + r_4 + r_5 + r_6) / 6.0 varr = ((r_1 - r_mean)**2 + (r_2 - r_mean)**2 + (r_3 - r_mean)**2 + (r_4 - r_mean)**2 + (r_5 - r_mean)**2 + (r_6 - r_mean)** 2) / 6.0 #Sample variance of monthly returns of each stock top_smooth = varr.bottom(50) #6. Screening filter, if (tradeable) then buy this stock tradeable = top_smooth return Pipeline(screen=tradeable, columns={'Tradeable': tradeable})
def make_pipeline(): returns = Returns(window_length=2) sentiment = stocktwits.bull_minus_bear.latest msg_volume = stocktwits.total_scanned_messages.latest return Pipeline(columns={ 'daily_returns': returns, 'sentiment': sentiment, 'msg_volume': msg_volume, }, )
class AdvancedMomentum(CustomFactor): inputs = (USEquityPricing.close, Returns(window_length=126)) window_length = 252 window_safe = True def compute(self, today, assets, out, prices, returns): am = np.divide(((prices[-21] - prices[-252]) / prices[-252] - prices[-1] - prices[-21]) / prices[-21], np.nanstd(returns, axis=0)) out[:] = preprocess(-am)
class AdvancedMomentum(CustomFactor): inputs = (USEquityPricing.close, Returns(window_length=126)) window_length = 252 def compute(self, today, assets, out, prices, returns): np.divide( ((prices[-21] - prices[-252]) / prices[-252] - prices[-1] - prices[-21]) / prices[-21], np.nanstd(returns, axis=0), out=out, )
def make_pipeline(): base_universe = Q500US() # 一週間のリターンをとりあえず過去5日間のリターンと考える fiveday_return = Returns(window_length=5) pipe = Pipeline(screen=base_universe, columns={ 'fiveday_return': fiveday_return, }) return pipe
def make_history_pipeline(factors, universe, n_fwd_days=5): # Call .rank() on all factors and mask out the universe factor_zscore = { name: f().zscore(mask=universe) for name, f in factors.iteritems() } # Get cumulative returns over last n_fwd_days days. We will later shift these. factor_zscore['Returns'] = Returns(inputs=[USEquityPricing.open], mask=universe, window_length=n_fwd_days) # Add many returns as factors for i in [2, 3, 4, 5, 10, 20, 30, 60, 100, 250]: factor_zscore['Return' + str(i)] = Returns( inputs=[USEquityPricing.open], mask=universe, window_length=i) #factor_zscore['SPY']=Returns(inputs=[USEquityPricing.open('SPY')] ) pipe = Pipeline(screen=universe, columns=factor_zscore) return pipe