Hello all -- First of all thank you for reading this post, and any feedback you provide will add value. I'm needing a little help with an algo I'm working on. It is a intraday SPY options trading strategy that's based on the EMAs for SPY itself and other factors. In my current write up, I'm trying to achieve the following:
- 26 EMA < 97 EMA for SPY, and price of SPY is within 0.05 of the 26EMA (and if the slope of the 15EMA is negative, which I've yet to figure out), buy nearest ATM put and expiration and set a trailing stop.
- I will be doing this for calls as well, but trying to get one side of the equation done first.
It looks like the algo is buying puts when the conditions are satisfied, but it's not getting the nearest expiration; and at some point, I'm getting an index filter error, I assume its due to my conditions for the optionschain, but unsure how to resolve it.
Also, I'm struggling a little with figuring out trailing stops for the options. I ended up setting a condition where it automatically liquidates when spy closes below the previous highest price, for profit; or if spy loses 20 cents below the 26EMA for some profit; or if spy closes above the 26EMA for a loss.
Any thoughts on how to set a trailign stop for options, and how to getrid of this index filter error is greatly appreciated.
Thank you
Derek Melchin
Hi Maurice,
The algorithm was not consistently selecting the contract with the nearest expiration because the sorting of contracts by expiry date needed to be reversed. This has been corrected in the algorithm attached below.
I was unable to reproduce the index error. However, this occurs when we try to access the first element of an empty list. To ensure this doesn't occur, we should check the length of a list after each time we filter it. For example, in the `BuyPut` method, we should add the following if-statement:
put = [x for x in filtered_contracts if x.ID.OptionRight == OptionRight.Put] if len(puts) == 0: return
This change has been added to the attached backtest in all the necessary locations.
In regards to the trailing stop loss orders for options, refer to our previous thread for an example algorithm.
Best,
Derek Melchin
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Maurice D
Hi Derek -- thank you for your response. I took a look at your response in the back test you attached and used it to make modifications to my algorithm. However, it still does not seem to be consistently selecting the soonest expiration; espeically since SPY contracts are Monday, Wednesday, and Friday. Also, the algorithm seems to be taking days off on its own and not trading. I assume this also has something to do with the way I implemented the options chain? Please take a look at the backtest attached and let me know your thoughts. Here are my questions:
1) what do I need to do to make sure it consistently selects the correct contract?
2) my buy creiteria currently sets to algo to enter calls if the slow > fast and when the underlying comes withing 0.03 of the fast. My ultimate goal is to add another condition that enables this entry only if the slope of the fast is positive (for calls). Any idea on how I can calculate the slope?
3) I have my fast and slow set as 30 and 100; technically, my fast and slows are 15 and 50. I assume since the resolution is a minute, the 30 and 100 equate to the 2 minute chart. Is this correct?
4) When this algorightm goes live, I'm getting an error that says: "The security does not have an accurate price as it has not yet received a bar of data. Before placing a trade (or using SetHoldings) warm up your algorithm with SetWarmup, or use slice." and it doesnt enter any contracts when live. Any ideas?
5) I want the algorithm to only work from 1000 to 1530 EST. Any ideas on how to set this condition?
Thank you ahead of time. I know this is a lot.
Derek Melchin
Hi Maurice,
This algorithm published above does not select the contract with the closest expiration because of the way it sorts the contracts.
(1) The following line sorts `otm_calls` by date and then by the distance the strike price is from the underlying price. Therefore, if we have a contract in `otm_calls` which has a strike equal to the underlying price but has the furthest expiry date, it will be at the front of the resulting list.
sorted(sorted(otm_calls, key = lambda x: x.ID.Date, reverse=False), key = lambda x: abs(self.underlyingPrice - x.ID.StrikePrice))
To fix this issue, we need to switch the order the sorting is performed to
sorted(sorted(otm_calls, key=lambda x: abs(self.underlyingPrice - x.ID.StrikePrice)), key=lambda x: x.ID.Date)
(2) I've adjusted the `OptionsFilter` method to eliminate duplicate code. To add to the entry conditions, we just need to add another condition to the lines that determine the `call_entry` and `put_entry`. To calculate the slope of the indicator values, we can utilize a RollingWindow. Refer to our documentation to learn how.
(3) A 30 period EMA with 1-minute candles is not always equal to a 15 period EMA with 2-minute candles. To setup 2-minute candles, we can consolidate our minute data into candles that span 2 minutes. Review our consolidated data documentation for an explanation of this process and a few examples.
(4) This error message surfaces because we are calling AddOptionContract and trying to place a MarketOrder during the same call to OnData. This causes issues because the algorithm hasn't received a bar of data for the option we are trying to buy. To fix this, we must ensure the data slice passed to OnData has the contract as a key before placing a trade.
self.contract_put = self.OptionsFilter(data, OptionRight.Put) if self.contract_put in data: self.MarketOrder(self.contract_put, +10)
(5) We can limit the algorithm to only run from 10:00 to 15:30 EST by placing the following guard at the top of OnData
if data.Time.hour < 10 or (data.Time.hour == 15 and data.Time.minute >= 30) or data.Time.hour > 15: return
Review the attached backtest for the full code file which addresses the issues above.
Best,
Derek Melchin
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Maurice D
Hi Derek -- thanks a lot for the review and modifications. Addresses the issues I was having. I was able to work in the rolling window and consolidator as well. Thank you.
-Maurice
Maurice D
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!