Index
Handling Data
Introduction
LEAN passes the data you request to the OnData
on_data
method so you can make trading decisions. The default OnData
on_data
method accepts a Slice
object, but you can define additional OnData
on_data
methods that accept different data types. For example, if you define an OnData
on_data
method that accepts a Tick
argument, it only receives Tick
objects. The Slice
object that the OnData
on_data
method receives groups all the data together at a single moment in time. To access the Slice
outside of the OnData
on_data
method, use the CurrentSlice
current_slice
property of your algorithm.
All the data formats use DataDictionary
objects to group data by Symbol
and provide easy access to information. The plural of the type denotes the collection of objects. For instance, the Ticks
DataDictionary
is made up of Tick
objects. To access individual data points in the dictionary, you can index the dictionary with the Index ticker or Symbol
symbol
, but we recommend you use the Symbol
symbol
.
To view the resolutions that are available for Index data, see Resolutions.
Bars
You can't trade Indices, but TradeBar
objects are bars that represent the open, high, low, and close of an Index price over a period of time.
To get the TradeBar
objects in the Slice
, index the Slice
or index the Bars
bars
property of the Slice
with the Index Symbol
. The Slice
may not contain data for your Symbol
at every time step. To avoid issues, check if the Slice
contains data for your Index before you index the Slice
with the Index Symbol
.
public override void OnData(Slice slice) { if (slice.Bars.ContainsKey(_symbol)) { var tradeBar = slice.Bars[_symbol]; var value = tradeBar.Value; } }
def on_data(self, slice: Slice) -> None: if self._symbol in slice.bars: trade_bar = slice.bars[self._symbol] value = trade_bar.value
TradeBar
objects have the following properties:
Examples
The following examples demonstrate some common practices for handling Index data.
Example 1: Trading ES Futures Based on the SPX Index RSI
The following algorithm adds daily data for the SPX Index and uses the Relative Strength Index (RSI) indicator to generate trading signals for the E-Mini S&P 500 Future. When the RSI crosses below 30, it buys the front-month ES contract. When the RSI crosses above 70, it liquidates the portfolio.
public class IndexDemoAlgorithm : QCAlgorithm { private dynamic _spx; private Future _es; public override void Initialize() { SetStartDate(2023, 1, 1); SetEndDate(2024, 1, 1); // Add daily SPX Index data. _spx = AddIndex("SPX", Resolution.Daily); // Create an RSI indicator for the SPX index. _spx.Rsi = RSI(_spx.Symbol, 15); // Add the ES front-month Futures contract. _es = AddFuture(Futures.Indices.SP500EMini, dataMappingMode: DataMappingMode.OpenInterest); _es.SetFilter(futureFilterUniverse => futureFilterUniverse.StandardsOnly().FrontMonth()); } public override void OnData(Slice slice) { // Check if the indicator is ready and we have the front-month contract data. if (!_spx.Rsi.IsReady || !slice.Bars.ContainsKey(_es.Mapped)) { return; } // If the SPX RSI is <30, buy the ES. if (!Portfolio.Invested && _spx.Rsi.Current.Value < 30) { SetHoldings(_es.Mapped, 0.5); } // If the SPX RSI is >70, liquidate the portfolio. else if (Portfolio.Invested && _spx.Rsi.Current.Value > 70) { Liquidate(); } } }
class IndexDemoAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2023, 1, 1) self.set_end_date(2024, 1, 1) # Add daily SPX Index data. self._spx = self.add_index("SPX", Resolution.DAILY) # Create an RSI indicator for the SPX index. self._spx.rsi = self.rsi(self._spx.symbol, 15) # Add the ES front-month Futures contract. self._es = self.add_future(Futures.Indices.SP_500_E_MINI, data_mapping_mode=DataMappingMode.OPEN_INTEREST) self._es.set_filter(lambda future_filter_universe: future_filter_universe.standards_only().front_month()) def on_data(self, slice: Slice) -> None: # Check if the indicator is ready and we have the front-month contract data. if not self._spx.rsi.is_ready or self._es.mapped not in slice.bars: return # If the SPX RSI is <30, buy the ES. if not self.portfolio.invested and self._spx.rsi.current.value < 30: self.set_holdings(self._es.mapped, 0.5) # If the SPX RSI is >70, liquidate the portfolio. elif self.portfolio.invested and self._spx.rsi.current.value > 70: self.liquidate()