Index

Handling Data

Introduction

LEAN passes the data you request to the OnDataon_data method so you can make trading decisions. The default OnDataon_data method accepts a Slice object, but you can define additional OnDataon_data methods that accept different data types. For example, if you define an OnDataon_data method that accepts a Tick argument, it only receives Tick objects. The Slice object that the OnDataon_data method receives groups all the data together at a single moment in time. To access the Slice outside of the OnDataon_data method, use the CurrentSlicecurrent_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 Symbolsymbol, but we recommend you use the Symbolsymbol.

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.

Trade bar breakdown

To get the TradeBar objects in the Slice, index the Slice or index the Barsbars 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()

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: