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 with 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, we are focusing on stocks in this post.
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 data. There 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
The logic for the Universe Selection model is as follows:
1) SelectCoarse: At the start of every year, select stocks with fundamental data (to avoid ETFs) and price above $5
# securities must have fundamental data (to avoid ETFs) # securities must have last 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
# select small caps only (market cap between $300 million and $2 billion) filterFine = [x for x in fine if 3e8 < x.MarketCap < 2e9 and x.ValuationRatios.PERatio > 0] # 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.
Do you have a strategy of your own that you would like to backtest and automate? Get in touch to learn more about our consulting services!