QuantConnect Algorithm Framework - Universe Selection


In our previous post 'A First Look Into QuantConnect', we gave an introduction to the different parts of the so called Algorithm Framework - a powerful framework for modular design of trading algorithms.

Today, we will go over the first component: Universe Selection

Intuitively, this module is in charge of selecting a number of securities that will become the subject of our trading strategy. Each 'selected' security will consume memory as we subscribe to its data (especially when subscribing to minute data) so this task is also very important in terms of computational resources.

As mentioned in our introduction post, this selection can essentially be of two types, namely Manual Selection and Dynamic Selection.

Manual Selection

If we have a list of tickers that we want to consider for our strategy, we can simply perform a manual selection. This is done only once at the start of the algorithm and those securities become part of the 'Universe' for the entire backtest period.

The algorithm below manually selects the equities 'FB', 'AMZN', 'NFLX' and 'GOOG', and performs a simple buy and hold strategy on them.

LONG ONLY - BUY AND HOLD - MANUAL UNIVERSE

The manual selection is done in the main.py script, as shown below:

1) Input a list of tickers.

# add tickers to the list
tickers = ['FB', 'AMZN', 'NFLX', 'GOOG']

2) Loop through them to create their symbols (QuantConnect way of identifying the securities associated to each ticker). We use the method Symbol.Create that takes three arguments: a valid Ticker, SecurityType (Equity in this case) and the Market (USA here). If we wanted to add, for example, currency pairs, we would specify SecurityType.Forex and Market.FXCM or Market.Oanda, depending on the broker you want to use (both FXCM and Oanda data are provided for free within QuantConnect).

symbols = []
# loop through the tickers list and create symbols for the universe
for i in range(len(tickers)):
symbols.append(Symbol.Create(tickers[i], SecurityType.Equity, Market.USA))

3) Finally, we select the manual universe model and pass the symbols list to it.

# select modules
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))

      Dynamic Selection

      Things are about to get interesting by introducing a dynamic selection of securities! We are going to build our own custom made screener that will run daily by default (overnight after each trading session from Tuesday to Saturday), but that can be modified to run weekly, monthly, yearly, etc.

      Now securities are going to be selected based on certain criteria, from basic price and volume data to technical indicators and fundamental data, hence reducing the so called selection bias.

      At this point, it's important to mention that this type of selection can be performed on any security type (Equities, Forex, etc.), but it is best utilized for US Equities due to the huge number of securities (over 8000) vs Forex (less than 100). For this reason, in this post we are focusing on stocks.

      This model contains two main functions that apply to ETFs and US Equities, one primarily involving price/volume data and another for fundamental data:

      • SelectCoarse: Generally speaking, the objective of this function is to select stocks that share some common desirable characteristics in terms of price and volume data (e.g. select/avoid penny stocks, low/high liquidity stocks, etc.). More specifically, this function can be used to filter securities that closed the last trading day within some price and volume levels and sort them somehow to further reduce the number of securities (e.g. stocks that closed above $20 and traded volume above 100K shares, then select highly liquid stocks by keeping the top 100 by dollar volume). As this is an introduction to Universe Selection, and our main concern is to understand its internal logic, we won't be showing more complex examples of Coarse selection (we reserve this for future blog posts). However, it's worth mentioning already the possibility of using historical data within this function, allowing for pretty much any logic involving OHLCV data (Open, High, Low, Close and Volume).
      • SelectFine: After performing Coarse selection, we can also refine our screener using corporate fundamentals dataThere is a long list of financial statements (income, balance sheet, cash flow statements), operation ratios, earning ratios and valuation ratios on multiple periods (last 1, 3, 6, 9 and 12 months, and last 1, 2, 3 and 5 years), as well as asset classification to filter by sectors and/or industries.

      In order to illustrate the capabilities of the Universe module while introducing a classic factor investing strategy, the algorithm below is an attempt to exploit the combination of the Small Cap and Low P/E Ratio anomalies.

      LONG ONLY - SMALL CAPS AND LOW PE RATIO - DYNAMIC UNIVERSE

      SmallCapsLowPERatioUniverseSelection.py is the script containing the Universe Selection model, and its logic is  as follows:

      1) SelectCoarse: At the start of every year, select stocks with fundamental data (to avoid ETFs) and price above $5

      filterCoarse = [x for x in coarse if x.HasFundamentalData and x.Price > 5]

      2) SelectFine: Then find Small Cap stocks and finally select the stocks with P/E Ratio in the 1st percentile

      filterFine = []
      # select small caps only (market cap between $300 million and $2 billion)
      for x in fine:
      marketCap = (x.EarningReports.BasicAverageShares.ThreeMonths *
      x.EarningReports.BasicEPS.TwelveMonths *
      x.ValuationRatios.PERatio)
      if marketCap > 3e8 and marketCap < 2e9:
      filterFine.append(x)

      # now calculate the PE Ratio 1st percentile
      peRatios = [x.ValuationRatios.PERatio for x in filterFine]
      lowestPERatioPercentile = np.percentile(peRatios, 1)

      # filter stocks in the 1st PE Ratio percentile
      lowestPERatio = list(filter(lambda x: x.ValuationRatios.PERatio <= lowestPERatioPercentile, filterFine))

      Conclusions

      Today we've introduced the Universe Selection module - the first component of the Algorithm Framework in charge of selecting the securities for the trading strategy.

      The main takeaways from this post are:

      • There are essentially two ways of selecting securities, manual and dynamic. While manual selection means inputting a simple list of tickers, dynamic selection involves the use of OHLCV data and corporate fundamentals to choose stocks.
      • The beauty of its modular design! Looking at the two examples above, we can observe how we switched from a Buy and Hold strategy with Manual Universe, to a Dynamic Universe strategy based on fundamentals by only changing the Universe Selection module. The rest of the framework models stayed the same.

      We're always here to answer your questions so please ask away!

      Do you have a strategy of your own that you would like to backtest and automate? Learn about our consulting services and get in touch at admin@innoquantivity.com

      Found this post useful? You can support this site by making a donation using the link below!

      - Disclaimer -
      The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by InnoQuantivity. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. InnoQuantivity makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.

        Leave a comment


        Please note, comments must be approved before they are published