US Equity

Corporate Actions

Introduction

US Equity subscriptions provide notifications for splits, dividends, symbol changes, and delistings.

Splits

When a company does a stock split, the number of shares each shareholder owns increases and the price of each share decreases. When a company does a reverse stock split, the number of shares each shareholder owns decreases and the price of each share increases. A company may perform a stock split or a reverse stock split to adjust the price of their stock so that more investors trade it and the liquidity increases.

When a stock split or reverse stock split occurs for an Equity in your algorithm, LEAN sends a Split object to the OnData method. Split objects have the following properties:

You receive Split objects when a split is in the near future and when it occurs. To know if the split occurs in the near future or now, check the Type property.

If you backtest without the Raw data normalization mode, the splits are factored into the price and volume. If you backtest with the Raw data normalization mode or trade live, when a split occurs, LEAN automatically adjusts your positions based on the SplitFactor. If the post-split quantity isn't a valid lot size, LEAN credits the remaining value to your cashbook in your account currency. If you have indicators in your algorithm, reset your indicators when splits occur so that the data in your indicators account for the price adjustments that the splits cause.

To get the Split objects in the Slice, index the Splits property of the Slice with the security Symbol. The Slice may not contain data for your Symbol. To avoid issues, check if the Splits property contains data for your security before you index it with the security Symbol.

public override void OnData(Slice slice)
{
    if (slice.Splits.ContainsKey(_symbol))
    {
        var split = slice.Splits[_symbol];
    }
}

public void OnData(Splits splits)
{
    if (splits.ContainsKey(_symbol))
    {
        var split = splits[_symbol];
    }
}
def OnData(self, slice: Slice) -> None:
    split = slice.Splits.get(self.symbol)
    if split:
        pass

You can also iterate through the Splits dictionary. The keys of the dictionary are the Symbol objects and the values are the Split objects.

public override void OnData(Slice slice)
{
    foreach (var kvp in slice.Splits)
    {
        var symbol = kvp.Key;
        var split = kvp.Value;
    }
}

public void OnData(Splits splits)
{
    foreach (var kvp in splits)
    {
        var symbol = kvp.Key;
        var split = kvp.Value;
    }
}
def OnData(self, slice: Slice) -> None:
    for symbol, split in slice.Splits.items():
        pass

LEAN stores the data for stock splits in factor files. To view some example factor files, see the LEAN GitHub repository. In backtests, your algorithm receives Split objects at midnight. In live trading, your algorithm receives Split objects when the factor files are ready.

If you hold an Option contract for an underlying Equity when a split occurs, LEAN closes your Option contract position.

If a split event occurs before your order is filled, the unfilled portion of the order is adjusted automatically, where its quantity is multiplied by the split factor and the limit/stop/trigger price (if any) is divided by the split factor.

Dividends

A dividend is a payment that a company gives to shareholders to distribute profits. When a dividend payment occurs for an Equity in your algorithm, LEAN sends a Dividend object to the OnData method. Dividend objects have the following properties:

If you backtest with the Adjusted or TotalReturn data normalization mode, the dividends are factored into the price. If you backtest with the other data normalization modes or trade live, when a dividend payment occurs, LEAN automatically adds the payment amount to your cashbook. If you have indicators in your algorithm, reset your indicators when dividend payments occur so that the data in your indicators account for the price adjustments that the dividend causes.

To get the Dividend objects in the Slice, index the Dividends property of the Slice with the security Symbol. The Slice may not contain data for your Symbol. To avoid issues, check if the Dividends property contains data for your security before you index it with the security Symbol.

public override void OnData(Slice slice)
{
    if (slice.Dividends.ContainsKey(_symbol))
    {
        var dividend = slice.Dividends[_symbol];
    }
}

public void OnData(Dividends dividends)
{
    if (dividends.ContainsKey(_symbol))
    {
        var dividend = dividends[_symbol];
    }
}
def OnData(self, slice: Slice) -> None:
    dividend = slice.Dividends.get(self.symbol)
    if dividend:
        pass

You can also iterate through the Dividends dictionary. The keys of the dictionary are the Symbol objects and the values are the Dividend objects.

public override void OnData(Slice slice)
{
    foreach (var kvp in slice.Dividends)
    {
        var symbol = kvp.Key;
        var dividend = kvp.Value;
    }
}

public void OnData(Dividends dividends)
{
    foreach (var kvp in dividends)
    {
        var symbol = kvp.Key;
        var dividend = kvp.Value;
    }
}
def OnData(self, slice: Slice) -> None:
    for symbol, dividend in slice.Dividends.items():
        pass

For a full example, see the DividendAlgorithmDividendAlgorithm in the LEAN GitHub repository.

Symbol Changes

The benefit of the Symbol class is that it always maps to the same security, regardless of their trading ticker. When a company changes its trading ticker, LEAN sends a SymbolChangedEvent to the OnData method. SymbolChangedEvent objects have the following properties:

To get the SymbolChangedEvent objects in the Slice, index the SymbolChangedEvents property of the Slice with the security Symbol. The Slice may not contain data for your Symbol. To avoid issues, check if the SymbolChangedEvents property contains data for your security before you index it with the security Symbol.

public override void OnData(Slice slice)
{
    if (slice.SymbolChangedEvents.ContainsKey(_symbol))
    {
        var symbolChangedEvent = slice.SymbolChangedEvents[_symbol];
    }
}

public void OnData(SymbolChangedEvents symbolChangedEvents)
{
    if (symbolChangedEvents.ContainsKey(_symbol))
    {
        var symbolChangedEvent = symbolChangedEvents[_symbol];
    }
}
def OnData(self, slice: Slice) -> None:
    symbol_changed_event = slice.SymbolChangedEvents.get(self.symbol)
    if symbol_changed_event:
        pass

You can also iterate through the SymbolChangedEvents dictionary. The keys of the dictionary are the Symbol objects and the values are the SymbolChangedEvent objects.

public override void OnData(Slice slice)
{
    foreach (var kvp in slice.SymbolChangedEvents)
    {
        var symbol = kvp.Key;
        var symbolChangedEvent = kvp.Value;
    }
}

public void OnData(SymbolChangedEvents symbolChangedEvents)
{
    foreach (var kvp in symbolChangedEvents)
    {
        var symbol = kvp.Key;
        var symbolChangedEvent = kvp.Value;
    }
}
def OnData(self, slice: Slice) -> None:
    for symbol, symbol_changed_event in slice.SymbolChangedEvents.items():
        pass

If you have an open order for a security when they change their ticker, LEAN cancels your order. To keep your order, in the OnOrderEvent method, get the quantity and Symbol of the cancelled order and submit a new order.

public override void OnOrderEvent(OrderEvent orderEvent)
{
    if (orderEvent.Status == OrderStatus.Canceled)
    {
        var ticket = Transactions.GetOrderTicket(orderEvent.OrderId);
        if (ticket.Tag.Contains("symbol changed event"))
        {
            Transactions.AddOrder(ticket.SubmitRequest);
        }
    } 
}
def OnOrderEvent(self, order_event: OrderEvent) -> None:
    if order_event.Status == OrderStatus.Canceled:
        ticket = self.Transactions.GetOrderTicket(order_event.OrderId)
        if "symbol changed event" in ticket.Tag:
            self.Transactions.AddOrder(ticket.SubmitRequest)

LEAN stores the data for ticker changes in map files. To view some example map files, see the LEAN GitHub repository.

Delistings

When a company is delisting from an exchange, LEAN sends a Delisting object to the OnData method. Delisting objects have the following properties:

You receive Delisting objects when a delisting is in the near future and when it occurs. To know if the delisting occurs in the near future or now, check the Type property.

To get the Delisting objects in the Slice, index the Delistings property of the Slice with the security Symbol. The Slice may not contain data for your Symbol. To avoid issues, check if the Delistings property contains data for your security before you index it with the security Symbol.

public override void OnData(Slice slice)
{
    if (slice.Delistings.ContainsKey(_symbol))
    {
        var delisting = slice.Delistings[_symbol];
    }
}

public void OnData(Delistings delistings)
{
    if (delistings.ContainsKey(_symbol))
    {
        var delisting = delistings[_symbol];
    }
}
def OnData(self, slice: Slice) -> None:
    delisting = slice.Delistings.get(self.symbol)
    if delisting:
        pass

You can also iterate through the Delistings dictionary. The keys of the dictionary are the Symbol objects and the values are the Delisting objects.

public override void OnData(Slice slice)
{
    foreach (var kvp in slice.Delistings)
    {
        var symbol = kvp.Key;
        var delisting = kvp.Value;
    }
}

public void OnData(Delistings delistings)
{
    foreach (var kvp in delistings)
    {
        var symbol = kvp.Key;
        var delisting = kvp.Value;
    }
}
def OnData(self, slice: Slice) -> None:
    for symbol, delisting in slice.Delistings.items():
        pass

The delist warning occurs on the final trading day of the stock to give you time to gracefully exit out of positions before LEAN automatically liquidates them.

if (delisting.Type == DelistingType.Warning)
{
    // Liquidate with MarketOnOpenOrder on delisting warning
    var quantity = Portfolio[symbol].Quantity;
    if (quantity != 0)
    {
        MarketOnOpenOrder(symbol, -quantity);
    }
}
if delisting.Type == DelistingType.Warning:
    # Liquidate with MarketOnOpenOrder on delisting warning
    quantity = self.Portfolio[symbol].Quantity
    if quantity != 0:
        self.MarketOnOpenOrder(symbol, -quantity)

For a full example, see the DelistingEventsAlgorithmDelistingEventsAlgorithm in the LEAN GitHub repository.

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: