Requesting Data

Universes

Introduction

The AddFutureadd_future method enables you to select a basket of Future contracts for an underlying Future. To form your universe of contracts, you can filter them down by their expiry. If you want to subscribe to individual contracts one-by-one instead of a set of contracts, see Individual Contracts.

Create Universes

To add a universe of Future contracts, in the Initializeinitialize method, call the AddFutureadd_future method. This method returns an Future object, which has a SetFilterset_filter method you can call to filter the set of tradable contract down to just the contracts you want.

Example: Continous Future Filtering And Rollover

The following algorithm shows how to request continuous Futures data of E-Mini S&P 500, with a universe filter to obtain only the contracts expiring within 6 months. To access the data of the continuous Future contract and mapped contract, you need to call the Symbol

symbol and Mapped

mapped properties of the Future object respectively, while accessing all contracts in the filtered Future chain using FuturesChains

future_chains of the Slice object.

To rollover the old mapped contract to the new one, you can refer to the below making use of the OnSymbolChangedEvents

on_symbol_changed_events event handler.

public class BasicFutureAlgorithm : QCAlgorithm
{
    private Future _future;
    public override void Initialize()
    {
        _future = AddFuture(Futures.Indices.SP500EMini,
            extendedMarketHours: true,
            dataMappingMode: DataMappingMode.OpenInterest,
            dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
            contractDepthOffset: 0);
        _future.SetFilter(0, 182);
    }

    public override void OnData(Slice data)
    {
        data.Bars.TryGetValue(_future.Symbol, out var continuousTradeBar);
        data.Bars.TryGetValue(_future.Mapped, out var mappedTradeBar);

        foreach (var (continuousSymbol, chain) in data.FuturesChains)
        {
            foreach (var (symbol, contract) in chain.Contracts)
            {
                var expiry = contract.Expiry;
            }
        }
    }

    // Track events when security changes its ticker, allowing the algorithm to adapt to these changes.
    public override void OnSymbolChangedEvents(SymbolChangedEvents symbolChangedEvents)
    {
        foreach (var (symbol, changedEvent) in symbolChangedEvents)
        {
            var oldSymbol = changedEvent.OldSymbol;
            var newSymbol = changedEvent.NewSymbol;
            var quantity = Portfolio[oldSymbol].Quantity;

            // Rolling over: to liquidate any position of the old mapped contract and switch to the newly mapped contract
            var tag = $"Rollover - Symbol changed at {Time}: {oldSymbol} -> {newSymbol}";
            Liquidate(oldSymbol, tag: tag);
            if (quantity != 0) MarketOrder(newSymbol, quantity, tag: tag);
        }
    }
}
class BasicFutureAlgorithm(QCAlgorithm):
    def initialize(self):
        self._future = self.add_future(Futures.Indices.SP_500_E_MINI,
            extended_market_hours=True,
            data_mapping_mode=DataMappingMode.OPEN_INTEREST,
            data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO,
            contract_depth_offset=0)
        self._future.set_filter(0, 182)
    
    def on_data(self, data):
        continuous_trade_bar = data.bars.get(self._future.symbol)
        mapped_trade_bar = data.bars.get(self._future.mapped)

        for continuous_symbol, chain in data.future_chains.items():
            for symbol, contract in chain.contracts.items():
                expiry = contract.expiry
    
    # Track events when security changes its ticker allowing algorithm to adapt to these changes.
    def on_symbol_changed_events(self, symbol_changed_events):
        for symbol, changed_event in  symbol_changed_events.items():
            old_symbol = changed_event.old_symbol
            new_symbol = changed_event.new_symbol
            quantity = self.portfolio[old_symbol].quantity

            # Rolling over: to liquidate any position of the old mapped contract and switch to the newly mapped contract
            tag = f"Rollover - Symbol changed at {self.time}: {old_symbol} -> {new_symbol}"
            self.liquidate(old_symbol, tag=tag)
            if quantity: self.market_order(new_symbol, quantity, tag=tag)

For more information about the AddFutureadd_future method, see Create Universes.

Continous Contracts

By default, LEAN only subscribes to the continuous Future contract. A continuous Future contract represents a series of separate contracts stitched together to form a continuous price. If you need a lot of historical data to warm up an indicator, apply the indicator to the continuous contract price series. The Future object has a Symbolsymbol property and a Mappedmapped property. The price of the Symbolsymbol property is the adjusted price of the continuous contract. The price of the Mappedmapped property is the raw price of the currently selected contract in the continuous contract series.

