Alpha

Key Concepts

Introduction

The Alpha model predicts market trends and signals the best moments to trade. These signals, or Insight objects, contain the Direction, Magnitude, and Confidence of a market prediction and the suggested portfolio Weight. You should generate insights on the set of assets provided by the Universe Selection model and only generate them when your predictions change.

Add Models

To add an Alpha model, in the Initialize method, call the AddAlpha method.

AddAlpha(new EmaCrossAlphaModel());
self.AddAlpha(EmaCrossAlphaModel())

To view all the pre-built Alpha models, see Supported Models.

Multi-Alpha Algorithms

You can add multiple Alpha models to a single algorithm and generate Insight objects with all of them.

AddAlpha(new RsiAlphaModel());
AddAlpha(new EmaCrossAlphaModel());
self.AddAlpha(RsiAlphaModel())
self.AddAlpha(EmaCrossAlphaModel())

Each Alpha model has a unique name. The Insight objects they generate are automatically named according to the Alpha model name.

If you add multiple Alpha models, each alpha model receives the current slice in the order that you add the Alphas. The combined stream of Insight objects is passed to the Portfolio Construction model.

Model Structure

Alpha models should extend the AlphaModel class. Extensions of the AlphaModel class must implement the Update method, which receives a Slice object and returns an array of Insight objects. Extensions should also implement the OnSecuritiesChanged method to track security changes in the universe.

// Algorithm framework model that produces insights
class MyAlphaModel : AlphaModel
{
    // Updates this Alpha model with the latest data from the algorithm.
    // This is called each time the algorithm receives data for subscribed securities
    public override Enumerable<Insight> Update(QCAlgorithm algorithm, Slice data) 
    {
        var insights = new List<Insight>();
        return insights;
    }

    public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) 
    {
        // Security additions and removals are pushed here.
        // This can be used for setting up algorithm state.
        // changes.AddedSecurities
        // changes.RemovedSecurities
    }
}
# Algorithm framework model that produces insights
class MyAlphaModel(AlphaModel):

    def Update(self, algorithm: QCAlgorithm, data: Slice) -> List[Insight]:
        # Updates this Alpha model with the latest data from the algorithm.
        # This is called each time the algorithm receives data for subscribed securities
        # Generate insights on the securities in the universe.
        insights = []
        return insights

    def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        # Security additions and removals are pushed here.
        # This can be used for setting up algorithm state.
        # changes.AddedSecurities
        # changes.RemovedSecurities
        pass

Method Parameters

The algorithm parameter that the methods receive is an instance of the base QCAlgorithm class, not your subclass of it. To access members of your algorithm object, either use a global variable or pass an algorithm reference to Alpha model constructor. Both of these approaches violate the separation of concerns principle.

The data parameter contains the latest data available to the algorithm.

The changes parameter contains the universe changes.

Model Names

To ensure your Alpha model is compatible with all Portfolio Construction models, assign a unique name to your Alpha model. Some Portfolio Construction models can combine multiple Alpha models together, so it can be important to distinguish between the Alpha models. By default, we use the class-type name as the Alpha model name.

public class RsiAlphaModel : AlphaModel
{
    // Give your alpha a name (perhaps based on its constructor args?)
    public override string Name { get; }
}

Track Security Changes

The Universe Selection model may select a dynamic universe of assets, so you should not assume a fixed set of assets in the Alpha model. When the Universe Selection model adds and removes assets from the universe, it triggers an OnSecuritiesChanged event. In the OnSecuritiesChanged event handler, you can initialize the security-specific state or load any history required for your Alpha model.

class MyAlphaModel : AlphaModel
{
    private Dictionary<symbol, symboldata> _symbolDataBySymbol = new Dictionary<symbol, symboldata>();
    
    public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) {
        foreach (var security in changes.AddedSecurities)
        {               
            _symbolDataBySymbol[security.Symbol] = new SymbolData(algorithm, security.Symbol);
        }

        foreach (var security in changes.RemovedSecurities)
        {
            if (_symbolDataBySymbol.ContainsKey(security.Symbol))
            {
                _symbolDataBySymbol[security.Symbol].dispose();
                _symbolDataBySymbol.Remove(security.Symbol);
            }
        }
    }

    public class SymbolData 
    {
        private QCAlgorithm _algorithm;
        private Symbol _symbol;
        private SimpleMovingAverage _indicator;
        private TradeBarConsolidator _consolidator;

        public SymbolData(QCAlgorithm algorithm, Symbol symbol)
        {
            _algorithm = algorithm;
            _symbol = symbol;

            _indicator = new SimpleMovingAverage(20);
            _consolidator = new TradeBarConsolidator(1);
            algorithm.SubscriptionManager.AddConsolidator(symbol, _consolidator);
            algorithm.RegisterIndicator(symbol, _indicator, _consolidator);
            algorithm.WarmUpIndicator(symbol, _indicator);
        }

        public void dispose()
        {
            _algorithm.SubscriptionManager.RemoveConsolidator(_symbol, _consolidator);
        }
    }
}
class MyAlphaModel(AlphaModel):
    symbol_data_by_symbol = {}

    def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for security in changes.AddedSecurities:
            self.symbol_data_by_symbol[security.Symbol] = SymbolData(algorithm, security.Symbol)

        for security in changes.RemovedSecurities:
            if security.Symbol in self.symbol_data_by_symbol:
                symbol_data = self.symbol_data_by_symbol.pop(security.Symbol, None)
                if symbol_data:
                    symbol_data.dispose()

class SymbolData:
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol

        self.indicator = SimpleMovingAverage(20)
        self.consolidator = TradeBarConsolidator(1)
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
        algorithm.RegisterIndicator(symbol, self.indicator, self.consolidator)
        algorithm.WarmUpIndicator(self.symbol, self.indicator)
    
    def dispose(self):
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.consolidator)

Insights

An Insight is a single prediction for an asset. The Update method returns an array of Insight objects. You can think of these as actionable trading signals, indicating the asset direction, magnitude, and confidence in the near future. All insights can take a weight parameter to set the desired weighting for the insight. If you change the cash of the algorithm, it will affect the orders, but not necessarily the insights.

The Portfolio Construction model consumes the Insight objects from the Alpha model. It's up to the Portfolio Construction model to define how Insight objects are converted into PortfolioTarget objects. In the pre-built Portfolio Construction models, down insights translate to short-biased trades, up insights translate to long-biased trades, and flat insights usually close open positions, but this doesn't have to be the case in custom Portfolio Construction models.

Insight Properties

Insight objects have the following properties:

Create Insights

To create an Insight, call the Insight constructor.

# Insight(symbol, period, type, direction, magnitude=None, confidence=None, sourceModel=None, weight=None)
insight = Insight("IBM", timedelta(minutes=20), InsightType.Price, InsightDirection.Up)
// new Insight(symbol, period, type, direction, magnitude=null, confidence=null, sourceModel=null, weight=null);
var insight = new Insight("IBM", TimeSpan.FromMinutes(20), InsightType.Price, InsightDirection.Up);

In the Insight constructor, the period argument can be a timedeltaTimeSpan object or a function that receives a DateTimedatetime object and returns the expiry DateTimedatetime. Some of the constructor arguments are optional to create the Insight object, but some of the Portfolio Construction models may require these properties. To check which Insight properties a Portfolio Construction model requires, see Supported Models.

You can also use the helper method to create Insight objects of the Price type.

# Insight.Price(symbol, period, direction, magnitude=None, confidence=None, sourceModel=None, weight=None) 
insight = Insight.Price("IBM", timedelta(minutes = 20), InsightDirection.Up)

# Insight.Price(symbol, resolution, barCount, direction, magnitude=None, confidence=None, sourceModel=None, weight=None) 
insight = Insight.Price("IBM", Resolution.Minute, 20, InsightDirection.Up)
// new Insight(symbol, period, direction, magnitude=null, confidence=null, sourceModel=null, weight=null)
var insight = Insight.Price("IBM", TimeSpan.FromMinutes(20), InsightDirection.Up);

// new Insight(symbol, resolution, barCount, direction, magnitude=null, confidence=null, sourceModel=null, weight=null)
var insight = Insight.Price("IBM", Resolution.Minute, 20, InsightDirection.Up);

