-
Notifications
You must be signed in to change notification settings - Fork 140
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
Securities / Asset Classes / Index Option / Requesting Data / Universes #1901
Comments
@LouisSzeto I'll take this one |
Hi @LouisSzeto I am stuck with the 2nd example.
class PythonTest(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2023,8,1)
self.set_end_date(2024,1,1)
self.set_cash(100_000)
# Subscribe to the option chain.
self._option = self.add_index_option("SPX", Resolution.DAILY)
# Select options that have expiry within 30 to 90 days.
self._option.set_filter(timedelta(30), timedelta(90))
# ATM strike price
self._strike = 0
self.atm_call = None
def on_data(self, slice: Slice) -> None:
if self.portfolio.invested:
return
chain = slice.option_chains.get(self._option.symbol)
if not chain:
return
calls = [contract for contract in chain if contract.right == OptionRight.CALL]
self.atm_call = sorted(calls, key=lambda x: abs(chain.underlying.price - x.strike))[0]
self._strike = self.atm_call.strike
self.log(f"Buy option with expiry: {self.atm_call.expiry}, and strike price: {self.atm_call.strike}")
if self.atm_call and not self.portfolio[self.atm_call.symbol].invested:
self.market_order(self.atm_call.symbol, 1)
def on_securities_changed(self, changes: SecurityChanges) -> None:
for removed in changes.removed_securities:
if removed.symbol == self.atm_call.symbol:
option_chain = self.option_chain_provider.get_option_contract_list(removed.symbol, self.time)
target_expiry = self.time + timedelta(90)
contracts = [contract for contract in option_chain if contract.id.strike_price == self._strike and 85 <= (contract.id.date - target_expiry).days <= 95 and contract.id.option_right == OptionRight.CALL]
if not contracts: return
contract = contracts[0]
# self.liquidate(self.atm_call.symbol)
# self.market_order(contract.value, 1)
self.log(contract) |
Hi @baobach I believe most of your logic is correct. The CSharp: namespace QuantConnect.Algorithm.CSharp
{
public class SampleAlgorithm : QCAlgorithm
{
private Option _indexOption;
public override void Initialize()
{
// Subscribe to the index option and filter to get only the ones expiring in 30-90 days
_indexOption = AddIndexOption("SPX", "SPXW");
_indexOption.SetFilter((u) => u.IncludeWeeklys().CallsOnly().Expiration(30, 90));
}
public override void OnData(Slice slice)
{
// Get option chain data for the canonical symbol
if (!Portfolio.Invested &&
slice.OptionChains.TryGetValue(_indexOption.Symbol, out var chain))
{
// Obtain the ATM call that expires furthest (90 days)
var expiry = chain.Max(x => x.Expiry);
var atmCall = chain.Where(x => x.Expiry == expiry)
.OrderBy(x => Math.Abs(x.Strike - x.UnderlyingLastPrice))
.First();
// Allocate 10% Capital
SetHoldings(atmCall.Symbol, 0.1m);
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
foreach (var removed in changes.RemovedSecurities)
{
// Liquidate the contracts that exit the universe (due to expiry)
if (Portfolio[removed.Symbol].Invested)
{
Liquidate(removed.Symbol);
}
}
}
}
} Python: class TestAlgorithm(QCAlgorithm):
def initialize(self) -> None:
# Subscribe to the index option and filter to get only the ones expiring in 30-90 days
self.index_option = self.add_index_option("SPX", "SPXW")
self.index_option.set_filter(lambda u: u.include_weeklys().calls_only().expiration(30, 90))
def on_data(self, slice: Slice) -> None:
# Get option chain data for the canonical symbol
chain = slice.option_chains.get(self.index_option.symbol)
if not self.portfolio.invested and chain:
# Obtain the ATM call that expires furthest (90 days)
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]
# Allocate 10% Capital
self.set_holdings(atm_call.symbol, 0.1)
def on_securities_changed(self, changes):
for removed in changes.removed_securities:
# Liquidate the contracts that exit the universe (due to expiry)
if self.portfolio[removed.symbol].invested:
self.liquidate(removed.symbol) |
Awesome @LouisSzeto Thanks for the help. |
@baobach you may add this in the description as well :) |
Remove second example since it doesn't address #1901.
@LouisSzeto , I reopened it because the 2nd example is incorrect, and I removes it ( def on_securities_changed(self, changes):
for removed in changes.removed_securities:
# Liquidate the contracts that exit the universe (due to expiry)
if self.portfolio[removed.symbol].invested:
self.liquidate(removed.symbol) |
Examples
Example 1: Expand current 0DTE example 1 to include initialize and trade. Use the new Option universe filtering by greeks.
Example 2: Select small universe +30, +90 expiry. In on_security_changed event handler liquidate on removed from universe. Buy the next one 90d out. Goal to demonstrate symbol changed events + rolling contracts. Allocate 10% capital.
Remember
For the new examples in the docs:
<h3>Examples</h3>
<p>The following examples demonstrate some common practices for _________.</p>
<h4>Example _: ____________</h4>
for each Example.<h4>Other Examples</h4>
. The sentence under that heading should read<p>For more examples, see the following algorithms:</p>
The text was updated successfully, but these errors were encountered: