I am constantly referring back to the Boot Camp, but it is difficult to access the information in its interactive format. I have copied the text of the lesson here for quick access and review. (Do the boot camp before using this for review.) -GK ......

Liquid Universe Selection

Using a universe selection filter, we will invest in the top 8 stocks which are liquid and cost more than \$10 per share. To do this we will use coarse universe selection features.

Lesson Overview

Using a universe selection filter, we will invest in the top 8 stocks which are liquid and cost more than \$10 per share. To do this we will use coarse universe selection features.

What You'll Learn
• Using universe selection data (“coarse fundamental data”)
• Sorting an array of coarse fundamental objects for its 8 most liquid symbols
• Monitoring how your universe of securities change
• Allocating and liquidating securities in your universe
• Configuring properties of the universe data requested
Lesson Requirements

We recommend you complete the Opening Range Breakout lesson and previous beginner lessons before starting this lesson.

Setting Up a Coarse Universe Filter
1. Liquid Universe Selection
2. Setting Up a Coarse Universe Filter
Introduction to Universe Selection

We use universe selection to algorithmically reduce the number of assets added to our algorithm (the investment “universe”). We want to choose our assets with formulas, not by manually selecting our favorite assets.

Selection Bias

Universe selection helps us avoid selection bias by algorithmically choosing our assets for trading. Selection bias is introduced when the asset selection is influenced by personal or non-random decision making, and often results in selecting winning stocks based on future knowledge.

Coarse Selection

We can add a universe with the method `self.AddUniverse()`

def Initialize(self):
# Create a filter function
def CoarseSelectionFilter(self, coarse):
pass

The method requires a filter function `CoarseSelectionFilter` which is passed an array of coarse data representing all stocks active on that trading day. Assets selected by our filter are automatically added to your algorithm in minute resolution.

Universe Unchanged

If we don't have specific filtering instructions for our universe, we can use `Universe.Unchanged` which specifies that universe selection should not make changes on this iteration.

# Create a filter function that currently does not change the universe
def CoarseSelectionFilter(self, coarse):
return Universe.Unchanged

Set up the foundation for performing universe selection.

1. Create a filter function `CoarseSelectionFilter(self, coarse)`.
2. In your filter function, save `coarse` to `self.coarse`, then return `Universe.Unchanged`.
3. Pass the name of filter function into `self.AddUniverse` to use coarse fundamental data.
Hint:

Did you make the CoarseSelectionFilter empty with `pass`, and include two parameters, `self` and `coarse`?

Make sure to not accidentally execute the filter function with brackets (), simply pass the name of the function.

Code:

class LiquidUniverseSelection(QCAlgorithm):

filteredByPrice = None
coarse = None

def Initialize(self):
self.SetStartDate(2019, 1, 11)
self.SetEndDate(2019, 7, 1)
self.SetCash(100000)

#3. Add a Universe model using Coarse Fundamental Data and set the filter function

#1. Add an empty filter function
def CoarseSelectionFilter(self, coarse):
#2. Save coarse as self.coarse and return an Unchanged Universe
self.coarse = coarse
return Universe.Unchanged

-------------------------------------

Understanding Coarse Fundamental Objects
1. Liquid Universe Selection
2. Understanding Coarse Fundamental Objects
Coarse Fundamental Objects

The `CoarseSelectionFilter` takes a parameter `coarse`. Coarse is an array of CoarseFundamentalObjects:

def CoarseSelectionFilter(self, coarse):
# 'coarse' is an array of CoarseFundamental data.
# CoarseFundamental has properties Symbol, DollarVolume and Price.
coarse[0].Symbol
coarse[0].DollarVolume
coarse[0].PriceUsing the Coarse Selection Filter

The `CoarseSelectionFilter` function narrows the list of companies according to properties like price and volume. The filter needs to return a list of symbols. For example, we may want to narrow down our universe to liquid assets, or assets that pass a technical indicator filter. We can do all of this in the coarse selection function.

You can use the coarse fundamental data to create your own criteria ("factors") to perform your selection. Once you have your target criteria there are two key tools: sorting and filtering. Sorting lets you take the top and/or bottom ranked symbols according to your criteria, filtering allows you to narrow your selection range to eliminate some assets. In python this is accomplished by `sort` and list selection methods. You can read more about it here.

