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

Option Strategy Filter Universe #8088

Merged
merged 17 commits into from
Jul 1, 2024
Merged

Option Strategy Filter Universe #8088

merged 17 commits into from
Jul 1, 2024

Conversation

LouisSzeto
Copy link
Collaborator

Description

Add helper method to filter option universe by shortlisting a particular type of option strategies
e.g. option.SetFilter(u => u.IncludeWeeklys().Strike(-2, 2).Expiration(0, 90).IronCondor(30, 5, 10) will return 4 contracts that best fit the criteria given and be able to form an Iron Condor.

Related Issue

NA

Motivation and Context

For users that only wish to obtain certain contracts for forming an option strategy, it can reduce the number of option contract data subscribed to speed up the algorithm and avoid further filtering manually.
e.g. A single-day Iron Condor algorithm yielded a near 50% speed improvement:

  • with .IronCondor(30, 5, 10) filter
    image
  • without helper filter
    image

Requires Documentation Change

  • Add table in option universe filter page
  • Add h3 section for each option strategy page

How Has This Been Tested?

  • unit tests
  • regression tests

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>-<description> or feature-<issue#>-<description>

Copy link
Member

@Martin-Molinero Martin-Molinero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Leaving some thoughts and requests

// Select the set strike
var strike = AllSymbols.OrderBy(x => Math.Abs(Underlying.Price - x.ID.StrikePrice + strikeFromAtm))
.First().ID.StrikePrice;
var contracts = AllSymbols.Where(x => x.ID.StrikePrice == strike && x.ID.OptionRight == right);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!
Couple of thoughts:

  • Believe it's a bit sad & fragile having to duplicate the knowledge of each strategy again here, we could have a core implementation which could take a OptionStrategyDefinition instance for example and generically handle it there, each of these sugar names could just pass their option strategy definition to the core one and boom, we can simplify many lines and potential issues due to the duplication
  • The implementations seem a bit inconsistent on when using AllSymbols &/or the helper methods Where/Contracts/etc the helper methods are overriding AllSymbols & calling to List (sad to do it multiple times etc) -> I think we should avoid them and just use AllSymbols but at the end of the method call ToList and override it
  • Just double checking, I see ur using Abs for date/strike input operations which is strange given the input could be +/- , seems if used in OrderBy it would treat +/- result in the same way which doesn't seem right?

Copy link
Collaborator Author

@LouisSzeto LouisSzeto Jun 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double checking, I see ur using Abs for date/strike input operations which is strange given the input could be +/- , seems if used in OrderBy it would treat +/- result in the same way which doesn't seem right?

Yah that was intentional. We look for the best match but not a conditional best match

Common/Securities/Option/OptionFilterUniverse.cs Outdated Show resolved Hide resolved
{
public override void Initialize()
{
_func = u => u.IncludeWeeklys().Strikes(-10, +10).Expiration(0, 180).BoxSpread(30, 5);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't Expiration filter overlapping with the daysTillExpiry in the option strategy? For example in this example if Expiration was (30, 180) 🤔
Makes me think that daysTillExpiry would only be used if Expiration filter isn't used? which could mean we can push it to the end of the option strategy as an optional probably defaulting to null, maybe if Expiration wasn't use use 30 instead as default

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is intentional: Expiration is a strict rule, but daysTillExpiry is looking for the best match only🤔 I don't think they are mutaully exclusive.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expiration is a strict rule, but daysTillExpiry is looking for the best match only🤔

Sounds like a bug if user provides 30 daysTIllExpiry and it can use something bellow that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.Strikes(-10, +10).Expiration(0, 180)

Let's remove this from the examples

Sounds like a bug if user provides 30 daysTIllExpiry and it can use something bellow that? nevermind 👍

@Martin-Molinero
Copy link
Member

Please rebase from master, the regression test interface was changed & a unit test CI bug was shipped

Comment on lines 256 to 260
var expiry = AllSymbols.OrderBy(x => Math.Abs((x.ID.Date - _lastExchangeDate.AddDays(daysTillExpiry)).Days))
.First().ID.Date;
var contracts = AllSymbols.Where(x => x.ID.Date == expiry && x.ID.OptionRight == right);
// Select strike price
var selected = contracts.OrderBy(x => Math.Abs(x.ID.StrikePrice - Underlying.Price - strikeFromAtm)).First();
Copy link
Member

@Martin-Molinero Martin-Molinero Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the expiration filter here is behaving as expected, take the follow example

DaysTillExpiry 4
Today 8

Contract 1 expiration date 9
Contract 2 expiration date 15
Contract 3 expiration date 20

9 - (8 + 4) =>  Abs(-3) ? -> HERE
15 - (8 + 4) => Abs(3) -> HERE
20 - (8 + 4) => Abs(8)

We should have 1 centralized helper method location where we handle these daysTillExpiry/strikeFromAtm and reuse them in the whole file


I'd suggest rename daysTillExpiry to minDaysTillExpiry and could directly use the Expiration(minDaysTillExpiry, max)?

@Martin-Molinero Martin-Molinero merged commit 409f93a into QuantConnect:master Jul 1, 2024
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants