Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add handling Future Option data examples #1913

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
include(DOCS_RESOURCES."/securities/option-contracts.php");

$contractTypeName = "Option";
$pyContractTypeName = "option";
$chainTypeName = "OptionChains";
$pyChainTypeName = "option_chains";
$variableName = "optionChains";
include(DOCS_RESOURCES."/securities/open-interest.php");
?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
include(DOCS_RESOURCES."/securities/futures-contracts.php");

$contractTypeName = "Future";
$pyContractTypeName = "future";
$chainTypeName = "FuturesChains";
$pyChainTypeName = "futures_chains";
$variableName = "futuresChains";
include(DOCS_RESOURCES."/securities/open-interest.php");
?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
include(DOCS_RESOURCES."/securities/option-contracts.php");

$contractTypeName = "Option";
$pyContractTypeName = "option";
$chainTypeName = "OptionChains";
$pyChainTypeName = "option_chains";
$variableName = "optionChains";
include(DOCS_RESOURCES."/securities/open-interest.php");
?>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<p>The following examples demonstrate some common practices for handling Future Option data.</p>

<h4>Example 1: Monthly Protective Put</h4>
<p>The following algorithm shows how to perform monthly selection on individual ES Future Option contract to implement a <a href="/docs/v2/writing-algorithms/trading-and-orders/option-strategies/protective-put">protective put</a> option strategy to hedge speculation on S&P500 Future. It is a useful tool to hedge the excessive risk on leverage using Futures to trade.</p>

<div class="section-example-container">
<pre class="csharp">public class FutureOptionExampleAlgorithm : QCAlgorithm
{
private Future _underlying;

public override void Initialize()
{
// Seed the security price to ensure the underlying price is available at the initial filtering.
SetSecurityInitializer((security) =&gt; new FuncSecuritySeeder(GetLastKnownPrices).SeedSecurity(security));
// Subscribe the underlying since the updated price is needed for filtering.
_underlying = AddFuture(Futures.Indices.SP500EMini,
dataMappingMode: DataMappingMode.OpenInterest,
dataNormalizationMode: DataNormalizationMode.Raw,
contractDepthOffset: 0);
// Filter the underlying continuous Futures to narrow the FOP spectrum.
_underlying.SetFilter(0, 31);

// Schedule a monthly event on selection of future-future option pair, since the portfolio rebalance on a monthly basis.
Schedule.On(
DateRules.MonthStart(_underlying.Symbol),
TimeRules.AfterMarketOpen(_underlying.Symbol, 0),
SelectionAndRebalance
);
}

private void SelectionAndRebalance()
{
// Get all available put FOP contract for the mapped underlying contract, since the trade liquidity and volatility is the highest.
var contractSymbols = OptionChainProvider.GetOptionContractList(_underlying.Mapped, Time)
.Where(symbol =&gt; symbol.ID.OptionRight == OptionRight.Put)
.ToList();
// Select the ATM put expires the same date as the underlying. The max expiry of the FOP will expire the same time as the front month future.
var expiry = contractSymbols.Max(symbol =&gt; symbol.ID.Date);
var selected = contractSymbols.Where(symbol =&gt; symbol.ID.Date == expiry)
.OrderBy(symbol =&gt; Math.Abs(symbol.ID.StrikePrice - Securities[_underlying.Mapped].Price))
.First();
// Request the FOP contract data for trading.
var contract = AddFutureOptionContract(selected);

// A Protective Put consists of long a lot of the underlying, and long a put contract.
MarketOrder(_underlying.Mapped, contract.SymbolProperties.ContractMultiplier);
MarketOrder(contract.Symbol, 1);
}
}</pre>
<pre class="python">class FutureOptionExampleAlgorithm(QCAlgorithm):
def initialize(self) -&gt; None:
# Seed the security price to ensure the underlying price is available at the initial filtering.
self.set_security_initializer(lambda security: FuncSecuritySeeder(self.get_last_known_prices).seed_security(security))
# Subscribe the underlying since the updated price is needed for filtering.
self.underlying = self.add_future(Futures.Indices.SP_500_E_MINI,
data_mapping_mode=DataMappingMode.OPEN_INTEREST,
data_normalization_mode=DataNormalizationMode.RAW,
contract_depth_offset=0)
# Filter the underlying continuous Futures to narrow the FOP spectrum.
self.underlying.set_filter(0, 31)

# Schedule a monthly event on selection of future-future option pair, since the portfolio rebalance on a monthly basis.
self.schedule.on(
self.date_rules.month_start(self.underlying.symbol),
self.time_rules.after_market_open(self.underlying.symbol, 0),
self.selection_and_rebalance
)

def selection_and_rebalance(self) -&gt; None:
# Get all available put FOP contract for the mapped underlying contract, since the trade liquidity and volatility is the highest.
contract_symbols = self.option_chain_provider.get_option_contract_list(self.underlying.mapped, self.time)
contract_symbols = [symbol for symbol in contract_symbols if symbol.id.option_right == OptionRight.PUT]
# Select the ATM put expires the same date as the underlying. The max expiry of the FOP will expire the same time as the front month future.
expiry = max(symbol.id.date for symbol in contract_symbols)
filtered_symbols = [symbol for symbol in contract_symbols if symbol.id.date == expiry]
selected = sorted(filtered_symbols, key=lambda symbol: abs(symbol.id.strike_price - self.securities[self.underlying.mapped].price))[0]
# Request the FOP contract data for trading.
contract = self.add_future_option_contract(selected)

# A Protective Put consists of long a lot of the underlying, and long a put contract.
self.market_order(self.underlying.mapped, contract.symbol_properties.contract_multiplier)
self.market_order(contract.symbol, 1)</pre>
</div>

<h4>Example 2: Weekly Covered Call</h4>
<p>The below example demonstrates a weekly-renewing <a href="/docs/v2/writing-algorithms/trading-and-orders/option-strategies/covered-call">covered call</a> strategy to collect credit of selling the option. It filters the ATM call contract that expires within the current week at week start using <code class="csharp">SetFilter</code><code class="python">set_filter</code> filtering function.</p>
<div class="section-example-container">
<pre class="csharp">public class FutureOptionExampleAlgorithm : QCAlgorithm
{
private Future _underlying;

public override void Initialize()
{
// Subscribe the underlying since the updated price is needed for filtering.
_underlying = AddFuture(Futures.Indices.SP500EMini,
extendedMarketHours: true,
dataMappingMode: DataMappingMode.OpenInterest,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
contractDepthOffset: 0);
// Filter the underlying continuous Futures to narrow the FOP spectrum.
_underlying.SetFilter(0, 182);
// Filter for the current-week-expiring calls to formulate a covered call that expires at the end of week.
AddFutureOption(_underlying.Symbol, (u) =&gt; u.IncludeWeeklys().CallsOnly().Expiration(0, 5));
}

public override void OnData(Slice slice)
{
// Create canonical symbol for the mapped future contract, since option chains are mapped by canonical symbol.
var symbol = QuantConnect.Symbol.CreateCanonicalOption(_underlying.Mapped);

// Get option chain data for the mapped future, as both the underlying and FOP have the highest liquidity among all other contracts.
if (!Portfolio.Invested &&
slice.OptionChains.TryGetValue(symbol, out var chain))
{
// Obtain the ATM call that expires at the end of week, such that both underlying and the FOP expires the same time.
var expiry = chain.Max(x =&gt; x.Expiry);
var atmCall = chain.Where(x =&gt; x.Expiry == expiry)
.OrderBy(x =&gt; Math.Abs(x.Strike - x.UnderlyingLastPrice))
.First();

// Use abstraction method to order a covered call to avoid manual error.
var optionStrategy = OptionStrategies.CoveredCall(symbol, atmCall.Strike, expiry);
Buy(optionStrategy, 1);
}
}
}</pre>
<pre class="python">class FutureOptionExampleAlgorithm(QCAlgorithm):
def initialize(self) -&gt; None:
# Subscribe the underlying since the updated price is needed for filtering.
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)
# Filter the underlying continuous Futures to narrow the FOP spectrum.
self.underlying.set_filter(0, 182)
# Filter for the current-week-expiring calls to formulate a covered call that expires at the end of week.
self.add_future_option(self.underlying.symbol, lambda u: u.include_weeklys().calls_only().expiration(0, 5))