# Use the sorted method to get keys in ascending order (greatest to least in DollarVolume)
sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True) # Get symbols from your sorted list with a price more than \$5 per share
symbols_by_price = [c.Symbol for c in sortedByDollarVolume if c.Price > 5]
# Get the top 10 symbols
symbols_by_price[:10]

When you return a symbol from the `CoarseSelectionFilter`, LEAN automatically subscribes to these symbols and adds them to our algorithm.

We want to trade the 8 most liquid symbols, worth more than \$10 per share. To get this list of symbols we will need to sort our list of coarse objects ("`coarse`") by dollar volume. Then we want to use a list comprehension filter to exclude penny stocks, and get the symbol objects.

1. Sort your symbols descending by dollar volume and save to `sortedByDollarVolume`
2. Set `self.filteredByPrice` to symbols with a price of more than \$10 per share
3. Return the 8 most liquid symbols from the `self.filteredByPrice` list
Hint:

This one can be a little tricky.

• Make sure you are sorting with the reverse descending=True like in the example code.
• Remember we want to iterate through the top 8 symbols by returning filteredByPrice[:8].
Code:

class LiquidUniverseSelection(QCAlgorithm):

filteredByPrice = None

def Initialize(self):
self.SetStartDate(2019, 1, 11)
self.SetEndDate(2019, 7, 1)
self.SetCash(100000)

def CoarseSelectionFilter(self, coarse):

#1. Sort descending by daily dollar volume
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)

#2. Select only Symbols with a price of more than \$10 per share
self.filteredByPrice = [x.Symbol for x in sortedByDollarVolume if x.Price > 10]

#3. Return the 8 most liquid Symbols from the filteredByPrice list
self.filteredByPrice = self.filteredByPrice[:8]
return self.filteredByPrice

----------------------------------

Tracking Security Changes
1. Liquid Universe Selection
2. Tracking Security Changes
Monitoring Universe Changes

When the universe constituents change (securities are added or removed from the algorithm) the algorithm generates an `OnSecuritiesChanged` event which is passed information about the asset changes.

def OnSecuritiesChanged(self, changes):
passUniverse Selection Timing

You can monitor and act on these events in the `OnSecuritiesChanged()` event handler. The universe selection is performed at midnight each day, to choose the assets for the next trading day. These assets are added in minute resolution by default.

Using Log()

Algorithms can write log files for later analysis using `self.Log(string message)`. At the end of the backtest a link will be presented in your console to view your results.

self.Log(f"OnSecuritiesChanged({self.Time}):: {changes}")

1. Create a function `OnSecuritiesChanged` with parameters self and changes
2. Store the changes variable to `self.changes`.
3. Log the changes in your `OnSecuritiesChanged` event handler.

Fun Tip: You might want to inspect the logs link in the console after the algorithm runs before moving to the next task.

Hint:

You will want to use a format string: prefixed with "f" to log the changes i.e. `f"OnSecuritiesChanged({self.Time}):: {changes}"`. .

Code:

class LiquidUniverseSelection(QCAlgorithm):

filteredByPrice = None
changes = None

def Initialize(self):
self.SetStartDate(2019, 1, 11)
self.SetEndDate(2019, 7, 1)
self.SetCash(100000)

def CoarseSelectionFilter(self, coarse):

sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)

filteredByPrice = [x.Symbol for x in sortedByDollarVolume if x.Price > 10]

return filteredByPrice[:8]

#1. Create a function OnSecuritiesChanged
def OnSecuritiesChanged(self, changes):
#2. Save securities changed as self.changes
self.changes = changes
#3. Log the changes in the function
self.Log(f"OnSecuritiesChanged({self.Time}):: {changes}")

------------------------------

Building Our Portfolio
1. Liquid Universe Selection
2. Building Our Portfolio

The `OnSecuritiesChanged` event fires whenever we have changes to our universe. It receives a `SecurityChanges` object containing references to the added and removed securities.

# List of securities entering the universe
# List of securities leaving the universe
changed.RemovedSecurities

To build our portfolio we can loop over the securities changed. The `AddedSecurities` and `RemovedSecurities` properties are lists of security objects.

def OnSecuritiesChanged(self, changes):
# Liquidate securities
for security in changes.RemovedSecurities:
if security.Invested:
self.Liquidate(security.Symbol)

# SetHoldings for each new asset
self.SetHoldings(security.Symbol, 0.1)