// Get the adjusted price of the continuous contract
var adjustedPrice = Securities[_future.Symbol].Price; 

// Get the raw price of the currently selected contract in the continuous contract series
var rawPrice = Securities[_future.Mapped].Price;
# Get the adjusted price of the continuous contract
adjusted_price = self.securities[self._future.symbol].price 

# Get the raw price of the currently selected contract in the continuous contract series
raw_price = self.securities[self._future.mapped].price

The continuous Futures contract isn't a tradable security. You must place orders for a specific Futures contract. To access the currently selected contract in the continuous contract series, use the Mappedmapped property of the Future object.

// Place a market order for the currently selected contract in the continuous contract series
MarkerOrder(_future.Mapped, 1); 
# Place a market order for the currently selected contract in the continuous contract series
self.market_order(self._future.mapped, 1)

For more information, see Continous Contracts.

Filter by Contract Properties

To set a contract filter, in the Initializeinitialize method, call the SetFilterset_filter method of the Future object. The following table describes the available filter techniques:

SetFilter(int minExpiry, int maxExpiry)set_filter(minExpiry: int, maxExpiry: int)

Selects the contracts that expire within the range you set. This filter runs asynchronously by default.

SetFilter(Func<FutureFilterUniverse, FutureFilterUniverse> universeFunc)set_filter(universeFunc: Callable[[FutureFilterUniverse], FutureFilterUniverse])

Selects the contracts that a function selects.

# Select the contracts which expire within 182 days
self._future.set_filter(0, 182)

# Select the front month contract
self._future.set_filter(lambda future_filter_universe: future_filter_universe.front_month())
// Select the contracts which expire within 182 days
_future.SetFilter(0, 182);

// Select the front month contract
_future.SetFilter(futureFilterUniverse => futureFilterUniverse.FrontMonth());

The following table describes the filter methods of the FutureFilterUniverse class:

StandardsOnly()standards_only()

Selects standard contracts

IncludeWeeklys()include_weeklys()

Selects non-standard weekly contracts

WeeklysOnly()weeklys_only()

Selects weekly contracts

FrontMonth()front_month()

Selects the front month contract

BackMonths()back_months()

Selects the non-front month contracts

BackMonth()back_month()

Selects the back month contracts

Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)expiration(min_expiry: timedelta, max_expiry: timedelta)

Selects contracts that expire within a range of dates relative to the current day

Expiration(int minExpiryDays, int maxExpiryDays)expiration(min_expiry_days: int, max_expiry_days: int)

Selects contracts that expire within a range of dates relative to the current day

Contracts(IEnumerable<Symbol> contracts)contracts(contracts: List[Symbol])

Selects a list of contracts

Contracts(Func<IEnumerable<Symbol>, IEnumerable< Symbol>> contractSelector)contracts(contractSelector: Callable[[List[Symbol]], List[Symbol]])

Selects contracts that a selector function selects

The preceding methods return an FutureFilterUniverse, so you can chain the methods together.

// Select the front month standard contracts
_future.SetFilter(futureFilterUniverse => futureFilterUniverse.StandardsOnly().FrontMonth());
# Select the front month standard contracts
self._future.set_filter(lambda future_filter_universe: future_filter_universe.standards_only().front_month())

You can also define an isolated filter method.

// In Initialize
_future.SetFilter(Selector);
    
private FutureFilterUniverse Selector(FutureFilterUniverse futureFilterUniverse)
{
    return futureFilterUniverse.StandardsOnly().FrontMonth();
}
# In Initialize
self._future.set_filter(self._contract_selector)
    
def _contract_selector(self, 
    future_filter_universe: Callable[[FutureFilterUniverse], FutureFilterUniverse]) -> FutureFilterUniverse:
    return future_filter_universe.standards_only().front_month()

Default Filter

By default, LEAN doesn't add any contracts to the FuturesChain it passes to the OnDataon_data method.

Examples

The following examples demonstrate some common practices for requesting Futures universe data.

Example 1: Rollover

Future contracts expire monthly or quarterly in most cases. Hence, if we hold Future position in month or quarter end, we must consider rolling over to the mapped contract. The following algorithm shows how to buy and roll over to the next front month Future contract. We make use of the universe selection filter to select the front month contract and order the next mapped contract during the previous one expires.

public class FutureExampleAlgorithm : QCAlgorithm
{
    private Symbol _future;

    public override void Initialize()
    {
        var future = AddFuture(Futures.Indices.SP500EMini, extendedMarketHours: true);
        _future = future.Symbol;
        // We only want to hold position of the front month contract.
        future.SetFilter(u => u.FrontMonth());
    }
    
    public override void OnSecuritiesChanged(SecurityChanges changes)
    {
        // Liquidate if expired (or not being the front month contract anymore) and exit universe.
        foreach (var removed in changes.RemovedSecurities)
        {
            Liquidate(removed.Symbol);
        }
        
        foreach (var added in changes.AddedSecurities)
        {
            // Make sure the newly added contract is an actual mapped tradable contract.
            if (!added.Symbol.IsCanonical())
            {
                // Roll over by ordering the same quantity.
                // Use limit order since market on open order is not supported on Future and avoid extreme quote filling.
                LimitOrder(added.Symbol, 1m, Securities[_future].Price);
            }
        }
    }
}
class FutureExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        future = self.add_future(Futures.Indices.SP_500_E_MINI, extended_market_hours=True)
        self._future = future.symbol
        # We only want to hold position of the front month contract.
        future.set_filter(lambda u: u.front_month())
    
    def on_securities_changed(self, changes: SecurityChanges) -> None:
        # Liquidate if expired (or not being the front month contract anymore) and exit universe.
        for removed in changes.removed_securities:
            self.liquidate(removed.symbol)
        
        for added in changes.added_securities:
            # Make sure the newly added contract is an actual mapped tradable contract.
            if not added.symbol.is_canonical():
                # Roll over by ordering the same quantity.
                # Use limit order since market on open order is not supported on Future and avoid extreme quote filling.
                self.limit_order(added.symbol, 1, self.securities[self._future].price)

Example 2: Continuous Future Indicator

One of the major applications of Continuous Future is to obtain smooth price series to feed into indicators. This can ensure the indicator gets the correct price data that is comparable to the current mapped Future contract. In this example, we demonstrate a 252-day Exponential Moving Average indicator update using continuous ES contract data.

public class FutureExampleAlgorithm : QCAlgorithm
{
    private Future _future;

    public override void Initialize()
    {
        // Use backward ratio normalization for continuous contract to feed smooth, comparable price series to the indicator.
        _future = AddFuture(Futures.Indices.SP500EMini,
            dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
            extendedMarketHours: true);
        // We only want to hold position of the front month contract.
        _future.SetFilter(u => u.FrontMonth());
        // Create a 252-day EMA indicator as a trend estimator.
        ((dynamic)_future).ema = EMA(_future.Symbol, 252, Resolution.Daily);
        // Warm up the EMA indicator to make it readily available.
        WarmUpIndicator(_future.Symbol, _future.Get<ExponentialMovingAverage>("ema"));
    }
    
    public override void OnData(Slice slice)
    {
        // Ensure the TradeBar data is available for the Future. Only use updated price data to update the indicator and make trading decision.
        if (slice.Bars.TryGetValue(_future.Symbol, out var bar))
        {
            // Buy the mapped contract if the trend is estimated to go up (price above EMA).
            if (_future.Get<ExponentialMovingAverage>("ema") >= bar.Close)
            {
                SetHoldings(_future.Mapped, 0.1m);
            }
            // Short the mapped contract if the trend is estimated to go down (price below EMA).
            else
            {
                SetHoldings(_future.Mapped, -0.1m);
            }
         }
    }
    
