- ago
This question is about IB. Is it possible to day trade options based on the intraday indicators crossovers?

I am looking for something like the moving average crossover up/down of underlying initiates orders to buy or sell call/put option that is two-strike OTM with expiry on coming up to 3-10 DTE Friday.
0
1,131
17 Replies

Reply

Bookmark

Sort
Cone8
 ( 28.25% )
- ago
#1
I'm working on something for you. There's no problem initiating orders, but I'd like to see it work in backtesting too, because that's just the way I roll :)

To that end, here's the issue. Currently, if you request an options historical chart, you get something like below, and this is the current contract, pretty much ATM for TTD. The red rectangle is all of the trading in this contract yesterday - there's not much, and this is typical for option chart trade data.



The problem with backtesting is that this chart would be synchronized to the regular price history, and the result would be option trade fills at "old" prices. Unrealistic.

There are other options for option data at IB. Here's one of them, which is the Bid/Ask MidPoint. Although there's no volume here, this obviously would be a lot better data to work with when backtesting.



The best idea I can think of is to combine these data - grabbing the volume from the Trades request and insert it in the Bid/Ask MidPoint chart. Stay tuned!
2
Glitch8
 ( 12.08% )
- ago
#2
Looks good! What we need though in the WL framework is a new Strategy method:

- GetOptionChain(string symbol, DateTime dt, OptionType ot)

This will give a list of symbols with possible metadata for options that are current for the specified symbol and date.

OptionType would be a new enum (Flags) OptionType.Put, OptionType.Call or OptionType.All.

A Strategy could then get a signal on the underlying, call GetOptionChain and pick an appropriate option, and "place" the trade on the option BarHistory result.

2
- ago
#3
Thanks Cone and Glitch. I don't see anyway to pull options chain for a symbol in the application. How do you trade options in WL? Is there any tutorial?
0
Glitch8
 ( 12.08% )
- ago
#4
We don't have any way currently. It's something still on the drawing board. Currently the only way to trade an option is to explicitly use the option symbol specific to the connected broker.
0
Cone8
 ( 28.25% )
- ago
#5
I'll whip up an example for you later this week. See Help > Extensions > Interactive Brokers for the symbol format to use, and make sure to use an intraday chart. IB doesn't return Daily bars for options.
0
- ago
#6
Is it also possible to PlaceOrder on the options symbol I construct when the bars object is of the underlying. So I am calculating my entries/exits and strike & expiration of the options contract based on the underlying but when I do PlaceTrade I can pass in my constructed options symbol?
2
Cone8
 ( 28.25% )
- ago
#7
QUOTE:
I do PlaceTrade I can pass in my constructed options symbol?
Not the symbol, but the BarHistory.

You might need to wait for IB Provider Build 7 to get correct results, for a few reasons.
1. The IB Provider wasn't assigning SymbolInfo. In Build 7, this is going to be improved greatly and you shouldn't even have to enter SymbolInfo for Futures, Options, etc.
2. Since option trading is usually illiquid, backtesting with Trades won't give you the right price at any given time. IB Build 7 will have a Preference to return the Bid/Ask Midpoint data for option contracts instead of getting actually trade history to give you continuous pricing throughout the day. You can decide which to use.
3. The first time you run this script, it could take a good while to finish because it needs to download all the option histories being traded. Be very patient with the first run. Backtest 1 symbol at a time.

Here's the example.

1. IB only returns intraday options data. I recommend 5 minute bars.
2. Since this script will look for the next expiry to trade, set the Date Range to start after the last expiry, 5/21/2022.
3. The number of contracts to trade is hard-coded to 5. You can change that in the _contractQty assignment.
4. The code has a IBOptionSymbol routine. Later we'll improve on this and finding precise contracts using OptionChains... I estimate it's coming in WL8 Build 9 11?

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Collections.Generic; using System.Globalization; namespace WealthScript2 { public class IntradaOptionDemo : UserStrategyBase {       public IntradaOptionDemo()       {       } public override void Initialize(BarHistory bars) {          _sma = SMA.Series(bars.Close, 5);          _sma2 = SMA.Series(bars.Close, 13);          PlotIndicatorLine(_sma, WLColor.Green);          PlotIndicatorLine(_sma2, WLColor.Red); }       string IBOptionSymbol(BarHistory bh, DateTime expiry, string right, double strike)       {          int imonth = expiry.Month - 1;          right = right.ToUpper().StartsWith("P") ? "P" : "C";          string yr = expiry.Year.ToString().Substring(2);          return string.Format("{0}{1}{2}{3}", bh.Symbol, expiry.ToString("yyMMdd"), right, strike.ToString(CultureInfo.InvariantCulture));       }       double ATMStrike(double price, double step = 5)       {          return Math.Floor(price / step) * step;       }        public override void Execute(BarHistory bars, int idx) { if (OpenPositionsAllSymbols.Count == 0) {             if (_sma.CrossesOver(_sma2, idx))             {                double strike = ATMStrike(bars.Close[idx]);                strike += 5;                string contractSymbol = IBOptionSymbol(bars, bars.NextOptionExpiryDate(idx), "Call", strike);                _obars = GetHistory(bars, contractSymbol, "ib_Options");                if (_obars == null)                {                   WriteToDebugLog(contractSymbol + " was null on " + bars.DateTimes[idx].ToShortDateTimeString());                   return;                }                                if (!_obh.ContainsKey(contractSymbol))                   _obh[contractSymbol] = _obars;                Transaction tn = PlaceTrade(_obars, TransactionType.Buy, OrderType.Market, 0, 11);                tn.Quantity = _contractQty;             } } else {                if (_sma.CrossesUnder(_sma2, idx))             {                PlaceTrade(_obars, TransactionType.Sell, OrderType.Market, 0, 11);             }     } } public override void BacktestComplete() {          foreach (BarHistory bh in _obh.Values)          {             PlotBarHistory(bh, bh.Symbol);                      }          }       //declare private variables below       int _contractQty = 5;       BarHistory _obars;       SMA _sma;       SMA _sma2;       Dictionary<string, BarHistory> _obh = new Dictionary<string, BarHistory>();       } }
2
- ago
#8
Thanks, Cone.

This is really helpful. I am assuming this strategy has to be run on the underlying symbol.
I understand backtesting will not give correct performance results but will it give results as trades are being executed on the underlying?
0
Cone8
 ( 28.25% )
- ago
#9
QUOTE:
assuming this strategy has to be run on the underlying symbol.
This strategy, yes, but there's no reason that it has to run on the underlying. The strategy just needs to identify the contract, any contract.

QUOTE:
I understand backtesting will not give correct performance results but will it give results as trades are being executed on the underlying?
First, this strategy is not trading the underlying. It's trading the option contract. You'll need IB Build 7 to get "correct" results for the reasons cited above. (Although you could probably enter the SymbolInfo manually using wildcards, but still you'll only have the illiquid contract trades to work with for data. Bid/Ask Midpoint is much better.)
0
- ago
#10
QUOTE:
First, this strategy is not trading the underlying. It's trading the options contract. You'll need IB Build 7 to get "correct" results for the reasons cited above. (Although you could probably enter the SymbolInfo manually using wildcards, still you'll only have the illiquid contract trades to work with for data. Bid/Ask Midpoint is much better.)


Yes, that's correct but is there any way to validate trade triggers through backtesting?
0
vk8
 ( 57.24% )
- ago
#11
If I understand you correctly you try to test the strategy on option data, right?
We have discussed it many times in the team and so far the problem is getting reliable data. Testing on highly liquid equities needs to consider data issues, doing the same on option even more.
0
Cone8
 ( 28.25% )
- ago
#12
QUOTE:
Yes, that's correct but is there any way to validate trade triggers through backtesting?
Explain what you mean by "validate".

It's all about data. I already discussed what's available for options data and that we're going to provide an IB preference to get the Bid/Ask Midpoint throughout the entire day.

Aside:
fwiw, I set up a script to request the MidPoint histories for all June contracts divisible by 5 in the trading range for the last 5 month for the Nasdaq 100 symbols. It's been working on that run for 9 hours now and it's only up to MELI.

Since we're looking ahead also at option chains, I noticed (last Friday) there were more than 28,000 option contracts just for AMZN!
0
- ago
#13
@Cone, so just to confirm, this would not be possible with TDA since it does not return historical bars on options. My goal was to use either Tradier or IBKR to get data but then send my orders to TDA.
0
Cone8
 ( 28.25% )
- ago
#14
Right. TDA doesn't return option historical bars, and from what I understand, Tradier does not support intraday historical bars (daily bars only) - not even for stocks. IB and IQFeed have intraday data for option contracts. Having the data (even if fictitious) you can trade the contract, one way or another.
0
- ago
#15
Thanks for the answer Cone but not sure I am following what you mean when you say even if you have fictitious data.

Ideally I would like to send my options orders to TDA or Tradier but if I construct my options symbols for any of these two brokers (both which use different formats) then request bars for these symbols, then I am assuming it would return null or no data.

Thinking out loud but is there a reason why placeorder method is so tightly coupled with the bars data itself, would it not be more beneficial to simply pass in a symbol to placeorder?

Or would it even be possible to generate my own BarHistory object and set the symbol myself and pass it into placetrade?

Thank you for the support
0
Glitch8
 ( 12.08% )
- ago
#16
The PlaceOrder call requires other information like pricing, market, etc which is why it takes a BarHistory and not just a symbol.
0
- ago
#17
Is there anything in the pipeline or a feature request I can vote on for options trading with Tradier & TDA, I understand that they don't return historical bars but is there a way to get around that?
0

Reply

Bookmark

Sort