Requesting Data
Universes
Introduction
The add_future_option
method enables you to select a basket of Option contracts for an underlying Future.
To form your universe of contracts, you can filter them down by their strike price and expiry or you can choose a subset of the contracts that form popular Option strategies.
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 Option contracts, in the initialize
method, call the add_future_option
method. Pass the option_filter
argument to filter the set of tradable contract down to just the contracts you want.
class BasicFutureOptionAlgorithm(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) self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.strikes(-1, 1)) def on_data(self, data): # Iterate all Option chains to find the desired future and future options contracts for canonical_symbol, chain in data.option_chains.items(): future_contract = canonical_symbol.underlying for symbol, contract in chain.contracts.items(): strike = contract.strike # Get the Option chain for the mapped contract mapped_chain = data.option_chains.get(Symbol.create_canonical_option(self._future.mapped)) if mapped_chain: for symbol, contract in mapped_chain.contracts.items(): strike = contract.strike
For more information about the add_future_option
method, see Create Universes.
Filter by Investment Strategy
Options trading strategies consist of simultaneously buying or selling one or more Option contracts of the same underlying Future with different features. The following table describes the filter methods of the OptionFilterUniverse
class that select contract for Option strategies.
The following table describes the filter methods of the OptionFilterUniverse
class that select contracts for Option strategies:
naked_call(min_days_till_expiry: int, strike_from_atm: float) Selects a call contract to form Naked Call, Covered Call, or Protective Call Option strategies. |
naked_put(min_days_till_expiry: int, strike_from_atm: float) Selects a put contract to form Naked Put, Covered Put, or Protective Put Option strategies. |
call_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float) Selects two call contracts to form Bull Call Spread or Bear Call Spread Option strategies. |
put_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float) Selects two put contracts to form Bull Put Spread or Bear Put Spread Option strategies. |
call_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int) Selects two call contracts to form Long Call Calendar Spread or Short Call Calendar Spread Option strategies. |
put_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int) Selects two put contracts to form Long Put Calendar Spread or Short Put Calendar Spread Option strategies. |
strangle(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float) Selects two contracts to form Long Strangle or Short Strangle Option strategies. |
straddle(min_days_till_expiry: int) Selects two contracts to form Long Straddle or Short Straddle Option strategies. |
protective_collar(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float) Selects two contracts to form Protective Collar Option strategies. |
conversion(min_days_till_expiry: int, strike_from_atm: float) Selects two contracts to form Conversion or Reverse Conversion Option strategies. |
call_butterfly(min_days_till_expiry: int, strike_spread: float) Selects three contracts to form Long Call Butterfly or Short Call Butterfly Option strategies. |
put_butterfly(min_days_till_expiry: int, strike_spread: float) Selects three contracts to form Long Put Butterfly or Short Put Butterfly Option strategies. |
iron_butterfly(min_days_till_expiry: int, strike_spread: float) Selects four contracts to form Long Iron Butterfly or Short Iron Butterfly Option strategies. |
iron_condor(min_days_till_expiry: int, near_strike_spread: float, far_strike_spread: float) Selects four contracts to form Long Iron Condor or Short Iron Condor Option strategies. |
box_spread(min_days_till_expiry: int, strike_spread: float) Selects four contracts to form Box Spread or Short Box Spread Option strategies. |
jelly_roll(strike_from_atm: float, min_near_days_till_expiry: int, min_far_days_till_expiry: int) Selects four contracts to form Jelly Roll or Short Jelly Roll Option strategies. |
call_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float) Selects four contracts to form Bear Call Ladder or Bull Call Ladder Option strategies. |
put_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float) Selects four contracts to form Bear Put Ladder or Bull Put Ladder Option strategies. |
The preceding methods return an OptionFilterUniverse
, so you can chain the methods together.
# Example 1: Select a Straddle self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.straddle(30, 5, 10)) # Example 2: Select the contracts (including weeklys) that expire in the next 30 days that form an Iron Condor self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.strikes(-20, 20).expiration(0, 30).iron_condor(30, 5, 10)) # Example 3: Select the front month contracts that form an Strangle self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.front_month().strangle(30, 5, -10))
Filter by Other Contract Properties
To set a contract filter, in the initialize
method, call the add_future_option
method and pass the option_filter
argument.
# Select contracts that have a strike price within 1 strike level above and below the underlying price self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.strikes(-1,1)) # Select contracts that expire within 30 days self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.expiration(0,30)) # Select contracts that have a strike price within 1 strike level and expire within 30 days self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.strikes(-1,1).expiration(0,30)) # Select call contracts self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.calls_only())
The following table describes the filter methods of the OptionFilterUniverse
class:
strikes(min_strike: int, max_strike: int) Selects contracts that are within |
calls_only() Selects call contracts. |
puts_only() Selects put contracts. |
standards_only() Selects standard contracts. |
include_weeklys() Selects non-standard weeklys contracts. |
weeklys_only() Selects weekly contracts. |
front_month() Selects the front month contract. |
back_months() Selects the non-front month contracts. |
back_month() Selects the back month contracts. |
expiration(min_expiryDays: int, max_expiryDays: int) Selects contracts that expire within a range of dates relative to the current day. |
contracts(contracts: List[Symbol]) Selects a list of contracts. |
contracts(contract_selector: Callable[[List[Symbol]], List[Symbol]]) Selects contracts that a selector function selects. |
The preceding methods return an OptionFilterUniverse
, so you can chain the methods together.
The preceding methods return an OptionFilterUniverse
, so you can chain the methods together.
# Example 1: Select the front month call contracts self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.calls_only().front_month()) # Example 2: Select the contracts that expire in the next 90 days self.add_future_option(self._future.symbol, lambda option_filter_universe: option_filter_universe.strikes(-20, 20).expiration(0, 90))
To perform thorough filtering on the OptionFilterUniverse
, define an isolated filter method.
class BasicFutureOptionAlgorithm(QCAlgorithm): def initialize(self): self.add_future_option(self._future.symbol, self._selector) def _selector(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse: symbols = option_filter_universe.puts_only() strike = min([symbol.id.strike_price for symbol in symbols]) symbols = [symbol for symbol in symbols if symbol.id.strike_price == strike] return option_filter_universe.contracts(symbols)
Some of the preceding filter methods only set an internal enumeration in the OptionFilterUniverse
that it uses later on in the filter process. This subset of filter methods don't immediately reduce the number of contract Symbol
objects in the OptionFilterUniverse
.
Default Filter
By default, LEAN subscribes to the Option contracts that have the following characteristics:
- Standard type (exclude weeklys)
- Within 1 strike price of the underlying asset price
- Expire within 35 days
To adjust the universe of contracts, set a filter. The filter usually runs at the first bar of every day. When the filter selects a contract that isn't currently in your universe, LEAN adds the new contract data to the next Slice
that it passes to the on_data
method.
Examples
The following examples demonstrate some common practices for requesting Future Option data through universe filtering.
Example 1: Call Spread
The following example demonstrates how to implement a
bull call spread
option strategy using universe filtering. We have to first subscribe to the underlying Future (with filtering), then call
self.add_future_option
with the underlying
Symbol
and the filtering function. We use
call_spread
method in the
OptionFilterUniverse
object to return only the 2 best match call contracts that forms a bull call spread.
class FutureOptionAlgorithm(QCAlgorithm): def initialize(self) -> None: # Filter the underlying continuous Futures to narrow the FOP spectrum. self.underlying = 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.underlying.set_filter(0, 182) # Use CallSpread filter to obtain the 2 best-matched contracts that forms a call spread. # It simplifies from further filtering and reduce computation on redundant subscription. self.add_future_option(self.underlying.symbol, lambda u: u.call_spread(5, 5, -5)) def on_data(self, slice: Slice) -> None: if self.portfolio.invested: return # Create canonical symbol for the mapped future contract, since we need that to access the option chain. symbol = Symbol.create_canonical_option(self.underlying.mapped) # Get option chain data for the mapped future only. # It requires 2 contracts with different strikes to form a call spread, so we make sure at least 2 contracts are present. chain = slice.option_chains.get(symbol) if not chain or len(list(chain)) < 2: return # Separate the contracts by strike, as we need to access their strike. expiry = min([x.expiry for x in chain]) sorted_by_strike = sorted([x.strike for x in chain]) itm_strike = sorted_by_strike[0] otm_strike = sorted_by_strike[-1] # Use abstraction method to order a bull call spread to avoid manual error. option_strategy = OptionStrategies.bull_call_spread(symbol, itm_strike, otm_strike, expiry) self.buy(option_strategy, 1)
Note that since both the underlying Future and the Future Option are expiring on the same day and are cash-settling in most cases, Lean can exercise the Future Option into account cash automatically at expiry and we do not need to handle the option exercise/assignment event.