def on_data(self, slice: Slice) -&gt; None:
# Create canonical symbol for the mapped future contract, since option chains are mapped by canonical symbol.
symbol = Symbol.create_canonical_option(self.underlying.mapped)

# Get option chain data for the mapped future, as both the underlying and FOP have the highest liquidity among all other contracts.
chain = slice.option_chains.get(symbol)
if not self.portfolio.invested and chain:
# Obtain the ATM call that expires at the end of week, such that both underlying and the FOP expires the same time.
expiry = max(x.expiry for x in chain)
atm_call = sorted([x for x in chain if x.expiry == expiry],
key=lambda x: abs(x.strike - x.underlying_last_price))[0]

# Use abstraction method to order a covered call to avoid manual error.
option_strategy = OptionStrategies.covered_call(symbol, atm_call.strike,expiry)
self.buy(option_strategy, 1)</pre>
</div>

<p>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.</p>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
include(DOCS_RESOURCES."/securities/option-contracts.php");

$contractTypeName = "Option";
$pyContractTypeName = "option";
$chainTypeName = "OptionChains";
$pyChainTypeName = "option_chains";
$variableName = "optionChains";
include(DOCS_RESOURCES."/securities/open-interest.php");
?>
Expand Down
8 changes: 8 additions & 0 deletions Resources/securities/future-chains.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@
<div class='section-example-container'>
<pre class='csharp'>public override void OnData(Slice slice)
{
// Try to get the FutureChain using the canonical symbol
if (slice.FuturesChains.TryGetValue(<?=$cSharpMemberName?>.Canonical, out var chain))
{
// Get all contracts if the FutureChain contains any member
var contracts = chain.Contracts;
}
}
</pre>
<pre class='python'>def on_data(self, slice: Slice) -> None:
# Try to get the FutureChain using the canonical symbol (None if no FutureChain return)
chain = slice.futures_chains.get(<?=$pythonMemberName?>.canonical)
if chain:
# Get all contracts if the FutureChain contains any member
contracts = chain.contracts</pre>
</div>

<p>You can also loop through the <code class="csharp">FuturesChains</code><code class="python">futures_chains</code> property to get each <code>FuturesChain</code>.</p>
<div class='section-example-container'>
<pre class='csharp'>public override void OnData(Slice slice)
{
// Iterate all received Canonical Symbol-FutureChain key-value pairs
foreach (var kvp in slice.FuturesChains)
{
var continuousContractSymbol = kvp.Key;
Expand All @@ -30,8 +35,10 @@
}
}

// Using this overload will only handle any FutureChains object received
public void OnData(FuturesChains futuresChains)
{
// Iterate all received Canonical Symbol-FutureChain key-value pairs
foreach (var kvp in futuresChains)
{
var continuousContractSymbol = kvp.Key;
Expand All @@ -40,6 +47,7 @@
}
}</pre>
<pre class='python'>def on_data(self, slice: Slice) -> None:
# Iterate all received Canonical Symbol-FutureChain key-value pairs
for continuous_contract_symbol, chain in slice.futures_chains.items():
contracts = chain.contracts</pre>
</div>
Expand Down
13 changes: 10 additions & 3 deletions Resources/securities/futures-contracts.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,36 @@
<div class='section-example-container'>
<pre class='csharp'>public override void OnData(Slice slice)
{
// Try to get the FutureChain using the canonical symbol
if (slice.FuturesChains.TryGetValue(<?=$cSharpMemberName?>.Canonical, out var chain))
{
// Get individual contract data
if (chain.Contracts.TryGetValue(<?=$cSharpMemberName?>, out var contract))
{
var price = contract.LastPrice;
}
}
}

// // Using this overload will only handle any FutureChains object received
public void OnData(FuturesChains futuresChains)
{
// Try to get the FutureChain using the canonical symbol
if (futuresChains.TryGetValue(<?=$cSharpMemberName?>.Canonical, out var chain))
{
// Get individual contract data
if (chain.Contracts.TryGetValue(<?=$cSharpMemberName?>, out var contract))
{
var price = contract.LastPrice;
}
}
}</pre>
<pre class='python'>def on_data(self, slice: Slice) -> None:
chain = slice.FuturesChains.get(<?=$pythonMemberName?>.Canonical)
# Try to get the FutureChain using the canonical symbol
chain = slice.future_chains.get(<?=$pythonMemberName?>.canonical)
if chain:
contract = chain.Contracts.get(<?=$pythonMemberName?>)
# Get individual contract data (None if not contained)
contract = chain.contracts.get(<?=$pythonMemberName?>)
if contract:
price = contract.LastPrice</pre>
price = contract.last_price</pre>
</div>
13 changes: 11 additions & 2 deletions Resources/securities/open-interest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<p>Open interest is the number of outstanding contracts that haven't been settled. It provides a measure of investor interest and the market liquidity, so it's a popular metric to use for contract selection. Open interest is calculated once per day. To get the latest open interest value, use the <code class="csharp">OpenInterest</code><code class="python">open_interest</code> property of the <code><?=$contractTypeName?></code> or <code class="csharp"><?=$contractTypeName?>Contract</code><code class="python"><?=$contractTypeName?>Contract</code>.</p>
<p>Open interest is the number of outstanding contracts that haven't been settled. It provides a measure of investor interest and the market liquidity, so it's a popular metric to use for contract selection. Open interest is calculated once per day. To get the latest open interest value, use the <code class="csharp">OpenInterest</code><code class="python">open_interest</code> property of the <code><?=$contractTypeName?></code> or <code class="csharp"><?=$contractTypeName?>Contract</code><code class="python"><?=$pyContractTypeName?>_contract</code>.</p>

<div class='section-example-container'>
<pre class='csharp'>public override void OnData(Slice slice)
{
// Try to get the <?=$chainTypeName?> using the canonical symbol
if (slice.<?=$chainTypeName?>.TryGetValue(_contractSymbol.Canonical, out var chain))
{
// Get individual contract data
if (chain.Contracts.TryGetValue(_contractSymbol, out var contract))
{
// Get the open interest of the selected contracts
var openInterest = contract.OpenInterest;
}
}
Expand All @@ -15,19 +18,25 @@
<? if ($chainTypeName != "FuturesChains") { ?>
public void OnData(<?=$chainTypeName?> <?=$variableName?>)
{
// Try to get the <?=$chainTypeName?> using the canonical symbol
if (<?=$variableName?>.TryGetValue(_contractSymbol.Canonical, out var chain))
{
// Get individual contract data
if (chain.Contracts.TryGetValue(_contractSymbol, out var contract))
{
// Get the open interest of the selected contracts
var openInterest = contract.OpenInterest;
}
}
}
<? } ?></pre>
<pre class='python'>def on_data(self, slice: Slice) -> None:
chain = slice.<?=$chainTypeName?>.get(self._contract_symbol.canonical)
# Try to get the <?=$pyChainTypeName?> using the canonical symbol
chain = slice.<?=$pyChainTypeName?>.get(self._contract_symbol.canonical)
if chain:
# Get individual contract data
contract = chain.contracts.get(self._contract_symbol)
if contract:
# Get the open interest of the selected contracts
open_interest = contract.open_interest</pre>
</div>
Loading