Add more assertions to new options filter api regression algorithms
This commit is contained in:
@@ -1,117 +0,0 @@
|
||||
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
### <summary>
|
||||
### Regression algorithm with new proposed option filter API using new options universe data (greeks, implied volatility, open interest, etc).
|
||||
### </summary>
|
||||
class BasicTemplateOptionsFilterAlgorithm(QCAlgorithm):
|
||||
underlying_ticker = "GOOG"
|
||||
|
||||
def initialize(self):
|
||||
self.set_start_date(2015, 12, 24)
|
||||
self.set_end_date(2015, 12, 24)
|
||||
self.set_cash(100000)
|
||||
|
||||
equity = self.add_equity(self.underlying_ticker)
|
||||
option = self.add_option(self.underlying_ticker)
|
||||
self.option_symbol = option.symbol
|
||||
|
||||
# set our strike/expiry filter for this option chain
|
||||
option.set_filter(lambda u: u.strikes(-2, +2).expiration(0, 180))
|
||||
|
||||
# Filter by a single greek:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.delta(0.64, 0.65))
|
||||
|
||||
# Filter by multiple greeks:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.delta(0.64, 0.65)
|
||||
.gamma(0.0008, 0.0010)
|
||||
.vega(7.5, 10.5)
|
||||
.theta(-1.10, -0.50)
|
||||
.rho(4, 10))
|
||||
|
||||
# Some syntax sugar:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.d(0.64, 0.65)
|
||||
.g(0.0008, 0.0010)
|
||||
.v(7.5, 10.5)
|
||||
.t(-1.10, -0.50)
|
||||
.r(4, 10))
|
||||
|
||||
# Filter by open interest and/or implied volatility:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.open_interest(100, 1000)
|
||||
.implied_volatility(0.10, 0.20))
|
||||
|
||||
# Some syntax sugar:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.oi(100, 1000)
|
||||
.iv(0.10, 0.20))
|
||||
|
||||
# Having delegate filters with the whole contract data.
|
||||
# We can reuse the OptionContract class for this. Might need some work on that side
|
||||
# (new constructors/factor methods, some abstraction to not rely on the option price mode, etc) but it's a good idea.
|
||||
|
||||
# EXAMPLES:
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.contracts(self.contracts_filter)) # def contracts_filter(self, contracts: list[OptionContract]) -> list[Symbol]:
|
||||
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.select(self.select_contract)) # def select_contract(self, contract: OptionContract) -> Symbol:
|
||||
|
||||
option.set_filter(lambda u: u
|
||||
.strikes(-2, +2)
|
||||
.expiration(0, 180)
|
||||
.where(self.where_contract)) # def where_contract(self, contract: OptionContract) -> bool:
|
||||
|
||||
def contracts_filter(self, contracts: list[OptionUniverse]) -> list[Symbol]:
|
||||
for contract in contracts:
|
||||
# Can access the contract data here:
|
||||
greeks = contract.greeks
|
||||
iv = contract.implied_volatility
|
||||
open_interest = contract.open_interest
|
||||
|
||||
yield contract.symbol
|
||||
|
||||
def select_contract(self, contract: OptionUniverse) -> Symbol:
|
||||
# Can access the contract data here:
|
||||
greeks = contract.greeks
|
||||
iv = contract.implied_volatility
|
||||
open_interest = contract.open_interest
|
||||
|
||||
return contract.symbol
|
||||
|
||||
def where_contract(self, contract: OptionUniverse) -> bool:
|
||||
# Can access the contract data here:
|
||||
greeks = contract.greeks
|
||||
iv = contract.implied_volatility
|
||||
open_interest = contract.open_interest
|
||||
|
||||
return True
|
||||
@@ -28,31 +28,47 @@ class OptionUniverseFilterGreeksRegressionAlgorithm(QCAlgorithm):
|
||||
option = self.add_option(underlying_ticker)
|
||||
self.option_symbol = option.symbol
|
||||
|
||||
self._min_delta = 0.5
|
||||
self._max_delta = 1.5
|
||||
self._min_gamma = 0.0001
|
||||
self._max_gamma = 0.0006
|
||||
self._min_vega = 0.01
|
||||
self._max_vega = 1.5
|
||||
self._min_theta = -2.0
|
||||
self._max_theta = -0.5
|
||||
self._min_rho = 0.5
|
||||
self._max_rho = 3.0
|
||||
self._min_iv = 1.0
|
||||
self._max_iv = 3.0
|
||||
self._min_open_interest = 100
|
||||
self._max_open_interest = 500
|
||||
|
||||
self.set_option_filter(option)
|
||||
|
||||
self.option_chain_received = False
|
||||
|
||||
def set_option_filter(self, security: Option) -> None:
|
||||
|
||||
# Contracts can be filtered by greeks, implied volatility, open interest:
|
||||
security.set_filter(lambda u: u
|
||||
.delta(0.5, 1.5)
|
||||
.gamma(0.0001, 0.0006)
|
||||
.vega(0.01, 1.5)
|
||||
.theta(-2.0, -0.5)
|
||||
.rho(0.5, 3.0)
|
||||
.implied_volatility(1.0, 3.0)
|
||||
.open_interest(100, 500))
|
||||
.delta(self._min_delta, self._max_delta)
|
||||
.gamma(self._min_gamma, self._max_gamma)
|
||||
.vega(self._min_vega, self._max_vega)
|
||||
.theta(self._min_theta, self._max_theta)
|
||||
.rho(self._min_rho, self._max_rho)
|
||||
.implied_volatility(self._min_iv, self._max_iv)
|
||||
.open_interest(self._min_open_interest, self._max_open_interest))
|
||||
|
||||
# Note: there are also shortcuts for these filter methods:
|
||||
'''
|
||||
security.set_filter(lambda u: u
|
||||
.d(0.5, 1.5)
|
||||
.g(0.0001, 0.0006)
|
||||
.v(0.01, 1.5)
|
||||
.t(-2.0, -0.5)
|
||||
.r(0.5, 3.0)
|
||||
.iv(1.0, 3.0)
|
||||
.oi(100, 500))
|
||||
.d(self._min_delta, self._max_delta)
|
||||
.g(self._min_gamma, self._max_gamma)
|
||||
.v(self._min_vega, self._max_vega)
|
||||
.t(self._min_theta, self._max_theta)
|
||||
.r(self._min_rho, self._max_rho)
|
||||
.iv(self._min_iv, self._max_iv)
|
||||
.oi(self._min_open_interest, self._max_open_interest))
|
||||
'''
|
||||
|
||||
def on_data(self, slice: Slice) -> None:
|
||||
@@ -60,6 +76,25 @@ class OptionUniverseFilterGreeksRegressionAlgorithm(QCAlgorithm):
|
||||
if chain and len(chain.contracts) > 0:
|
||||
self.option_chain_received = True
|
||||
|
||||
for contract in chain:
|
||||
if contract.Greeks.Delta < self._min_delta or contract.Greeks.Delta > self._max_delta:
|
||||
raise RegressionTestException(f"Delta {contract.Greeks.Delta} is not within {self._min_delta} and {self._max_delta}")
|
||||
|
||||
if contract.Greeks.Gamma < self._min_gamma or contract.Greeks.Gamma > self._max_gamma:
|
||||
raise RegressionTestException(f"Gamma {contract.Greeks.Gamma} is not within {self._min_gamma} and {self._max_gamma}")
|
||||
|
||||
if contract.Greeks.Vega < self._min_vega or contract.Greeks.Vega > self._max_vega:
|
||||
raise RegressionTestException(f"Vega {contract.Greeks.Vega} is not within {self._min_vega} and {self._max_vega}")
|
||||
|
||||
if contract.Greeks.Theta < self._min_theta or contract.Greeks.Theta > self._max_theta:
|
||||
raise RegressionTestException(f"Theta {contract.Greeks.Theta} is not within {self._min_theta} and {self._max_theta}")
|
||||
|
||||
if contract.Greeks.Rho < self._min_rho or contract.Greeks.Rho > self._max_rho:
|
||||
raise RegressionTestException(f"Rho {contract.Greeks.Rho} is not within {self._min_rho} and {self._max_rho}")
|
||||
|
||||
if contract.ImpliedVolatility < self._min_iv or contract.ImpliedVolatility > self._max_iv:
|
||||
raise RegressionTestException(f"Implied volatility {contract.ImpliedVolatility} is not within {self._min_iv} and {self._max_iv}")
|
||||
|
||||
def on_end_of_algorithm(self) -> None:
|
||||
if not self.option_chain_received:
|
||||
raise RegressionTestException("Option chain was not received.")
|
||||
|
||||
@@ -23,10 +23,10 @@ class OptionUniverseFilterGreeksShortcutsRegressionAlgorithm(OptionUniverseFilte
|
||||
def set_option_filter(self, security: Option) -> None:
|
||||
# Contracts can be filtered by greeks, implied volatility, open interest:
|
||||
security.set_filter(lambda u: u
|
||||
.d(0.5, 1.5)
|
||||
.g(0.0001, 0.0006)
|
||||
.v(0.01, 1.5)
|
||||
.t(-2.0, -0.5)
|
||||
.r(0.5, 3.0)
|
||||
.iv(1.0, 3.0)
|
||||
.oi(100, 500))
|
||||
.d(self._min_delta, self._max_delta)
|
||||
.g(self._min_gamma, self._max_gamma)
|
||||
.v(self._min_vega, self._max_vega)
|
||||
.t(self._min_theta, self._max_theta)
|
||||
.r(self._min_rho, self._max_rho)
|
||||
.iv(self._min_iv, self._max_iv)
|
||||
.oi(self._min_open_interest, self._max_open_interest))
|
||||
|
||||
@@ -27,13 +27,13 @@ class OptionUniverseFilterOptionsDataRegressionAlgorithm(OptionUniverseFilterGre
|
||||
|
||||
'''
|
||||
security.set_filter(lambda u: u
|
||||
.delta(0.5, 1.5)
|
||||
.gamma(0.0001, 0.0006)
|
||||
.vega(0.01, 1.5)
|
||||
.theta(-2.0, -0.5)
|
||||
.rho(0.5, 3.0)
|
||||
.implied_volatility(1.0, 3.0)
|
||||
.open_interest(100, 500))
|
||||
.delta(self._min_delta, self._max_delta)
|
||||
.gamma(self._min_gamma, self._max_gamma)
|
||||
.vega(self._min_vega, self._max_vega)
|
||||
.theta(self._min_theta, self._max_theta)
|
||||
.rho(self._min_rho, self._max_rho)
|
||||
.implied_volatility(self._min_iv, self._max_iv)
|
||||
.open_interest(self._min_open_interest, self._max_open_interest))
|
||||
'''
|
||||
|
||||
security.set_filter(
|
||||
@@ -44,11 +44,11 @@ class OptionUniverseFilterOptionsDataRegressionAlgorithm(OptionUniverseFilterGre
|
||||
contract for contract in contracts
|
||||
# Can access the contract data here and do some filtering based on it is needed.
|
||||
# More complex math can be done here for filtering, but will be simple here for demonstration sake:
|
||||
if (contract.Greeks.Delta > 0.5 and contract.Greeks.Delta < 1.5 and
|
||||
contract.Greeks.Gamma > 0.0001 and contract.Greeks.Gamma < 0.0006 and
|
||||
contract.Greeks.Vega > 0.01 and contract.Greeks.Vega < 1.5 and
|
||||
contract.Greeks.Theta > -2.0 and contract.Greeks.Theta < -0.5 and
|
||||
contract.Greeks.Rho > 0.5 and contract.Greeks.Rho < 3.0 and
|
||||
contract.ImpliedVolatility > 1.0 and contract.ImpliedVolatility < 3.0 and
|
||||
contract.OpenInterest > 100 and contract.OpenInterest < 500)
|
||||
if (contract.Greeks.Delta > self._min_delta and contract.Greeks.Delta < self._max_delta and
|
||||
contract.Greeks.Gamma > self._min_gamma and contract.Greeks.Gamma < self._max_gamma and
|
||||
contract.Greeks.Vega > self._min_vega and contract.Greeks.Vega < self._max_vega and
|
||||
contract.Greeks.Theta > self._min_theta and contract.Greeks.Theta < self._max_theta and
|
||||
contract.Greeks.Rho > self._min_rho and contract.Greeks.Rho < self._max_rho and
|
||||
contract.ImpliedVolatility > self._min_iv and contract.ImpliedVolatility < self._max_iv and
|
||||
contract.OpenInterest > self._min_open_interest and contract.OpenInterest < self._max_open_interest)
|
||||
]))
|
||||
|
||||
Reference in New Issue
Block a user