Securities
Handling Data
Introduction
If you create a data subscription, your algorithm receives data updates for that security or custom data source.
Get Prices
LEAN uses data updates to set the current prices of a security and compute the contribution of securities you hold to the portfolio value.
To get the current prices of a security, find the Security
object in the Securities
securities
dictionary and access the price attributes.
// Use the Securities object as a dictionary to get the current ask and bid price of the SPY. var security = Securities["SPY"]; var price = security.Price; var bidPrice = security.BidPrice; var askPrice = security.AskPrice;
# Use the securities object as a dictionary to get the current ask and bid price of the SPY. security = self.securities["SPY"] price = security.price bid_price = security.bid_price ask_price = security.ask_price
Data Events
The Slice
that LEAN passes to the OnData
on_data
method represents all of the data for your subscriptions at a single point in time. The Slice
object contains data like Tick
objects, TradeBar
objects, QuoteBar
objects, corporate actions, and chains for Option and Future contracts. You can use the data in the Slice
to make trading decisions.
To access data in the Slice
, index it with the security Symbol
. If you use the security ticker instead of the Symbol
, LEAN automatically finds the Symbol
.
// Use the OnData method to get the data for a symbol in the current time slice. public override void OnData(Slice slice) { if (slice.ContainsKey(_symbol)) { var myData = slice[_symbol]; } }
# Use the OnData method to get the data for a symbol in the current time slice. def on_data(self, slice: Slice) -> None: if slice.contains_key(self._symbol): my_data = slice[self._symbol]
The following table shows the Slice
property to index based on the data format you want:
Data Format | Slice Property |
---|---|
TradeBar | Bars bars |
QuoteBar | QuoteBars quote_bars |
Tick | Ticks ticks |
// Get the tradebar from the slice. public override void OnData(Slice slice) { if (slice.ContainsKey(_symbol)) { var bar = slice.Bars[_symbol]; } }
# Get the tradebar from the slice. def on_data(self, slice: Slice) -> None: if slice.contains_key(self._symbol): bar = slice.bars[self._symbol]
If you just index the Slice
instead of the preceding properties, it returns the correct object. For instance, if your data subscription provides QuoteBar
objects and you index the Slice
with the security Symbol
, it returns the QuoteBar
.
For more information about the Slice
class, see Timeslices.
Cache
To get the most recent data for a security, call the GetLastData
get_last_data
method on the Security
object.
// Get the most recent data for a security. var data = Securities["SPY"].GetLastData();
# Get the most recent data for a security. data = self.securities["SPY"].get_last_data()
The Cache
cache
property of a Security
object provides additional price information since you can access TradeBar
, QuoteBar
, and Tick
data.
// Get additional price information for the security. var cache = Securities["SPY"].Cache; var tradeBar = cache.GetData<TradeBar>(); var quoteBar = cache.GetData<QuoteBar>(); var ticks = cache.GetAll<Tick>();
# Get additional price information for the security cache = self.securities["SPY"].cache trade_bar = cache.get_data[TradeBar]() quote_bar = cache.get_data[QuoteBar]() ticks = cache.get_all[Tick]()
Examples
The following examples demonstrate some common practices for handling data.
Example 1: Use QuoteBar Data
To increase the accuracy of indicator values for illiquid assets, update the indicator with the mid-price of a quote bar.
private Symbol _symbol; // Initialize a new instance of a SimpleMovingAverage object private SimpleMovingAverage _indicator = new(20); public override void Initialize() { _symbol = AddEquity("SPY").Symbol; } public override void OnData(Slice slice) { // Check if the QuoteBars received contain SPY quote data if (slice.QuoteBars.ContainsKey(_symbol)) { var quoteBar = slice.QuoteBars[_symbol]; // Calculate the mid price by averaging the bid and ask price var midPrice = (quoteBar.Bid.Close + quoteBar.Ask.Close) * 0.5m; // Update the SMA indicator with the mid price _indicator.Update(quoteBar.EndTime, midPrice); } }
def initialize(self) -> None: self._symbol = self.add_equity("SPY").symbol self._indicator = SimpleMovingAverage(20) def on_data(self, slice: Slice) -> None: # Check if the QuoteBars received contain SPY quote data if slice.quote_bars.contains_key(self._symbol): quote_bar = slice.quote_bars[self._symbol] # Calculate the mid price by averaging the bid and ask price mid_price = (quote_bar.bid.close + quote_bar.ask.close) * 0.5 # Update the SMA indicator with the mid price self._indicator.update(quote_bar.end_time, mid_price)
Example 2: Use Tick Data
To obtain the instant bid and ask size of the latest tick, use tick data.
private Symbol _symbol; // Set up variables to save the bid and ask sizes. private decimal _bidSize = 0m; private decimal _askSize = 0m; public override void Initialize() { _symbol = AddEquity("SPY", Resolution.Tick).Symbol; } public override void OnData(Slice slice) { // Check if the Ticks received contain SPY tick data if (slice.Ticks.ContainsKey(_symbol)) { // Reset the bid and ask size. _bidSize = 0; _askSize = 0; var ticks = slice.Ticks[_symbol]; // Iterate all related ticks to calculate the bid and ask size. // Make sure the tick data is a quote to obtain either bid and ask size. foreach (var tick in ticks.Where(tick => tick.TickType == TickType.Quote)) { // Update the bid or ask size. _bidSize += tick.BidSize; _askSize += tick.AskSize; } } }
def initialize(self) -> None: self._symbol = self.add_equity("SPY", Resolution.TICK).symbol # Set up variables to save the bid and ask price. self._bid_size = 0 self._ask_size = 0 def on_data(self, slice: Slice) -> None: # Check if the Ticks received contain SPY tick data. if slice.ticks.contains_key(self._symbol): # Reset the bid and ask size self._bid_size = 0 self._ask_size = 0 ticks = slice.ticks[self._symbol] # Iterate all related ticks to calculate the bid and ask size. for tick in ticks: # Make sure the tick data is a quote to obtain either bid and ask size. if tick.tick_type == TickType.QUOTE: # Update the bid or ask size. self._bid_size += tick.bid_size self._ask_size += tick.ask_size
Example 3: Fundamental Cache
To get the fundamentals of an Equity, use its Fundamental
data cache.
public override void OnData(Slice slice) { // Iterate active security objects. foreach (var security in ActiveSecurities.Values) { // Get the Fundamental cache. var fundamental = security.Fundamentals; // Get the sector code. var sectorCode = fundamental.AssetClassification.MorningstarSectorCode; } }
def on_data(self, slice: Slice) -> None: # Iterate active security objects. for security in self.active_securities.values(): # Get the Fundamental cache. fundamental = security.fundamentals # Get the sector code. sector_code = fundamental.asset_classification.morningstar_sector_code
Example 4: Access Option Greeks
To get properties of an Option contract, use the OptionChains
option_chains
property of the Slice
.
private Symbol _symbol; public override void Initialize() { // Subscribe to the Option data. var option = AddOption("SPY"); // Set the Option universe filter. option.SetFilter(x => x.IncludeWeeklys().Strikes(-5, 5).Expiration(0, 60)); // Save a reference of the canonical symbol. _symbol = option.Symbol; } public override void OnData(Slice slice) { // Try to get the Option contracts within the Option chain. if (slice.OptionChains.TryGetValue(_symbol, out var chain)) { foreach (var contract in chain) { // Get the implied volatility and greeks of each Option contract. var iv = contract.ImpliedVolatility; var greeks = contract.Greeks; var delta = greeks.Delta; var gamma = greeks.Gamma; var vega = greeks.Vega; var theta = greeks.Theta; var rho = greeks.Rho; } } }
def initialize(self) -> None: # Subscribe to the Option data. option = self.add_option("SPY") # Set the Option universe filter. option.set_filter(lambda x: x.include_weeklys().strikes(-5, 5).expiration(0, 60)) # Save a reference of the canonical symbol. self._symbol = option.symbol def on_data(self, slice: Slice) -> None: # Try to get the Option contracts within the Option chain. chain = slice.option_chains.get(self._symbol) if chain: for contract in chain: # Get the implied volatility and greeks of each Option contract. iv = contract.implied_volatility greeks = contract.greeks delta = greeks.delta gamma = greeks.gamma vega = greeks.vega theta = greeks.theta rho = greeks.rho
Example 5: Get Asset Sentiment Values
The following example demonstrates how to get sentiment values from the Brain Sentiment Indicator:
private Symbol _dataset7DaySymbol; public override void Initialize() { var aapl = AddEquity("AAPL", Resolution.Daily).Symbol; // Subscribe to 7-day sentiment data. _dataset7DaySymbol = AddData<BrainSentimentIndicator7Day>(aapl).Symbol; } public override void OnData(Slice slice) { // Check if the current slice contains the 7-day sentiment data. if (slice.ContainsKey(_dataset7DaySymbol)) { var dataPoint = slice[_dataset7DaySymbol]; // Log the sentiment value. Log($"{_dataset7DaySymbol} sentiment at {slice.Time}: {dataPoint.Sentiment}"); } }
def initialize(self) -> None: aapl = self.add_equity("AAPL", Resolution.DAILY).symbol # Subscribe to 7-day sentiment data. self.dataset_7day_symbol = self.add_data(BrainSentimentIndicator7Day, aapl).symbol def on_data(self, slice: Slice) -> None: # Check if the current slice contains the 7-day sentiment data. if slice.contains_key(self.dataset_7day_symbol): data_point = slice[self.dataset_7day_symbol] # Log the sentiment value. self.log(f"{self.dataset_7day_symbol} sentiment at {slice.time}: {data_point.sentiment}")