US Equity
Corporate Actions
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
on_data
method.
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
type
property.
If you backtest without the Raw
RAW
data normalization mode, the splits are factored into the price and volume. If you backtest with the Raw
RAW
data normalization mode or trade live, when a split occurs, LEAN automatically adjusts your positions based on the SplitFactor
split_factor
. 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 and warm-up your indicators with ScaledRaw data when splits occur so that the data in your indicators account for the price adjustments that the splits cause.
To get the Split
objects, index the Splits
splits
object with the security Symbol
symbol
. The Splits
splits
object may not contain data for your Symbol
. To avoid issues, check if the Splits
splits
object 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 override void OnSplits(Splits splits) { if (splits.ContainsKey(_symbol)) { var split = splits[_symbol]; } }
def on_data(self, slice: Slice) -> None: split = slice.splits.get(self._symbol) if split: pass def on_splits(self, splits: Splits) -> None: split = splits.get(self._symbol) if split: pass
You can also iterate through the Splits
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 override void OnSplits(Splits splits) { foreach (var kvp in splits) { var symbol = kvp.Key; var split = kvp.Value; } }
def on_data(self, slice: Slice) -> None: for symbol, split in slice.splits.items(): pass def on_splits(self, splits: Splits) -> None: for symbol, split in splits.items(): pass
To get historical splits, make a history request with the Split
type.
var splits = History<Split>(symbol, TimeSpan.FromDays(4*365));
splits_df = self.history(Split, symbol, timedelta(4*365)) splits = self.history[Split](symbol, timedelta(4*365))
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.
Split
objects have the following properties:
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
on_data
method.
If you backtest with the Adjusted
ADJUSTED
or TotalReturn
TOTAL_RETURN
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 and warm-up your indicators with ScaledRaw data 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, index the Dividends
dividends
object with the security Symbol
symbol
. The Dividends
dividends
object may not contain data for your Symbol
symbol
. To avoid issues, check if the Dividends
dividends
object contains data for your security before you index it with the security Symbol
symbol
.
public override void OnData(Slice slice) { if (slice.Dividends.ContainsKey(_symbol)) { var dividend = slice.Dividends[_symbol]; } } public override void OnDividends(Dividends dividends) { if (dividends.ContainsKey(_symbol)) { var dividend = dividends[_symbol]; } }
def on_data(self, slice: Slice) -> None: dividend = slice.dividends.get(self._symbol) if dividend: pass def on_dividends(self, dividends: Dividends) -> None: dividend = dividends.get(self._symbol) if dividend: pass
You can also iterate through the Dividends
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 override void OnDividends(Dividends dividends) { foreach (var kvp in dividends) { var symbol = kvp.Key; var dividend = kvp.Value; } }
def on_data(self, slice: Slice) -> None: for symbol, dividend in slice.dividends.items(): pass def on_dividends(self, dividends: Dividends) -> None: for symbol, dividend in dividends.items(): pass
To get historical dividends, make a history request with the Dividend
type.
var dividends = History<Dividend>(symbol, TimeSpan.FromDays(4*365));
dividends_df = self.history(Dividend, symbol, timedelta(4*365)) dividends = self.history[Split](Dividend, timedelta(4*365))
For a full example, see the DividendAlgorithmDividendAlgorithm in the LEAN GitHub repository.
Dividend
objects have the following properties:
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
on_data
method.
To get the SymbolChangedEvent
objects, index the SymbolChangedEvents
symbol_changed_events
object with the security Symbol
symbol
. The SymbolChangedEvents
symbol_changed_events
object may not contain data for your Symbol
symbol
. To avoid issues, check if the SymbolChangedEvents
symbol_changed_events
object contains data for your security before you index it with the security Symbol
symbol
.
public override void OnData(Slice slice) { if (slice.SymbolChangedEvents.ContainsKey(_symbol)) { var symbolChangedEvent = slice.SymbolChangedEvents[_symbol]; } } public override void OnSymbolChangedEvents(SymbolChangedEvents symbolChangedEvents) { if (symbolChangedEvents.ContainsKey(_symbol)) { var symbolChangedEvent = symbolChangedEvents[_symbol]; } }
def on_data(self, slice: Slice) -> None: symbol_changed_event = slice.symbol_changed_events.get(self._symbol) if symbol_changed_event: pass def on_symbol_changed_events(self, symbol_changed_events: SymbolChangedEvents) -> None: symbol_changed_event = symbol_changed_events.get(self._symbol) if symbol_changed_event: pass
You can also iterate through the SymbolChangedEvents
symbol_changed_events
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 override void OnSymbolChangedEvents(SymbolChangedEvents symbolChangedEvents) { foreach (var kvp in symbolChangedEvents) { var symbol = kvp.Key; var symbolChangedEvent = kvp.Value; } }
def on_data(self, slice: Slice) -> None: for symbol, symbol_changed_event in slice.symbol_changed_events.items(): pass def on_symbol_changed_events(self, symbol_changed_events: SymbolChangedEvents) -> None: for symbol, symbol_changed_event in symbol_changed_events.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
on_order_event
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 on_order_event(self, order_event: OrderEvent) -> None: if order_event.status == OrderStatus.CANCELED: ticket = self.transactions.get_order_ticket(order_event.order_id) if "symbol changed event" in ticket.tag: self.transactions.add_order(ticket.submit_request)
LEAN stores the data for ticker changes in map files. To view some example map files, see the LEAN GitHub repository.
SymbolChangedEvent
objects have the following properties:
Delistings
When a company is delisting from an exchange, LEAN sends a Delisting
object to the OnData
on_data
method.
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, index the Delistings
delistings
object with the security Symbol
symbol
. The Delistings
delistings
objects may not contain data for your Symbol
symbol
. To avoid issues, check if the Delistings
delistings
object contains data for your security before you index it with the security Symbol
symbol
.
public override void OnData(Slice slice) { if (slice.Delistings.ContainsKey(_symbol)) { var delisting = slice.Delistings[_symbol]; } } public override void OnDelistings(Delistings delistings) { if (delistings.ContainsKey(_symbol)) { var delisting = delistings[_symbol]; } }
def on_data(self, slice: Slice) -> None: delisting = slice.delistings.get(self._symbol) if delisting: pass def on_delistings(self, delistings: Delistings) -> None: delisting = delistings.get(self._symbol) if delisting: pass
You can also iterate through the Delistings
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 override void OnDelistings(Delistings delistings) { foreach (var kvp in delistings) { var symbol = kvp.Key; var delisting = kvp.Value; } }
def on_data(self, slice: Slice) -> None: for symbol, delisting in slice.Delistings.items(): pass def on_delistings(self, delistings: Delistings) -> None: for symbol, delisting in 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.market_on_open_order(symbol, -quantity)
The OnSecuritiesChanged
on_securities_changed
event notifies the algorithm when delisted assets are removed from the universe.
To improve iteration speed, LEAN removes delisted securities from the Securities
securities
primary collection. To access all the securities, iterate the Securities.Total
securities.total
property.
// Access all the securities. foreach (var security in Securities.Total) { } // Exclude delisted securities. foreach (var security in Securities.Values) { }
# Access all the securities. for security in self.securities.total: pass # Exclude delisted securities. for security in self.securities.values(): pass
For a full example, see the DelistingEventsAlgorithmDelistingEventsAlgorithm in the LEAN GitHub repository.
Delisting
objects have the following properties:
Examples
The following examples demonstrate some common practices for US Equity corporate actions.
Example 1: Resetting Indicators on Split Events
The following algorithm adds raw TSLA data and uses it to update an Exponential Moving Average (EMA) indicator. When a split occurs, it resets and warms up the indicator with scaled raw data to ensure the indicator doesn't reflect price discontinuities.
public class USEquityCorporateActionExampleAlgorithm : QCAlgorithm { private dynamic _equity; public override void Initialize() { // Add raw US Equity data. _equity = AddEquity("TSLA", Resolution.Daily, dataNormalizationMode: DataNormalizationMode.Raw); // Create an EMA indicator. _equity.Ema = EMA(_equity.Symbol, 50); } public override void OnSplits(Splits splits) { // Wait until the split has occurred. var split = splits[_equity.Symbol]; if (split.Type != SplitType.SplitOccurred) { return; } // Reset the indicator. _equity.Ema.Reset(); // Warm up the indicator with scaled raw data. var history = History<TradeBar>( _equity.Symbol, _equity.Ema.WarmUpPeriod, dataNormalizationMode: DataNormalizationMode.ScaledRaw ); foreach (var bar in history) { _equity.Ema.Update(bar.EndTime, bar.Close); } } }
class USEquityCorporateActionExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # Add raw US Equity data. self._equity = self.add_equity("TSLA", Resolution.DAILY, data_normalization_mode=DataNormalizationMode.RAW) # Create an EMA indicator. self._equity.ema = self.ema(self._equity.symbol, 50) def on_splits(self, splits: Splits) -> None: # Wait until the split has occurred. split = splits[self._equity.symbol] if split.type != SplitType.SPLIT_OCCURRED: return # Reset the indicator. self._equity.ema.reset() # Warm up the indicator with scaled raw data. history = self.history[TradeBar]( self._equity.symbol, self._equity.ema.warm_up_period, data_normalization_mode=DataNormalizationMode.SCALED_RAW ) for bar in history: self._equity.ema.update(bar.end_time, bar.close)
Example 2: Reinvesting Dividend Payments
The following algorithm adds raw SPY data. It then holds the SPY and re-invests the dividend payments into additional shares.
public class USEquityCorporateActionExampleAlgorithm : QCAlgorithm { private Equity _spy; public override void Initialize() { // Add raw Equity data. _spy = AddEquity("SPY", dataNormalizationMode: DataNormalizationMode.Raw); } public override void OnData(Slice slice) { // Buy and hold. if (!_spy.Holdings.Invested) { SetHoldings(_spy.Symbol, 0.5); } } public override void OnDividends(Dividends dividends) { // Get the total dividend payment amount. var totalDividendAmount = dividends[_spy.Symbol].Distribution * _spy.Holdings.Quantity; // Calculate the number of shares you can buy with the dividend payment. var quantity = Math.Floor(totalDividendAmount / _spy.Price); if (quantity > 0) { // Place an order to re-invest the dividends. MarketOrder(_spy.Symbol, quantity); } } }
class USEquityCorporateActionExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # Add raw Equity data. self._spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW) def on_data(self, slice: Slice) -> None: # Buy and hold. if not self._spy.holdings.invested: self.set_holdings(self._spy.symbol, 0.5) def on_dividends(self, dividends: Dividends) -> None: # Get the total dividend payment amount. total_dividend_amount = dividends[self._spy.symbol].distribution * self._spy.holdings.quantity # Calculate the number of shares you can buy with the dividend payment. quantity = np.floor(total_dividend_amount / self._spy.price) if quantity: # Place an order to re-invest the dividends. self.market_order(self._spy.symbol, quantity)