In the Price method, the period argument can be a timedeltaTimeSpan object, a DateTimedatetime object, or a function that receives a DateTimedatetime object and returns the expiry DateTimedatetime.

Group Insights

Sometimes an algorithm's performance relies on multiple insights being traded together, like in pairs trading and options straddles. These types insights should be grouped. Insight groups signal to the Execution model that the insights need to be acted on as a single unit to maximize the alpha created.

To mark insights as a group, call the Insight.Group method.

return Insight.Group(insight1, insight2, insight3);
return Insight.Group([insight1, insight2,insight3])

Insight Collection

The InsightCollection class is a helper class to manage insights. The class managers an internal dictionary that has the security Symbol as the key and a list of Insight objects as the value.

Add Insights

To add an Insight to the InsightCollection, call the Add method.

_insightCollection.Add(insight);
self.insight_collection.Add(insight)

To add a list of Insight objects, call the AddRange method.

_insightCollection.AddRange(insights);
self.insight_collection.AddRange(insights)

Check Membership

To check if an insight exists in the InsightCollection, call the Contains method.

var insightInCollection = _insightCollection.Contains(insight);
insight_in_collection = self.insight_collection.Contains(insight)

To check if a Symbol exists in the InsightCollection, call the ContainsKey method.

var symbolInCollection = _insightCollection.ContainsKey(symbol);
symbol_in_collection = self.insight_collection.ContainsKey(symbol)

To check if the InsightCollection has active insights for a certain Coordinated Universal Time (UTC), call the HasActiveInsights method.

var hasActiveInsights = _insightCollection.HasActiveInsights(symbol, utcTime);
has_active_insights = self.insight_collection.HasActiveInsights(symbol, utc_time)

Access Insights

To access the Insight objects for a Symbol, index the InsightCollection with the Symbol.

var insights = _insightCollection[symbol];
insights = self.insight_collection[symbol]

To iterate through the InsightCollection, call the GetEnumerator method.

var enumerator = _insightCollection.GetEnumerator();
enumerator = self.insight_collection.GetEnumerator()

To get all of the active insights at a certain UTC time, call the GetActiveInsights method.

var activeInsights = _insightCollection.GetActiveInsights(utcTime);
active_insights = self.insight_collection.GetActiveInsights(utc_time)

Get the Next Expiry Time

To get the next Insight expiry time, call the GetNextExpiryTime method.

var nextExpiry = _insightCollection.GetNextExpiryTime();
next_expiry = self.insight_collection.GetNextExpiryTime()

Remove Insights

To remove an Insight from the InsightCollection, call the Remove method.

var removeSuccessful = _insightCollection.Remove(insight);
remove_successful = self.insight_collection.Remove(insight)

To remove a subset of the Insight objects, pass a list of Symbol objects the Clear method.

_insightCollection.Clear(symbols);
self.insight_collection.Clear(symbols)

To remove all the Insight objects, call the Clear method.

_insightCollection.Clear();
self.insight_collection.Clear()

To remove all the expired insights at a certain UTC time, call the RemoveExpiredInsights method.

var expiredInsights = _insightCollection.RemoveExpiredInsights(utcTime);
expired_insights = self.insight_collection.RemoveExpiredInsights(utc_time)

Copy Insights

To copy a subset of the Insight objects in the InsightCollection to an array, call the CopyTo method. The arrayIndex argument is the zero-based index in the array at which copying begins.

_insightCollection.CopyTo(array, arrayIndex);
self.insight_collection.CopyTo(array, arrayIndex)

Stop Loss Orders Workaround

In some cases, if you add a Risk Management model that uses stop loss logic, the Risk Management model generates PortfolioTarget objects with a 0 quantity to make the Execution model liquidate your positions, but then the Portfolio Construction model generates PortfolioTarget objects with a non-zero quantity to make the Execution model re-enter the same position. This issue can occur if your Portfolio Construction model rebalances and your Alpha model still has an active insight for the liquidated securities. To avoid this issue, add the stop loss order logic to the Alpha model. When the stop loss is hit, emit a flat insight for the security. Note that this is a workaround, but it violates the separation of concerns principle since the Alpha Model shouldn't react to open positions.

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: