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): # 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, )