-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1887 from QuantConnect/refactor-equity-option-gre…
…eks-indicator Refactor example snippets of Equity Option Greeks Indicators
- Loading branch information
Showing
2 changed files
with
238 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,112 @@ | ||
<p>To create an <a href='/docs/v2/writing-algorithms/indicators/automatic-indicators'>automatic indicator</a> for <?=$name?>, call the <code class="csharp">QCAlgorithm.<?=$helperMethod?></code><code class="python">QCAlgorithm.<?=strtolower($helperMethod)?></code> method with the Option contract <code class="csharp">Symbol</code><code class="python">symbol</code> object(s).</p> | ||
|
||
<div class="section-example-container"> | ||
<pre class="csharp">private <?=$typeName?> _<?=strtolower($typeName)?>; | ||
<pre class="csharp">private Symbol _spy; | ||
private List<Symbol> _<?=strtolower($typeName)?>s = new(); | ||
|
||
public override void Initialize() | ||
{ | ||
var option = QuantConnect.Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Put, 505m, new DateTime(2014, 6, 27)); | ||
AddOptionContract(option); | ||
// Subscribe to the underlying | ||
_spy = AddEquity("SPY", dataNormalizationMode=DataNormalizationMode.Raw).Symbol; | ||
|
||
// Set up a scheduled event to select contract and create Greeks indicator daily before market open | ||
Schedule.On( | ||
DateRules.EveryDay(_spy), | ||
TimeRules.At(9, 0), | ||
UpdateContractsAndGreeks | ||
); | ||
} | ||
|
||
// Example of using the single-contract IV calculation: | ||
_<?=strtolower($typeName)?> = <?=$helperMethod?>(option); | ||
private void UpdateContractsAndGreeks() | ||
{ | ||
// Get all tradable option contracts | ||
var contractList = OptionChainProvider.GetOptionContractList(_spy, Time).ToList(); | ||
// You can do further filtering here | ||
|
||
// Iterate all expiries | ||
foreach (var expiry in contractList.Select(x => x.ID.Date).Distinct()) | ||
{ | ||
var contractsByExpiry = contractList.Where(x => x.ID.Date == expiry).ToList(); | ||
|
||
// Iterate all strike prices among the contracts of the same expiry | ||
foreach (var strike in contractsByExpiry.Select(x => x.ID.StrikePrice).Distinct()) | ||
{ | ||
var contractsByStrike = contractsByExpiry.Where(x => x.ID.StrikePrice == strike).ToList(); | ||
|
||
// Get the call and put respectively | ||
var call = contractsByStrike.SingleOrDefault(x => x.ID.OptionRight == OptionRight.Call); | ||
var put = contractsByStrike.SingleOrDefault(x => x.ID.OptionRight == OptionRight.Put); | ||
// Skip if either call or put not exist | ||
if (call == null || put == null) continue; | ||
|
||
// Create subscriptions to both contract | ||
call = AddOptionContract(call).Symbol; | ||
put = AddOptionContract(put).Symbol; | ||
|
||
// Create the automatic-updating <?=$typeName?> indicator | ||
var call<?=$typeName?> = <?=$helperMethod?>(call, put); | ||
var put<?=$typeName?> = <?=$helperMethod?>(put, call); | ||
// Add to list of indicator | ||
_<?=strtolower($typeName)?>s.Add(call<?=$typeName?>); | ||
_<?=strtolower($typeName)?>s.Add(put<?=$typeName?>); | ||
} | ||
} | ||
} | ||
|
||
// Example of using the using mirror-contract IV calculation: | ||
var mirrorOption = QuantConnect.Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Call, 505m, new DateTime(2014, 6, 27)); | ||
AddOptionContract(mirrorOption); | ||
_<?=strtolower($typeName)?> = <?=$helperMethod?>(option, mirrorOption); | ||
public override void OnData(Slice slice) | ||
{ | ||
// Access the <?=$typeName?> indicator of each contract | ||
foreach (var <?=strtolower($typeName)?> in _<?=strtolower($typeName)?>s) | ||
{ | ||
Log($"{<?=strtolower($typeName)?>.OptionSymbol}::{<?=strtolower($typeName)?>.Current.EndTime}::{<?=strtolower($typeName)?>.Current.Value}"); | ||
} | ||
}</pre> | ||
<pre class="python">def initialize(self): | ||
option = Symbol.create_option("AAPL", Market.USA, OptionStyle.AMERICAN, OptionRight.PUT, 505, datetime(2014, 6, 27)) | ||
self.add_option_contract(option) | ||
|
||
# Example of using the single-contract IV calculation: | ||
self._<?=strtolower($typeName)?> = self.<?=strtolower($helperMethod)?>(option) | ||
|
||
# Example of using the using mirror-contract IV calculation: | ||
mirror_option = Symbol.create_option("AAPL", Market.USA, OptionStyle.AMERICAN, OptionRight.CALL, 505, datetime(2014, 6, 27)) | ||
self.add_option_contract(mirror_option) | ||
self._<?=strtolower($typeName)?> = self.<?=strtolower($helperMethod)?>(option, mirror_option) | ||
</pre> | ||
<pre class="python">def initialize(self) -> None: | ||
# List to hold Greeks indicators | ||
self.<?=strtolower($typeName)?>s = [] | ||
|
||
# Subscribe to the underlying | ||
self.spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW).symbol | ||
|
||
# Set up a scheduled event to select contract and create Greeks indicator daily before market open | ||
self.schedule.on( | ||
self.date_rules.every_day(self.spy), | ||
self.time_rules.at(9, 0), | ||
self.update_contracts_and_greeks | ||
) | ||
|
||
def update_contracts_and_greeks(self) -> None: | ||
# Get all tradable option contracts | ||
contract_list = self.option_chain_provider.get_option_contract_list(self.spy, self.time) | ||
# You can do further filtering here | ||
|
||
# Iterate all expiries | ||
for expiry in set(x.id.date for x in contract_list): | ||
contract_by_expiry = [x for x in contract_list if x.id.date == expiry] | ||
|
||
# Iterate all strike prices among the contracts of the same expiry | ||
for strike in set(x.id.strike_price for x in contract_by_expiry): | ||
contract_by_strike = [x for x in contract_by_expiry if x.id.strike_price == strike] | ||
|
||
# Get the call and put respectively | ||
call = next(filter(lambda x: x.id.option_right == OptionRight.CALL, contract_by_strike)) | ||
put = next(filter(lambda x: x.id.option_right == OptionRight.PUT, contract_by_strike)) | ||
# Skip if either call or put not exist | ||
if not call or not put: | ||
continue | ||
|
||
# Create subscriptions to both contract | ||
call = self.add_option_contract(call).symbol | ||
put = self.add_option_contract(put).symbol | ||
|
||
# Create the automatic-updating <?=$typeName?> indicator | ||
call_<?=strtolower($typeName)?> = self.<?=strtolower($helperMethod)?>(call, put) | ||
put_<?=strtolower($typeName)?> = self.<?=strtolower($helperMethod)?>(put, call) | ||
# Add to list of indicator | ||
self.<?=strtolower($typeName)?>s.extend([call_<?=strtolower($typeName)?>, put_<?=strtolower($typeName)?>]) | ||
|
||
def on_data(self, slice: Slice) -> None: | ||
# Access the <?=$typeName?> indicator of each contract | ||
for <?=strtolower($typeName)?> in self.<?=strtolower($typeName)?>s: | ||
self.log(f"{<?=strtolower($typeName)?>.option_symbol}::{<?=strtolower($typeName)?>.current.end_time}::{<?=strtolower($typeName)?>.current.value}")</pre> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,149 @@ | ||
<p>To create a <a href='https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/manual-indicators'>manual indicator</a> for <?=$name?>, call the <code><?=$typeName?></code> constructor.</p> | ||
|
||
<div class="section-example-container"> | ||
<pre class="csharp">private <?=$typeName?> _<?=strtolower($typeName)?>; | ||
<pre class="csharp">private Symbol _spy; | ||
private DividendYieldProvider _dividendYieldProvider; | ||
private List<Symbol> _<?=strtolower($typeName)?>s = new(); | ||
// Define the option pricing model | ||
private readonly OptionPricingModelType _optionPricingModel = OptionPricingModelType.ForwardTree; | ||
|
||
public override void Initialize() | ||
{ | ||
var equity = AddEquity("AAPL").Symbol; | ||
var option = QuantConnect.Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Put, 505m, new DateTime(2014, 6, 27)); | ||
AddOptionContract(option); | ||
// Subscribe to the underlying | ||
_spy = AddEquity("SPY", dataNormalizationMode=DataNormalizationMode.Raw).Symbol; | ||
// Set up dividend yield provider for the underlying | ||
_dividendYieldProvider = new(_spy); | ||
|
||
// Set up a scheduled event to select contract and create Greeks indicator daily before market open | ||
Schedule.On( | ||
DateRules.EveryDay(_spy), | ||
TimeRules.At(9, 0), | ||
UpdateContractsAndGreeks | ||
); | ||
} | ||
|
||
var interestRateProvider = new InterestRateProvider(); | ||
var dividendYieldProvider = new DividendYieldProvider(equity); | ||
private void UpdateContractsAndGreeks() | ||
{ | ||
// Get all tradable option contracts | ||
var contractList = OptionChainProvider.GetOptionContractList(_spy, Time).ToList(); | ||
// You can do further filtering here | ||
|
||
// Iterate all expiries | ||
foreach (var expiry in contractList.Select(x => x.ID.Date).Distinct()) | ||
{ | ||
var contractsByExpiry = contractList.Where(x => x.ID.Date == expiry).ToList(); | ||
|
||
// Iterate all strike prices among the contracts of the same expiry | ||
foreach (var strike in contractsByExpiry.Select(x => x.ID.StrikePrice).Distinct()) | ||
{ | ||
var contractsByStrike = contractsByExpiry.Where(x => x.ID.StrikePrice == strike).ToList(); | ||
|
||
// Get the call and put respectively | ||
var call = contractsByStrike.SingleOrDefault(x => x.ID.OptionRight == OptionRight.Call); | ||
var put = contractsByStrike.SingleOrDefault(x => x.ID.OptionRight == OptionRight.Put); | ||
// Skip if either call or put not exist | ||
if (call == null || put == null) continue; | ||
|
||
// Example of using the single-contract IV calculation: | ||
_<?=strtolower($typeName)?> = new <?=$typeName?>(option, interestRateProvider, dividendYieldProvider); | ||
// Create subscriptions to both contract | ||
call = AddOptionContract(call).Symbol; | ||
put = AddOptionContract(put).Symbol; | ||
|
||
// Create the manual-updating <?=$typeName?> indicator | ||
var call<?=$typeName?> = new <?=$typeName?>(call, RiskFreeInterestRateModel, _dividendYieldProvider, put, _optionPricingModel); | ||
var put<?=$typeName?> = new <?=$typeName?>(put, RiskFreeInterestRateModel, _dividendYieldProvider, call, _optionPricingModel); | ||
// Add to list of indicator | ||
_<?=strtolower($typeName)?>s.Add(call<?=$typeName?>); | ||
_<?=strtolower($typeName)?>s.Add(put<?=$typeName?>); | ||
} | ||
} | ||
} | ||
|
||
public override void OnData(Slice slice) | ||
{ | ||
// Iterate indicators | ||
foreach (var <?=strtolower($typeName)?>Indicator in _<?=strtolower($typeName)?>s) | ||
{ | ||
var option = <?=strtolower($typeName)?>Indicator.OptionSymbol; | ||
var mirrorRight = option.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call; | ||
var mirror = QuantConnect.Symbol.CreateOption(option.Underlying.Value, Market.USA, OptionStyle.American, mirrorRight, option.ID.StrikePrice, option.ID.Date); | ||
|
||
// Example of using the using mirror-contract IV calculation: | ||
var mirrorOption = QuantConnect.Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Call, 505m, new DateTime(2014, 6, 27)); | ||
AddOptionContract(mirrorOption); | ||
_<?=strtolower($typeName)?> = new <?=$typeName?>(option, interestRateProvider, dividendYieldProvider, mirrorOption); | ||
// Check if price data available for both contracts and the underlying | ||
if (slice.QuoteBars.ContainsKey(option) && slice.QuoteBars.ContainsKey(mirror) && slice.Bars.ContainsKey(_spy)) | ||
{ | ||
// Update the indicator | ||
<?=strtolower($typeName)?>Indicator.Update(new IndicatorDataPoint(option, slice.QuoteBars[option].EndTime, slice.QuoteBars[option].Close)); | ||
<?=strtolower($typeName)?>Indicator.Update(new IndicatorDataPoint(mirror, slice.QuoteBars[mirror].EndTime, slice.QuoteBars[mirror].Close)); | ||
<?=strtolower($typeName)?>Indicator.Update(new IndicatorDataPoint(_spy, slice.Bars[_spy].EndTime, slice.Bars[_spy].Close)); | ||
|
||
// Get the current value | ||
var <?=strtolower($typeName)?> = <?=strtolower($typeName)?>Indicator.Current.Value; | ||
} | ||
} | ||
}</pre> | ||
<pre class="python">def initialize(self): | ||
equity = self.add_equity("AAPL").symbol | ||
option = Symbol.create_option("AAPL", Market.USA, OptionStyle.AMERICAN, OptionRight.PUT, 505, datetime(2014, 6, 27)) | ||
self.add_option_contract(option) | ||
|
||
interest_rate_provider = InterestRateProvider() | ||
dividend_yield_provider = DividendYieldProvider(equity) | ||
|
||
# Example of using the single-contract IV calculation: | ||
self._<?=strtolower($typeName)?> = <?=$typeName?>(option, interest_rate_provider, dividend_yield_provider) | ||
|
||
# Example of using the using mirror-contract IV calculation: | ||
mirror_option = Symbol.create_option("AAPL", Market.USA, OptionStyle.AMERICAN, OptionRight.CALL, 505, datetime(2014, 6, 27)) | ||
self.add_option_contract(mirror_option) | ||
self._<?=strtolower($typeName)?> = <?=$typeName?>(option, interest_rate_provider, dividend_yield_provider, mirror_option) | ||
</pre> | ||
<pre class="python">def initialize(self) -> None: | ||
# List to hold Greeks indicators | ||
self.<?=strtolower($typeName)?>s = [] | ||
|
||
# Subscribe to the underlying | ||
self.spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW).symbol | ||
# Set up dividend yield provider for the underlying | ||
self.dividend_yield_provider = DividendYieldProvider(self.spy) | ||
# Define the option pricing model | ||
self.option_pricing_model = OptionPricingModelType.FORWARD_TREE | ||
|
||
# Set up a scheduled event to select contract and create Greeks indicator daily before market open | ||
self.schedule.on( | ||
self.date_rules.every_day(self.spy), | ||
self.time_rules.at(9, 0), | ||
self.update_contracts_and_greeks | ||
) | ||
|
||
def update_contracts_and_greeks(self) -> None: | ||
# Get all tradable option contracts | ||
contract_list = self.option_chain_provider.get_option_contract_list(self.spy, self.time) | ||
# You can do further filtering here | ||
|
||
# Iterate all expiries | ||
for expiry in set(x.id.date for x in contract_list): | ||
contract_by_expiry = [x for x in contract_list if x.id.date == expiry] | ||
|
||
# Iterate all strike prices among the contracts of the same expiry | ||
for strike in set(x.id.strike_price for x in contract_by_expiry): | ||
contract_by_strike = [x for x in contract_by_expiry if x.id.strike_price == strike] | ||
|
||
# Get the call and put respectively | ||
call = next(filter(lambda x: x.id.option_right == OptionRight.CALL, contract_by_strike)) | ||
put = next(filter(lambda x: x.id.option_right == OptionRight.PUT, contract_by_strike)) | ||
# Skip if either call or put not exist | ||
if not call or not put: | ||
continue | ||
|
||
# Create subscriptions to both contract | ||
call = self.add_option_contract(call).symbol | ||
put = self.add_option_contract(put).symbol | ||
|
||
# Create the manual-updating <?=$typeName?> indicator | ||
call_<?=strtolower($typeName)?> = <?=$typeName?>(call, self.risk_free_interest_rate_model, self.dividend_yield_provider, put, self.option_pricing_model) | ||
put_<?=strtolower($typeName)?> = <?=$typeName?>(put, self.risk_free_interest_rate_model, self.dividend_yield_provider, call, self.option_pricing_model) | ||
# Add to list of indicator | ||
self.<?=strtolower($typeName)?>s.extend([call_<?=strtolower($typeName)?>, put_<?=strtolower($typeName)?>]) | ||
|
||
def on_data(self, slice: Slice) -> None: | ||
# Iterate indicators | ||
for <?=strtolower($typeName)?>_indicator in self.<?=strtolower($typeName)?>s: | ||
option = <?=strtolower($typeName)?>_indicator.option_symbol | ||
mirror_right = OptionRight.Call if option.id.option_right == OptionRight.PUT else OptionRight.PUT | ||
mirror = Symbol.create_option(option.underlying.value, Market.USA, OptionStyle.AMERICAN, mirror_right, option.id.strike_price, option.id.date) | ||
|
||
# Check if price data available for both contracts and the underlying | ||
if option in slice.quote_bars and mirror in slice.quote_bars and self.spy in slice.bars: | ||
# Update the indicator | ||
<?=strtolower($typeName)?>_indicator.update(IndicatorDataPoint(option, slice.quote_bars[option].end_time, slice.quote_bars[option].close))</pre> | ||
<?=strtolower($typeName)?>_indicator.update(IndicatorDataPoint(mirror, slice.quote_bars[mirror].end_time, slice.quote_bars[mirror].close)) | ||
<?=strtolower($typeName)?>_indicator.update(IndicatorDataPoint(self.spy, slice.bars[self.spy].end_time, slice.bars[self.spy].close)) | ||
|
||
# Get the current value | ||
<?=strtolower($typeName)?> = <?=strtolower($typeName)?>_indicator.current.value; | ||
</div> | ||
|
||
<p>For more information about the <code><?=$typeName?></code> constructor, see <a href="/docs/v2/writing-algorithms/indicators/supported-indicators/<?=$indicatorPage?>">Using <?=$helperMethod?> Indicator</a>.</p> |