For this strategy, we want to always have 10% of our cash allocated to each of the securities in the universe. When a security leaves the universe liquidate any holdings we have in that asset. Once all the securities are liquidated, purchase the new universe securities.

1. In the `OnSecuritiesChanged` event, loop over the removed securities, liquidating each one.
2. In the `OnSecuritiesChanged` event, loop over the added securities, using `SetHoldings` to allocate 10% to each.

Note: We changed the data resolution to daily. In next task will discuss configuring more universe settings.

Hint:

Remember when we set holdings we can pass in a `symbol` and a `percentage allocation``self.SetHoldings(security.Symbol, 0.1)`

`Code:`

`class LiquidUniverseSelection(QCAlgorithm):        filteredByPrice = None        def Initialize(self):        self.SetStartDate(2019, 1, 11)          self.SetEndDate(2019, 7, 1)         self.SetCash(100000)          self.AddUniverse(self.CoarseSelectionFilter)        # Ignore this for now, we'll cover it in the next task.        self.UniverseSettings.Resolution = Resolution.Daily `

`    def CoarseSelectionFilter(self, coarse):        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)         filteredByPrice = [x.Symbol for x in sortedByDollarVolume if x.Price > 10]        return filteredByPrice[:8]       def OnSecuritiesChanged(self, changes):        self.changes = changes        self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")                #1. Liquidate removed securities        for security in changes.RemovedSecurities:            if security.Invested:                self.Liquidate(security.Symbol)                #2. We want 10% allocation in each security in our universe        for security in changes.AddedSecurities:            self.SetHoldings(security.Symbol, 0.1)`

`---------------------------`

Customizing Universe Settings
1. Liquid Universe Selection
2. Customizing Universe Settings
Universe Settings

You can control the settings of assets added by universe selection with the UniverseSettings helper. This mostly used to control the Resolution, Leverage and Data Normalization Mode of assets in your universe.

self.UniverseSettings.Resolution
self.UniverseSettings.Leverage
self.UniverseSettings.FillForward
self.UniverseSettings.MinimumTimeInUniverse
self.UniverseSettings.ExtendedMarketHoursLeverage with SetHoldings

Brokerages sometimes let clients borrow money to invest, this is known as leverage. When leverage is available you can purchase up to "Cash x Leverage" worth of stock.

`SetHoldings` calculates the number of shares to purchase, based on a fraction of your equity, and then places a market order for them. For example, if you have \$10,000 cash, `SetHoldings("SPY", 1.0)` will attempt to purchase \$10,000 of SPY. With a leverage of 2.0, you could use `SetHoldings("SPY", 2.0)` and purchase \$20,000 of SPY, with \$10,000 cash.

Keeping a Cash Buffer

The market can quickly change price from the time you place the SetHoldings request to when the order is filled. If your portfolio allocations sum to exactly 100% orders may be rejected due to insufficient buying power. You should leave a buffer to account for market movements and fees. This is especially important with daily data where orders are placed overnight.

# Set holdings to a percentage with a cash buffer
# Leverage 1.0: 10 Assets x 0.10 each => 100%, 0% buffer, fail.
# Leverage 2.0: 10 Assets x 0.18 each => 180%, 20% buffer
self.SetHoldings(security.Symbol, 0.18)

1. Set the universe leverage to 2 with `UniverseSettings`
`class LiquidUniverseSelection(QCAlgorithm):        filteredByPrice = None        def Initialize(self):        self.SetStartDate(2019, 1, 11)          self.SetEndDate(2019, 7, 1)         self.SetCash(100000)          self.AddUniverse(self.CoarseSelectionFilter)        self.UniverseSettings.Resolution = Resolution.Daily`
`        #1. Set the leverage to 2        self.UniverseSettings.Leverage = 2           def CoarseSelectionFilter(self, coarse):        sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)        filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > 10]        return filteredByPrice[:10] `
`    def OnSecuritiesChanged(self, changes):        self.changes = changes        self.Log(f"OnSecuritiesChanged({self.Time}):: {changes}")                for security in self.changes.RemovedSecurities:            if security.Invested:                self.Liquidate(security.Symbol)                for security in self.changes.AddedSecurities:            #2. Leave a cash buffer by setting the allocation to 0.18 instead of 0.2             # self.SetHoldings(security.Symbol, ...)            self.SetHoldings(security.Symbol, 0.18)`