    public override void OnSecuritiesChanged(SecurityChanges changes)
    {
        // Liquidate if expired (or not being the front month contract anymore) and exit universe.
        foreach (var removed in changes.RemovedSecurities)
        {
            Liquidate(removed.Symbol);
        }
    }
}
class FutureExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        # Use backward ratio normalization for continuous contract to feed smooth, comparable price series to the indicator.
        self._future = self.add_future(Futures.Indices.SP_500_E_MINI,
            data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO,
            extended_market_hours=True)
        # We only want to hold position of the front month contract.
        self._future.set_filter(lambda u: u.front_month())
        # Create a 252-day EMA indicator as a trend estimator.
        self._future.ema = self.ema(self._future.symbol, 252, Resolution.DAILY)
        # Warm up the EMA indicator to make it readily available.
        self.warm_up_indicator(self._future.symbol, self._future.ema)
    
    def on_data(self, slice: Slice) -> None:
        # Ensure the TradeBar data is available for the Future. Only use updated price data to update the indicator and make trading decision.
        bar = slice.bars.get(self._future.symbol)
        if bar:
            # Buy the mapped contract if the trend is estimated to go up (price above EMA).
            if self._future.ema.current.value >= bar.close:
                self.set_holdings(self._future.mapped, 0.1)
            # Short the mapped contract if the trend is estimated to go down (price below EMA).
            else:
                self.set_holdings(self._future.mapped, -0.1)
    
    def on_securities_changed(self, changes: SecurityChanges) -> None:
        # Liquidate if expired (or not being the front month contract anymore) and exit universe.
        for removed in changes.removed_securities:
            self.liquidate(removed.symbol)

Example 3: Contango

In Future trading, contango refers to the far-to-expiry Future contract price is higher than the spot price due to various reasons, such as storage fee and insurance of the commodities. The following example shows a contango trading by shorting the far contract that the price is above a threshold compared to the front month contract price and buying the front month contract to earn the premium in between.

public class FutureExampleAlgorithm : QCAlgorithm
{
    private Symbol _future;

    public override void Initialize()
    {
        // Allow extended market hours trade, which is common for Future since extended market hour is still popular.
        var future = AddFuture(Futures.Metals.MicroGold, extendedMarketHours: true);
        _future = future.Symbol;
        // Limit the expiration to within 6 months, as the longer the expiration, the higher the price uncertainty.
        future.SetFilter((u) => u.Expiration(0, 183));
    }
    
    public override void OnData(Slice slice)
    {
        // Get Future chain only for the selected Future contract.
        if (!Portfolio.Invested && slice.FutureChains.TryGetValue(_future, out var chain))
        {
            // It takes 2 contracts with different expiries to form a horizontal spread arbitration to earn price difference in contango.
            if (chain.Count() < 2) return;
            var farContract = chain.MaxBy(x => x.Expiry);
            var nearContract = chain.MinBy(x => x.Expiry);
    
            // Check if the far contract price is 1% higher than the near one.
            // If so, short the far contract and buy the near one to earn the horizontal spread premium.
            if (farContract.BidPrice >= nearContract.AskPrice * 1.01m)
            {
                MarketOrder(farContract.Symbol, -1);
                MarketOrder(nearContract.Symbol, 1);
            }
        }
    }
    
    public override void OnSecuritiesChanged(SecurityChanges changes)
    {
        // Liquidate if expired (or not being the front month contract anymore) and exit universe.
        foreach (var removed in changes.RemovedSecurities)
        {
            Liquidate();
        }
    }
}
class FutureExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        # Allow extended market hours trade, which is common for Future since extended market hour is still popular.
        future = self.add_future(Futures.Metals.MICRO_GOLD, extended_market_hours=True)
        self._future = future.symbol
        # Limit the expiration to within 6 months, as the longer the expiration, the higher the price uncertainty.
        future.set_filter(lambda u: u.expiration(0, 183))
    
    def on_data(self, slice: Slice) -> None:
        # Get Future chain only for the selected Future contract.
        chain = slice.future_chains.get(self._future)
        if not self.portfolio.invested and chain:
            # It takes 2 contracts with different expiries to form a horizontal spread arbitration to earn price difference in contango.
            if len(list(chain)) < 2:
                return
            sorted_by_expiry = sorted(chain, key=lambda x: x.expiry)
            far_contract = sorted_by_expiry[-1]
            near_contract = sorted_by_expiry[0]
    
            # Check if the far contract price is 1% higher than the near one.
            # If so, short the far contract and buy the near one to earn the horizontal spread premium.
            if far_contract.bid_price >= near_contract.ask_price * 1.01:
                self.market_order(far_contract.symbol, -1)
                self.market_order(near_contract.symbol, 1)
    
    def on_securities_changed(self, changes: SecurityChanges) -> None:
        # Liquidate if expired (or not being the front month contract anymore) and exit universe.
        for removed in changes.removed_securities:
            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: