def make_pipeline(): base_universe = QTradableStocksUS() beta = SimpleBeta( target=sid(8554), regression_length=260, ) universe = (Sector().notnull() & base_universe & beta.notnull()) AMTvol = AverageMonthlyTradingVolume() #market_cap = Fundamentals.market_cap.latest #book_to_price = 1/Fundamentals.pb_ratio.latest momentum = Momentum(window_length=252) growth = Fundamentals.growth_score.latest # Alpha Generation # ---------------- # Compute Z-scores AMTvol_z = AMTvol.zscore(mask=universe) growth_z = growth.zscore(mask=universe) large = AMTvol_z.percentile_between(80,100) fast = growth_z.percentile_between(80,100) momentum_z = momentum.zscore(mask=(universe & (fast | large))) # Alpha Combination # ----------------- # Assign every asset a combined rank and center the values at 0. # For UNIVERSE_SIZE=500, the range of values should be roughly -250 to 250. alpha1 = (momentum_z).rank().demean() # S2 monthly_top_volume = ( AverageDollarVolume(window_length=LIQUIDITY_LOOKBACK_LENGTH) .top(UNIVERSE_SIZE, mask=universe) .downsample(BASE_UNIVERSE_RECALCULATE_FREQUENCY)) universe2 = (monthly_top_volume & universe) vr = mstar.valuation_ratios #fcf_zscore = vr.fcf_yield.latest.zscore(mask=universe2) yield_zscore = vr.earning_yield.latest.zscore(mask=universe2) roe_zscore = Fundamentals.roic.latest.zscore(mask=universe2) ltd_to_eq = Fundamentals.long_term_debt_equity_ratio.latest.zscore(mask=universe2) value = (Fundamentals.cash_return.latest.zscore(mask=universe2) + Fundamentals.fcf_yield.latest.zscore(mask=universe2)).zscore() quality = (roe_zscore + ltd_to_eq +value + 0) #alpha2 = (fcf_zscore + yield_zscore+quality).rank().demean() alpha2 = (yield_zscore+quality).rank().demean() combined_alpha = alpha1 + alpha2 return Pipeline( columns={ 'Momentum': momentum, 'Volume': AMTvol, 'Growth_score':growth, 'sector':Sector(), 'alpha':combined_alpha, 'beta': beta, }, screen= combined_alpha.notnull() )
def initialize(context): """ Called once at the start of the program. Any one-time startup logic goes here. """ # Define context variables that can be accessed in other methods of # the algorithm. context.long_leverage = 0.5 context.short_leverage = -0.5 context.returns_lookback = 2 context.sector = Sector() # Rebalance on the first trading day of each week at 11AM. schedule_function(rebalance, date_rules.every_day(), time_rules.market_close(minutes=1)) ''' # Record tracking variables at the end of each day. schedule_function(record_vars, date_rules.every_day(), time_rules.market_close(minutes=1)) ''' set_commission(commission.PerShare(cost=0, min_trade_cost=10)) # Create and attach our pipeline (dynamic stock selector), defined below. attach_pipeline(make_pipeline(context), 'mean_reversion_example')
def make_pipeline(context): mask = Q500US() #lb_13 = -Returns(window_length=13, mask=mask) weekly_return = Returns(window_length=6, mask=mask) pipe = Pipeline( columns={ 'weekly_return': weekly_return, 'sector': Sector(), }, # combined_alpha will be NaN for all stocks not in our universe, # but we also want to make sure that we have a sector code for everything # we trade. screen=weekly_return.notnull() & Sector().notnull(), ) return pipe
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
def make_pipeline(): #Nuestro universo de acciones serán todas aquellas que se puedan comprar en US# base_universe = QTradableStocksUS() #Nuestro primer factor será el fcf: Cash Flow Operations minus Capital Expenditures.# fcf_growth = Fundamentals.free_cash_flow.latest #Segundo factor será el ROIC: Net Income / (Total Equity + Long-term Debt and Capital Lease Obligation + Short-term Debt and Capital Lease Obligation)# roic = morningstar.operation_ratios.roic.latest #Filtramos por aquellas con Roic más alto (he estado jugando con los percentiles por lo que quizas el rto no sea el mismo)# high_roic = roic.percentile_between(60,100, mask=base_universe) #Filtramos por aquellas con FCF que más ha crecido# high_fcfgrowth = fcf_growth.percentile_between(60, 100, mask = base_universe) #Mezclamos los dos anteriores y hacemos un único ranking# securities_of_high_growth = (high_roic & high_fcfgrowth) #De ese ranking queremos que nos saque los siguientes datos# return Pipeline( columns = { 'Return on Invested Capital': roic, 'Top Growth Company': securities_of_high_growth, 'FCF Growth': fcf_growth, 'Sector': Sector(), }, screen = securities_of_high_growth ) #Debe devolver a la función anterior el Pipeline# return Pipeline()
def make_pipeline(context): base_universe = Q500US() # 昨日の終値 yesterday_close = USEquityPricing.close.latest yesterday_volume = USEquityPricing.volume.latest dollar_volume = AverageDollarVolume(window_length=30) high_dollar_volume = dollar_volume.percentile_between( context.high_dollar_volume_thresh_min, context.high_dollar_volume_thresh_max) sector = Sector() rsi = RSI(inputs=[USEquityPricing.close]) pipe = Pipeline(screen=base_universe & high_dollar_volume, columns={ 'high_dollar_volume': high_dollar_volume, 'sector': sector, 'rsi': rsi, 'roa': ROA(), 'roe': ROE(), 'normalized_basic_eps': NormalizedBasicEps(), 'net_income_growth': NetIncomeGrowth(), 'pe': PE(), 'book_value_yield': BookValueYield(), 'dividend_yield': DividendYield(), 'period_ending_date': PeriodEndingDate(), 'prev_close': yesterday_close, }) return pipe
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. """ # Create our mean reversion factor by taking the negative of a momentum factor reversion = Reversion() # Classify all securities by sector so that we can enforce sector neutrality later sector = Sector() # Screen out non-desirable securities by defining our universe. universe = Q1500US() # 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 was included in the Q1500US. # 標準偏差 # filter のかけかたを mask で行ってしまう factor_rank = reversion.rank(mask=universe).zscore() # Build Filters representing the top and bottom 150 stocks by our ranking system. # We'll use these as our tradeable universe each day. longs = factor_rank.top(NUM_LONG_POSITIONS) shorts = factor_rank.bottom(NUM_SHORT_POSITIONS) # The final output of our pipeline should only include # the top/bottom 300 stocks by our criteria long_short_screen = (longs | shorts) # Define any risk factors that we will want to neutralize # We are chiefly interested in market beta as a risk factor so we define it using # Bloomberg's beta calculation # Ref: https://www.lib.uwo.ca/business/betasbydatabasebloombergdefinitionofbeta.html beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen ).beta + 0.33*1.0 # Create pipeline pipe = Pipeline( columns={ 'longs': longs, 'shorts': shorts, 'factor_rank': factor_rank, 'reversion': reversion, 'sector': sector, 'market_beta': beta }, screen=long_short_screen ) return pipe
def make_pipeline(context): """ Builds a Pipeline with Bollinger bands for top NUM_SYMBOLS stocks by market cap in the tech sector. Starts out from the Q500US base universe. """ # Base universe of top 500 US stocks. base_universe_filter = Q500US() # Stocks of only tech sector. tech_sector = Sector(mask=base_universe_filter) tech_universe_filter = base_universe_filter & tech_sector.eq(311) # Top 10 tech stocks with largest market cap. mkt_cap_filter = morningstar.valuation.market_cap.latest top_mkt_cap_tech_filter = mkt_cap_filter.top(context.NUM_SYMBOLS, mask=tech_universe_filter) # Bollinger band factor with Stdev factor 2. lower_band_factor, middle_factor, upper_band_factor = BollingerBands( window_length=22, k=2, mask=top_mkt_cap_tech_filter) # Percent difference between (price, lower_band) and (price, upper_band). price = USEquityPricing.close.latest buy_percent_factor = ((lower_band_factor - price) * 100) / price sell_percent_factor = ((price - upper_band_factor) * 100) / price # Mean reversion buy and sell filters. # Sell when price exceeds upper-band and buy when price is below lower-band. buy_filter = buy_percent_factor > 0 sell_filter = sell_percent_factor > 0 # Build and return the Pipeline. pipe_bbands = Pipeline(columns={ 'buy_percent': buy_percent_factor, 'lower_band': lower_band_factor, 'buy': buy_filter, 'price': price, 'sell': sell_filter, 'upper_band': upper_band_factor, 'sell_percent': sell_percent_factor }, screen=top_mkt_cap_tech_filter) return pipe_bbands
def make_pipeline(context): ## symbol universe base_universe = Q500US() if False else Q1500US() ## filters # Filter for primary share equities. IsPrimaryShare is a built-in filter. primary_share = IsPrimaryShare() # Equities listed as common stock (as opposed to, say, preferred stock). # 'ST00000001' indicates common stock. common_stock = morningstar.share_class_reference.security_type.latest.eq( 'ST00000001') # Non-depositary receipts. Recall that the ~ operator inverts filters, # turning Trues into Falses and vice versa not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest # Equities not trading over-the-counter. not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith( 'OTC') # Not when-issued equities. not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI') # Equities without LP in their name, .matches does a match using a regular expression not_lp_name = ~morningstar.company_reference.standard_name.latest.matches( '.* L[. ]?P.?$') # Equities with a null value in the limited_partnership Morningstar fundamental field. not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull( ) # Equities whose most recent Morningstar market cap is not null have fundamental data and therefore are not ETFs. have_market_cap = morningstar.valuation.market_cap.latest.notnull() is_cyclical = SuperSector().eq(SuperSector.CYCLICAL) is_defensive = SuperSector().eq(SuperSector.DEFENSIVE) is_sensitive = SuperSector().eq(SuperSector.SENSITIVE) sector = Sector() close = USEquityPricing.close # For filter tradeable_stocks = (primary_share & common_stock & not_depositary & not_otc & not_wi & not_lp_name & not_lp_balance_sheet & have_market_cap & (is_cyclical | is_defensive | is_sensitive)) dollar_volume = AverageDollarVolume(window_length=30) high_dollar_volume = dollar_volume.percentile_between(98, 100) myscreen = (base_universe & tradeable_stocks & high_dollar_volume) # Pipeline pipe = Pipeline(columns={ 'yesterday_close': close.latest, 'day_before_yesterday_close': PrevClose(), 'day_before_yesterday_volume': PrevVolume(), 'morningstar_sector_code': sector, }, screen=myscreen) return pipe
def MYQ500US(): return make_us_equity_universe( target_size=500, rankby=AverageDollarVolume(window_length=200), mask=default_us_equity_universe_mask(), groupby=Sector(), max_group_weight=1.0, smoothing_func=lambda f: f.downsample('month_start'), )
def make_pipeline(): minprice = USEquityPricing.close.latest > 5 not_announced_acq_target = ~IsAnnouncedAcqTarget() pipe = Pipeline(screen=Q1500US() & minprice & not_announced_acq_target) sectors = Sector() pipe.add(sectors, 'sector') pipe.add(BusinessDaysSincePreviousEarnings(), 'PE') return pipe
def make_pipeline(): base_universe = QTradableStocksUS() gross_margin = morningstar.operation_ratios.gross_margin.latest roa = morningstar.operation_ratios.roa.latest factor_to_analyze = gross_margin.zscore() + roa.zscore() sector = Sector() return Pipeline(columns={ 'factor to analyze': factor_to_analyze, 'sector': sector }, screen=base_universe & sector.notnull() & factor_to_analyze.notnull())
def initialize(context): ## plugging in our factors into existing code testing_factor1 = operation_ratios.operation_margin.latest testing_factor2 = operation_ratios.revenue_growth.latest testing_factor3 = sentiment.sentiment_signal.latest universe = (Q1500US() & testing_factor1.notnull() & testing_factor2.notnull() & testing_factor3.notnull()) testing_factor1 = testing_factor1.rank(mask=universe, method='average') testing_factor2 = testing_factor2.rank(mask=universe, method='average') testing_factor3 = testing_factor3.rank(mask=universe, method='average') combined_alpha = testing_factor1 + testing_factor2 + testing_factor3 testing_quantiles = combined_alpha.quantiles(2) # Schedule Tasks # -------------- # Create and register a pipeline computing our combined alpha and a sector # code for every stock in our universe. We'll use these values in our # optimization below. pipe = Pipeline( columns={ 'alpha': combined_alpha, 'sector': Sector(), }, # combined_alpha will be NaN for all stocks not in our universe, # but we also want to make sure that we have a sector code for everything # we trade. screen=combined_alpha.notnull() & Sector().notnull(), ) algo.attach_pipeline(pipe, 'pipe') # Schedule a function, 'do_portfolio_construction', to run once a week # ten minutes after market open. algo.schedule_function( do_portfolio_construction, date_rule=algo.date_rules.week_start(), time_rule=algo.time_rules.market_open(minutes=MINUTES_AFTER_OPEN_TO_TRADE), half_days=False, )
def make_pipeline(context): profitable = mstar.valuation_ratios.ev_to_ebitda.latest > 0 market_cap = mstar.valuation.market_cap.latest my_screen = market_cap.top(context.n_stocks, mask=(Q1500US() & profitable)) return Pipeline(columns={ 'sector': Sector(), }, screen=my_screen)
def make_pipeline(): pipe = Pipeline() # Set the universe to the QTradableStocksUS & stocks with Sector and Top 2000 by MarketCap universe = MarketCap().top(2000, mask = QTradableStocksUS()) & Sector().notnull() #filter more with momentum and volarility filter(lowest 600 volatility stocks) momentum = Momentum() volatility = Volatility() volatility_rank = volatility.rank(mask=universe, ascending=True) pipe.set_screen(universe & (volatility_rank.top(600)) & (momentum>1)) # Creating Price_to_book,Price_to_earnings, and return_on_assets, return_on_Equity, Return on Invested Capital Objects, and Dividend_yield Object and Rank them #Create Price to book and Price to Earning and rank them, the lower the ratio, the better pb = Price_to_Book() pb_rank = pb.rank(mask=universe, ascending=True) pe = Price_to_Earnings() pe_rank = pe.rank(mask=universe, ascending=True) #Create Return on Assets, Return on Equity, Return on Invested Capital and Dividend Yield Class and rank them,the higher the ratio, the better roa = Return_on_Assets() roa_rank = roa.rank(mask=universe, ascending=False) roe = Return_on_Equity() roe_rank = roe.rank(mask=universe, ascending=False) roic = Return_on_Invested_Capital() roic_rank = roic.rank(mask=universe, ascending=False) earnings_yield = Earnings_Yield() EY_rank = earnings_yield.rank(ascending=False, mask=universe) dy = Dividend_Yield() dy_rank = dy.rank(mask=universe, ascending=False) #Give 1 weight forall metrics such as P/e,P/B,Dividend Yield,Return on Assets,Equity and Invested Capital the_ranking_score = (pb_rank+pe_rank+dy_rank+roa_rank+roe_rank+roic_rank*2 + EY_rank)/8 # Rank the combo_raw and add that to the pipeline pipe.add(the_ranking_score.rank(mask=universe), 'ranking_score') return pipe
def make_pipeline(investment_set): """ This will return the selected stocks by market cap, dynamically updated. """ # Base universe base_universe = investment_set yesterday_close = USEquityPricing.close.latest pipe = Pipeline(screen=base_universe, columns={ 'close': yesterday_close, 'sector': Sector() }) return pipe
def make_pipeline(): # Sector sector = Sector() # Equity Filters mkt_cap_filter = morningstar.valuation.market_cap.latest >= 500000000 price_filter = USEquityPricing.close.latest >= 5 nan_filter = sentiment_free.sentiment_signal.latest.notnull() # Universe universe = Q1500US() & price_filter & mkt_cap_filter & nan_filter # Rank sentiment_signal = sentiment_free.sentiment_signal.latest sma_30 = SimpleMovingAverage(inputs=[sentiment_free.sentiment_signal], window_length=30, mask=universe) combined_rank = (sentiment_signal + sma_30.rank(mask=universe).zscore()) # Long and Short Positions longs = combined_rank.top(NUM_LONG_POSITIONS) shorts = combined_rank.bottom(NUM_SHORT_POSITIONS) long_short_screen = (longs | shorts) # Bloomberg Beta Implementation beta = 0.66 * RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen).beta + 0.33 * 1.0 pipe = Pipeline() pipe.add(longs, 'longs') pipe.add(shorts, 'shorts') pipe.add(combined_rank, 'combined_rank') pipe.add(sentiment_free.sentiment_signal.latest, 'sentiment_signal') pipe.add(sma_30, 'sma_30') pipe.add(sector, 'sector') pipe.add(beta, 'market_beta') pipe.set_screen(universe) return pipe
def make_ml_pipeline(factors, universe, window_length=21, n_fwd_days=5): factors_pipe = OrderedDict() # Create returns over last n days. factors_pipe['Returns'] = Returns(inputs=[USEquityPricing.open], mask=universe, window_length=n_fwd_days + 1) # Instantiate ranked factors for name, f in factors.iteritems(): factors_pipe[name] = f().rank(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['Sector'] = Sector() pipe = Pipeline(screen=universe, columns=factors_pipe) return pipe
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 set to the QTradableStocksUS base_universe = QTradableStocksUS()#Q500US() base_universe = (base_universe & Q500US()) #base_universe = (base_universe & Fundamentals.market_cap.latest.top(150)) # Factor of yesterday's close price. #yesterday_close = USEquityPricing.close.latest pipe = Pipeline( columns={ #'close': yesterday_close, 'sector': Sector(), }, screen=base_universe ) 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) factor_zscore['Momentum'] = Momentum(mask=universe) factor_zscore['Sectors'] = Sector(mask=universe) # Add many returns as factors for i in [2, 3, 4, 5, 10, 20]: 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
def make_pipeline(context): ## symbol universe base_universe = Q500US() if False else Q1500US() ## filters # Filter for primary share equities. IsPrimaryShare is a built-in filter. primary_share = IsPrimaryShare() # Equities listed as common stock (as opposed to, say, preferred stock). # 'ST00000001' indicates common stock. common_stock = morningstar.share_class_reference.security_type.latest.eq('ST00000001') # Non-depositary receipts. Recall that the ~ operator inverts filters, # turning Trues into Falses and vice versa not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest # Equities not trading over-the-counter. not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith('OTC') # Not when-issued equities. not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI') # Equities without LP in their name, .matches does a match using a regular expression not_lp_name = ~morningstar.company_reference.standard_name.latest.matches('.* L[. ]?P.?$') # Equities with a null value in the limited_partnership Morningstar fundamental field. not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull() # Equities whose most recent Morningstar market cap is not null have fundamental data and therefore are not ETFs. have_market_cap = morningstar.valuation.market_cap.latest.notnull() is_cyclical = SuperSector().eq(SuperSector.CYCLICAL) is_defensive = SuperSector().eq(SuperSector.DEFENSIVE) is_sensitive = SuperSector().eq(SuperSector.SENSITIVE) # Filter for stocks that pass all of our previous filters. tradeable_stocks = ( primary_share &common_stock ¬_depositary ¬_otc ¬_wi ¬_lp_name ¬_lp_balance_sheet &have_market_cap #&(is_cyclical) #&(is_defensive) #&(is_sensitive) &(is_cyclical | is_defensive | is_sensitive) ) # ToDo この範囲を色々変えてみる. dollar_volume = AverageDollarVolume(window_length=30) high_dollar_volume = dollar_volume.percentile_between(98, 100) daily_volatility = AnnualizedVolatility(window_length=20)/math.sqrt(252) sme20 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=20) rsi = RSI(inputs=[USEquityPricing.close]) #sector = ms.asset_classification.morningstar_sector_code sector = Sector() static_sectors = (sector.eq(311) | sector.eq(309) | sector.eq(103) | sector.eq(101) | sector.eq(308) | sector.eq(206) ) if context.static_asset: myscreen = StaticSids(context.special_sids) #context.special_assets else: myscreen = (base_universe & tradeable_stocks & high_dollar_volume ) # & static_sectors pipe = Pipeline( columns={ 'prev_close': PrevClose(), 'prev_volume': PrevVolume(), 'prev_turnover': PrevClose()*PrevVolume(), 'dollar_volume': dollar_volume, 'high_dollar_volume': high_dollar_volume, 'daily_volatility': daily_volatility, 'sma20': sme20, 'rsi': rsi, 'morningstar_sector_code': sector, }, screen=myscreen, ) return pipe
'Percent Difference':percent_difference, '30 Day Mean Close':mean_close_30, 'Latest Close':latest_close, 'Positive Percent Diff': perc_diff_check}, screen=final_filter) results = run_pipeline(make_pipeline(),'2017-01-01','2017-01-01') results.head() len(results) ### Classifiers: for categorical output from quantopian.pipeline.data import morningstar from quantopian.pipeline.classifiers.morningstar import Sector morningstar_sector = Sector() exchange = morningstar.share_class_reference.exchange_id.latest exchange nyse_filter = exchange.eq('NYS') def make_pipeline(): # Create Filters for Masks First latest_close = USEquityPricing.close.latest small_price = latest_close < 5 # Classifier nyse_filter = exchange.eq('NYS') # Pass in the mask
def make_pipeline(): """ Defining out trading universe and alpha factor for long and short equities """ operation_margin = operation_ratios.operation_margin.latest revenue_growth = operation_ratios.revenue_growth.latest value = (Fundamentals.ebit.latest / Fundamentals.enterprise_value.latest) roe = Fundamentals.roe.latest momentum = Momentum() liquidity = Liquidity() free_cash_flows = morningstar.valuation_ratios.fcf_yield.latest earnings_yield = morningstar.valuation_ratios.earning_yield.latest # Filter for stocks that are announced acquisition target. not_announced_acq_target = ~IsAnnouncedAcqTarget() mkt_cap_filter = morningstar.valuation.market_cap.latest >= 500000000 # dividend_filter = Fundamentals.valuation_ratios.dividend_yield >= 0.02 # Our universe is made up of stocks that have a non-null factors & with market cap over 500 Million $, are not announced # acquisition targets, and are in the Q1500US. universe = ( QTradableStocksUS() # & not_near_earnings_announcement & not_announced_acq_target & earnings_yield.notnull() & free_cash_flows.notnull() & value.notnull() & roe.notnull() & mkt_cap_filter & momentum.notnull()) # combined_factor = roe*0 # for factor in factors: # combined_factor += factor.rank(mask=universe) # prediction_rank_quantiles = prediction_quality.quantiles(5) # longs = prediction_rank_quantiles.eq(4) # shorts = prediction_rank_quantiles.eq(0) combined_factor = ( earnings_yield.winsorize(min_percentile=0.05, max_percentile=0.95).zscore(mask=universe) + free_cash_flows.winsorize(min_percentile=0.05, max_percentile=0.95).zscore(mask=universe) + value.winsorize(min_percentile=0.05, max_percentile=0.95).zscore(mask=universe) + roe.winsorize(min_percentile=0.05, max_percentile=0.95).zscore(mask=universe) + momentum.winsorize(min_percentile=0.05, max_percentile=0.95).zscore(mask=universe)) combined_factor_quantiles = combined_factor.quantiles(10) longs = combined_factor_quantiles.eq(9) shorts = combined_factor_quantiles.eq(0) # longs = combined_factor.top(2*TOTAL_POSITIONS//3, mask=universe) # shorts = combined_factor.bottom(TOTAL_POSITIONS//3, mask=universe) # We will take market beta into consideration when placing orders in our algorithm. beta = RollingLinearRegressionOfReturns(target=sid(8554), returns_length=5, regression_length=260, mask=(longs | shorts)).beta # I calculated the market beta using rolling window regression using Bloomberg's computation. # Ref: https://guides.lib.byu.edu/c.php?g=216390&p=1428678 bb_beta = (0.66 * beta) + (0.33 * 1.0) ## create pipeline columns = { 'longs': longs, 'shorts': shorts, 'market_beta': bb_beta, 'sector': Sector(), 'combined_factor': combined_factor, } pipe = Pipeline(columns=columns, screen=(longs | shorts)) return pipe
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. """ # Create our momentum, value, and quality factors momentum = Momentum() # By appending .latest to the imported morningstar data, we get builtin Factors # so there's no need to define a CustomFactor value = morningstar.income_statement.ebit.latest / morningstar.valuation.enterprise_value.latest quality = morningstar.operation_ratios.roe.latest # Classify all securities by sector so that we can enforce sector neutrality later sector = Sector() # Screen out non-desirable securities by defining our universe. # Removes ADRs, OTCs, non-primary shares, LP, etc. # Also sets a minimum $500MM market cap filter and $5 price filter mkt_cap_filter = morningstar.valuation.market_cap.latest >= 500000000 price_filter = USEquityPricing.close.latest >= 5 universe = Q1500US() & price_filter & mkt_cap_filter # Construct a Factor representing the rank of each asset by our momentum, # value, and quality metrics. We aggregate them together here using simple # addition. # # 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 was included in the Q1500US. combined_rank = ( momentum.rank(mask=universe).zscore() + value.rank(mask=universe).zscore() + quality.rank(mask=universe).zscore() ) # Build Filters representing the top and bottom 150 stocks by our combined ranking system. # We'll use these as our tradeable universe each day. longs = combined_rank.top(NUM_LONG_POSITIONS) shorts = combined_rank.bottom(NUM_SHORT_POSITIONS) # The final output of our pipeline should only include # the top/bottom 300 stocks by our criteria long_short_screen = (longs | shorts) # Define any risk factors that we will want to neutralize # We are chiefly interested in market beta as a risk factor so we define it using # Bloomberg's beta calculation # Ref: https://www.lib.uwo.ca/business/betasbydatabasebloombergdefinitionofbeta.html beta = 0.66*RollingLinearRegressionOfReturns( target=sid(8554), returns_length=5, regression_length=260, mask=long_short_screen ).beta + 0.33*1.0 # Create pipeline pipe = Pipeline(columns = { 'longs':longs, 'shorts':shorts, 'combined_rank':combined_rank, 'quality':quality, 'value':value, 'momentum':momentum, 'sector':sector, 'market_beta':beta }, screen = long_short_screen) return pipe
# ----- Pipeline construction ---------- pipe = Pipeline(screen=universe) pipe.add(factor, select_factor) # ------- Ranking factor top to bottom ------- factor_rank = factor.rank() # ------- Ranking factor top to bottom ------- factor_rank = factor.rank() # ------- Adding Factor Rank to Pipeline as separate column ------- pipe.add(factor_rank, 'factor_rank') # ------- Adding Sector categorization to Pipeline construction ------- pipe.add(Sector(), 'Sector') # ------- Measurement inteval for the analysis ------- #start = pd.Timestamp("2015-01-01") start = pd.Timestamp("2015-01-01") #end = pd.Timestamp("2017-06-30") #start = pd.Timestamp("2017-06-30") #start = pd.Timestamp("2017-08-01") end = pd.Timestamp("2017-08-29") # ------- Run the pipeline and measure runtime ------- start_timer = time() #results = run_pipeline(pipe, start_date=start, end_date=end).dropna() results = run_pipeline(pipe, start_date=start,
def universe_filters(): """ Create a Pipeline producing Filters implementing common acceptance criteria. Returns ------- zipline.Filter Filter to control tradeablility """ # Equities with an average daily volume greater than 750000. high_volume = (AverageDollarVolume(window_length=252) > 750000) # Not Misc. sector: sector_check = Sector().notnull() # Equities that morningstar lists as primary shares. # NOTE: This will return False for stocks not in the morningstar database. primary_share = IsPrimaryShare() # Equities for which morningstar's most recent Market Cap value is above $300m. have_market_cap = mstar.valuation.market_cap.latest > 300000000 # Equities not listed as depositary receipts by morningstar. # Note the inversion operator, `~`, at the start of the expression. not_depositary = ~mstar.share_class_reference.is_depositary_receipt.latest # Equities that listed as common stock (as opposed to, say, preferred stock). # This is our first string column. The .eq method used here produces a Filter returning # True for all asset/date pairs where security_type produced a value of 'ST00000001'. common_stock = mstar.share_class_reference.security_type.latest.eq( COMMON_STOCK) # Equities whose exchange id does not start with OTC (Over The Counter). # startswith() is a new method available only on string-dtype Classifiers. # It returns a Filter. not_otc = ~mstar.share_class_reference.exchange_id.latest.startswith('OTC') # Equities whose symbol (according to morningstar) ends with .WI # This generally indicates a "When Issued" offering. # endswith() works similarly to startswith(). not_wi = ~mstar.share_class_reference.symbol.latest.endswith('.WI') # Equities whose company name ends with 'LP' or a similar string. # The .matches() method uses the standard library `re` module to match # against a regular expression. not_lp_name = ~mstar.company_reference.standard_name.latest.matches( '.* L[\\. ]?P\.?$') # Equities with a null entry for the balance_sheet.limited_partnership field. # This is an alternative way of checking for LPs. not_lp_balance_sheet = mstar.balance_sheet.limited_partnership.latest.isnull( ) # Highly liquid assets only. Also eliminates IPOs in the past 12 months # Use new average dollar volume so that unrecorded days are given value 0 # and not skipped over # S&P Criterion liquid = ADV_adj() > 250000 # Add logic when global markets supported # S&P Criterion domicile = True # Keep it to liquid securities ranked_liquid = ADV_adj().rank(ascending=False) < 1500 universe_filter = (high_volume & primary_share & have_market_cap & not_depositary & common_stock & not_otc & not_wi & not_lp_name & not_lp_balance_sheet & liquid & domicile & sector_check & liquid & ranked_liquid) return universe_filter
def initialize(context): # To set a custom benchmark the following function can be called: # set_benchmark(symbol('IWV')) # Otherwise the default benchmark will be used (SPY). # Commission is set to be $0.005 per share and $1 per trade. set_commission( us_equities=commission.PerShare(cost=0.005, min_trade_cost=1)) # Exchange code of a firm. exchange = mstar.share_class_reference.exchange_id.latest # A filter rule is created that returns True only for # the stocks from the exchanges listed. my_exchanges = exchange.element_of(['NYSE', 'NYS', 'NAS', 'ASE']) # Market capitalisation, sector code and momentum of a firm. market_cap = MarketCap() sector = Sector() umd = Momentum() # Defining total_equity, operating_income and interest_expense as # corresponding values in the latest income statement and balance sheet. total_equity = mstar.balance_sheet.total_equity.latest operating_income = mstar.income_statement.operating_income.latest interest_expense = mstar.income_statement.interest_expense.latest # The trading universe is defined as QTradableStocksUS that falls into # my_exchanges and has data for umd, total_equity, operating_income, # interest_expense, market_cap and sector. universe_exchange = QTradableStocksUS() & umd.notnull( ) & my_exchanges & total_equity.notnull() & market_cap.notnull( ) & sector.notnull() & operating_income.notnull( ) & interest_expense.notnull() # Small and large market cap groups specified as percentile. small = (MarketCap(mask=universe_exchange).percentile_between(0, 50)) large = (MarketCap(mask=universe_exchange).percentile_between(50, 100)) # Create a filter that returns True for the assets in the universe # that belong to the given sector(s). sec = mstar.asset_classification.morningstar_sector_code.latest my_sec = sec.element_of([101]) # Here the universe redefined as universe_exchange that belongs # to the sector(s) in 'my_sec' and falls into either # small or large market cap group as defined above. # my_sec should be uncommented in case if a speficic sector is wanted. ''' Here are the sector codes that might be used: -1: 'Misc', 101: 'Basic Materials', 102: 'Consumer Cyclical', 103: 'Financial Services', 104: 'Real Estate', 205: 'Consumer Defensive', 206: 'Healthcare', 207: 'Utilities', 308: 'Communication Services', 309: 'Energy', 310: 'Industrials', 311: 'Technology' , ''' universe = universe_exchange & small #& my_sec # Book to market is defined as total_equity divided by the market_cap. # The value is normalised and ranked in an ascending order. bm = total_equity / market_cap bm_weights = bm.rank(ascending=True, mask=universe) # Operating profitability ratio is defined as operating_income subtracted # interest_expense divided by the total_equity. # The value is normalised and ranked in an ascending order. op = (operating_income - interest_expense) / total_equity op_weights = op.rank(ascending=True, mask=universe) # Price momentum values are ranked and normalised in an ascending order. umd_weights = umd.rank(ascending=True, mask=universe) # A class JoinFactors is defined that is used to combine the normalised # scores of the factors defined above. class JoinFactors(CustomFactor): #inputs = [factor1, factor2, ...] There can be multiple inputs. window_length = 1 def compute(self, today, assets, out, *inputs): array = np.concatenate(inputs, axis=0) out[:] = np.nansum(array, axis=0) out[np.all(np.isnan(array), axis=0)] = np.nan # window_safe declares that scores of the factors are robust to # pricing adjustments from splits or dividends. In other words, # the value that will be the same no matter what day you are # looking back from. This is a required step in order to # use them as the input to JoinFactors. bm_weights.window_safe = True op_weights.window_safe = True umd_weights.window_safe = True # The weights of the combined factor. 1, 2, 3 or more factors can be used. final_weights = JoinFactors(inputs=[bm_weights, op_weights, umd_weights], mask=universe) universe = final_weights.notnan() # The Pipeline object filled with the data defined above is returned. pipe = Pipeline( columns={ 'bm_weights': bm_weights, 'op_weights': op_weights, 'umd_weights': umd_weights, 'alpha': final_weights, 'exchange': exchange, 'market_cap': market_cap, 'sector': sector, }, # Screen out all the data points outside the trading universe. screen=universe) # The function attach_pipeline is called # to load the data in defined in the pipeline. algo.attach_pipeline(pipe, 'pipe') # Schedule a function, 'do_portfolio_construction', to run once a month # ten minutes after market is open. algo.schedule_function( do_portfolio_construction, date_rule=algo.date_rules.month_start(), time_rule=algo.time_rules.market_open(minutes=MINUTES_AFTER_MARKET), half_days=False, )
def make_pipeline(): """ Dynamically apply the custom factors defined below to select candidate stocks from the PreCog universe """ pred_quality_thresh = 0.5 # Filter for stocks that are not within 2 days of an earnings announcement. not_near_earnings_announcement = ~( (BusinessDaysUntilNextEarnings() <= 2) | (BusinessDaysSincePreviousEarnings() <= 2)) # Filter for stocks that are announced acquisition target. not_announced_acq_target = ~IsAnnouncedAcqTarget() # Our universe is made up of stocks that have a non-null sentiment & precog signal that was # updated in the last day, are not within 2 days of an earnings announcement, are not announced # acquisition targets, and are in the Q1500US. universe = (Q1500US() & precog.predicted_five_day_log_return.latest.notnull() & not_near_earnings_announcement & not_announced_acq_target) # Prediction quality factor. prediction_quality = PredictionQuality(mask=universe) # Filter for stocks above the threshold quality. quality = prediction_quality > pred_quality_thresh latest_prediction = precog.predicted_five_day_log_return.latest non_outliers = latest_prediction.percentile_between(1, 99, mask=quality) normalized_return = latest_prediction.zscore(mask=non_outliers) normalized_prediction_rank = normalized_return.rank() prediction_rank_quantiles = normalized_prediction_rank.quantiles(5) longs = prediction_rank_quantiles.eq(4) shorts = prediction_rank_quantiles.eq(0) # We will take market beta into consideration when placing orders in our algorithm. beta = RollingLinearRegressionOfReturns(target=sid(8554), returns_length=5, regression_length=260, mask=(longs | shorts)).beta # We will actually be using the beta computed using Bloomberg's computation. # Ref: https://www.lib.uwo.ca/business/betasbydatabasebloombergdefinitionofbeta.html bb_beta = (0.66 * beta) + (0.33 * 1.0) ## create pipeline columns = { 'longs': longs, 'shorts': shorts, 'market_beta': bb_beta, 'sector': Sector(), } pipe = Pipeline(columns=columns, screen=(longs | shorts)) return pipe
'30 Day Mean Close': mean_close_30, 'Percent Diff': percent_diff, 'Latest Close': latest_close, 'Percent Diff Filter': percent_diff_filter }, # OR USE COMBINATION FILTER combo_filter screen=percent_diff_filter) # OR '~percent_diff_filter' FOR OPPOSITE OF THE FILTER pipe = make_pipeline() # start_date == end_date, THEREFORE THE SAME DAY result = run_pipeline(pipe, start_date='2017-01-03', end_date='2017-01-03') result.head() # NOW, USING MASKS latest_close = USEquityPricing.close.latest small_price = latest_close < 5 mean_close_30 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=30, mask=small_price) mean_close_10 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=10, mask=small_price) # mask=val APPLIES A FILTER 1ST BEFORE CALC'ING THIS SMA FACTOR (SAVES COMPUTATIONAL COMPLEXITY) # NOW USE FACTORS (mean_close_30, mean_close_10) HOWEVER # NOW, USING CLASSIFIERS from quantopian.pipeline.data import morningstar from quantopian.pipeline.classifiers.morningstar import Sector ms_sector = Sector() # A LOT OF PROPERTIES OF ms_sector ARE CLASSIFIERS exchange_classifier = ms_sector.share_class_reference.exchange_id.latest nyse_filter = exchange_classifier.eq('NYS') # OR .isnull() / startswith() # NOW, USE nyse_filter WITHIN pipe = Pipeline(..., screen=nyse_filter)
def initialize(context): pipe = Pipeline() attach_pipeline(pipe, 'ranked_2000') my_sectors = [206] #"Healthcare" sector_filter = Sector().element_of(my_sectors) # Create list of all criteria for securities worth investing in """ 9 filters: 1. common stock 2 & 3. not limited partnership - name and database check 4. database has fundamental data 5. not over the counter 6. not when issued 7. not depository receipts 8. primary share 9. high dollar volume """ mkt_cap = MarketCap() top_2000 = mkt_cap.top(2000) common_stock = morningstar.share_class_reference.security_type.latest.eq( 'ST00000001') not_lp_name = ~morningstar.company_reference.standard_name.latest.matches( '.* L[\\. ]?P\.?$') not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull( ) have_data = morningstar.valuation.market_cap.latest.notnull() not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith( 'OTC') not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI') not_depository = ~morningstar.share_class_reference.is_depositary_receipt.latest primary_share = IsPrimaryShare() # Combine the above filters. tradable_filter = (common_stock & not_lp_name & not_lp_balance_sheet & have_data & not_otc & not_wi & not_depository & primary_share & sector_filter & top_2000) pipe_screen = (sector_filter) # Create, register and name a pipeline # Add the factor defined to the pipeline price_to_sales = Price_to_sales(mask=tradable_filter) pipe.add(price_to_sales, 'price to sales') # Create and apply a filter representing the top 2000 equities by MarketCap every day # This is an approximation of the Russell 2000 # Rank price to sales and add the rank to our pipeline price_to_sales_rank = price_to_sales.rank(mask=tradable_filter) pipe.add(price_to_sales_rank, 'ps_rank') # Set a screen to ensure that only the top 2000 companies by market cap # which are healthcare companies with positive PS ratios are screened pipe.set_screen(top_2000 & (price_to_sales > 0)) # Scedule my rebalance function schedule_function(func=rebalance, date_rule=date_rules.month_start(days_offset=0), time_rule=time_rules.market_open(hours=0, minutes=30), half_days=True) # Schedule my plotting function schedule_function(func=record_vars, date_rule=date_rules.every_day(), time_rule=time_rules.market_close(), half_days=True) # set my leverage context.long_leverage = 1.00 context.short_leverage = -0.00 context.spy = sid(8554) context.short_list = [] context.short_list.append(context.spy)