Problem Description
Solution
To handle a stock changing its ticker symbol in QuantConnect, you utilize the on_symbol_changed_events event handler.
In the LEAN engine, the unique Symbol object (the internal ID) remains constant even if the string representation (the Ticker) changes. LEAN automatically maps historical data and portfolio holdings to the new ticker. However, you should use the event handler to log changes, update any string-based dictionaries you might be maintaining, or adjust open orders.
Implementation Strategy
- Automatic Handling: You do not need to sell the old stock and buy the new one. The
self.portfolioobject automatically updates the holding to reflect the new ticker. - Event Handler: Implement
on_symbol_changed_eventsto capture the exact moment the change occurs. - Order Management: It is best practice to cancel open orders associated with the old ticker string if your logic relies heavily on specific ticker naming conventions, though LEAN attempts to map these as well.
Code Example
The following algorithm demonstrates how to capture a symbol change event.
# region imports
from AlgorithmImports import *
# endregion
class SymbolChangeHandlingAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2022, 6, 1) # Example date around a ticker change
self.set_end_date(2022, 6, 15)
self.set_cash(100000)
# Example: Facebook (FB) changed to Meta Platforms (META) on June 9, 2022.
# Even if we add the NEW ticker, LEAN loads the history for the OLD ticker
# automatically before the change date.
self.equity = self.add_equity("META", Resolution.DAILY)
self.symbol = self.equity.symbol
# Invest to demonstrate portfolio mapping
self.set_holdings(self.symbol, 0.5)
def on_data(self, data: Slice):
# Standard data processing
if self.symbol in data.bars:
bar = data.bars[self.symbol]
# self.log(f"{self.time} :: {self.symbol.value} :: Close: {bar.close}")
def on_symbol_changed_events(self, symbol_changed_events: SymbolChangedEvents):
"""
This event fires specifically when a ticker symbol changes.
"""
for symbol, changed_event in symbol_changed_events.items():
old_ticker = changed_event.old_symbol
new_ticker = changed_event.new_symbol
self.log(f"SYMBOL CHANGE DETECTED at {self.time}")
self.log(f"Old Ticker: {old_ticker} -> New Ticker: {new_ticker}")
# Example Logic: Cancel open orders for this security to avoid confusion
open_orders = self.transactions.get_open_orders(symbol)
if len(open_orders) > 0:
self.transactions.cancel_open_orders(symbol)
self.log(f"Cancelled {len(open_orders)} open orders due to symbol change.")
# Verify Portfolio State
# The portfolio object automatically updates to the new ticker
holding = self.portfolio[symbol]
self.log(f"Current Holding for {new_ticker}: {holding.quantity} shares")
Key Concepts
Symbolvs. Ticker: In QuantConnect,self.symbolis an object containing a unique identifier (SID). When a company rebrands (e.g., FB to META), the Ticker string property changes, but the SID remains the same. This ensures data continuity.SymbolChangedEventsObject: This dictionary-like object containsSymbolChangedEventitems.changed_event.old_symbol: The string representation of the previous ticker.changed_event.new_symbol: The string representation of the new ticker.
- Data Request: If you run an algorithm starting in 2010 and add "META", LEAN automatically serves "FB" data for the years prior to the change.
Q&A: Handling Corporate Actions
Q: Do I need to manually update my portfolio holdings when a ticker changes?
A: No. The LEAN engine automatically maps your existing holdings to the new ticker symbol. Your self.portfolio[symbol].quantity will remain consistent, but self.portfolio[symbol].symbol.value will reflect the new name.
Q: What happens to my historical data indicators after a name change?
A: Indicators are tied to the Symbol object, not the ticker string. Because the underlying Symbol object ID persists through the name change, your Moving Averages, RSI, or other indicators will continue to update seamlessly without resetting.
Q: Will on_data stop receiving data for the old ticker?
A: Yes. Once the change event occurs, the Slice object in on_data will reference the data using the new ticker string. If you access data using data["OLD_TICKER"], it will fail; you must use the Symbol object or the new ticker string.