- ago
@Cone
In the sample code you provided in here you shared the technique of using a Dictionary for option bar history to avoid redundant historical data requests from IB for the same symbol.

CODE:
Dictionary<string, BarHistory> _obh = new Dictionary<string, BarHistory>();


CODE:
if (_obh.ContainsKey(contractSymbol)) _obars = _obh[contractSymbol]; else { _obars = GetHistory(bars, contractSymbol); _obh[contractSymbol] = _obars; }

If the key is found, the history will be missing the current bar. Does WL automatically update _obars history to the current bar before processing?

0
170
11 Replies

Reply

Bookmark

Sort
Cone8
 ( 27.64% )
- ago
#1
The Dictionary is local, so it won't have any members when the Strategy starts executing for that symbol. In that case, the logic calls GetHistory() which updates the option BarHistory to the latest bar for the scale requested and then it's added to the Dictionary if needed again.
0
- ago
#2
I think I may have assumed this works in a way that it doesn't. From your response I gather:
1. There is unique dictionary instance for each symbol
2. The lifetime of the dictionary is the current bar, so there would need to be another fresh request for history on the next bar
3. As a result, this construct only saves data requests if another method on the same bar needs the same history for the same symbol
4. You would advise against making the dictionary a static variable (for use on additional bars) because the bar history would not be up-to-date for future bar execution


0
Cone8
 ( 27.64% )
- ago
#3
1. Yes, all local (private/internal) variables are per symbol.
2. No. Just like indicators that are created and assigned to a private variable, they "live" for the entire run.
3. N/A
4. Right. This wouldn't be the right use case for a static object.
0
- ago
#4
QUOTE:
2. No. Just like indicators that are created and assigned to a private variable, they "live" for the entire run.

I had just confirmed this with a test before I saw your response. Yes, thank you for confirming. Then it does save a lot of data requests over the entire run. I realize now this is since the Dictionary is a private (myStrategy) variable at the class level, its lifetime extends over multiple execution runs for the same backtest. Makes sense to me now.

But that brings me back to one of my original questions. I am still unclear about the currency of the history that's fetched from the dictionary. E.g. in my custom log data
QUOTE:

obars *not* found 12/1/2023 10:30:00 AM
obars found 12/4/2023 4:00:00 PM

Wouldn't the obars found on 12/4 (which come from the Dictionary) be out-of-date by 3 days (and 36 bars) and therefore unusable? What am I missing here? Do those bars get auto updated by WL before processing Execution method?

Addition: The backtest did not request obars for this symbol between 12/1 and 12/4, so the code did not make daily or bar-by-bar updates of the dictionary symbol bars value.
0
Cone8
 ( 27.64% )
- ago
#5
The Dictionary will have the BarHistory for each option symbol that you request with GetHistory() - if the data is returned. There's nothing else to it.

Instead of showing "obars" show the actual oSymbol. My guess is that 12/1 obars is a different symbol than the obars for 12/4.
0
- ago
#6
QUOTE:
1/26/2024 12:16:04:974 AMD !AMD240119C115 obars *not* found 12/1/2023 10:30:00 AM
1/26/2024 12:16:06:548 AMD !AMD240119C115 obars found 12/4/2023 1:00:00 PM
1/26/2024 12:16:06:631 AMD !AMD240119C115 obars found 12/4/2023 1:30:00 PM
1/26/2024 12:16:06:106 AMD !AMD240119C115 obars found 12/4/2023 10:30:00 AM
1/26/2024 12:16:06:188 AMD !AMD240119C115 obars found 12/4/2023 11:00:00 AM
1/26/2024 12:16:06:268 AMD !AMD240119C115 obars found 12/4/2023 11:30:00 AM
1/26/2024 12:16:06:382 AMD !AMD240119C115 obars found 12/4/2023 12:00:00 PM
1/26/2024 12:16:06:471 AMD !AMD240119C115 obars found 12/4/2023 12:30:00 PM
1/26/2024 12:16:06:718 AMD !AMD240119C115 obars found 12/4/2023 2:00:00 PM
1/26/2024 12:16:06:785 AMD !AMD240119C115 obars found 12/4/2023 2:30:00 PM
1/26/2024 12:16:06:863 AMD !AMD240119C115 obars found 12/4/2023 3:00:00 PM
1/26/2024 12:16:06:929 AMD !AMD240119C115 obars found 12/4/2023 3:30:00 PM
1/26/2024 12:16:07:004 AMD !AMD240119C115 obars found 12/4/2023 4:00:00 PM
1/26/2024 12:16:07:674 AMD !AMD240119C115 obars found 12/5/2023 1:00:00 PM
1/26/2024 12:16:07:748 AMD !AMD240119C115 obars found 12/5/2023 1:30:00 PM
1/26/2024 12:16:07:079 AMD !AMD240119C115 obars found 12/5/2023 10:00:00 AM
1/26/2024 12:16:07:166 AMD !AMD240119C115 obars found 12/5/2023 10:30:00 AM
1/26/2024 12:16:07:244 AMD !AMD240119C115 obars found 12/5/2023 11:00:00 AM
1/26/2024 12:16:07:342 AMD !AMD240119C115 obars found 12/5/2023 11:30:00 AM
1/26/2024 12:16:07:472 AMD !AMD240119C115 obars found 12/5/2023 12:00:00 PM
1/26/2024 12:16:07:569 AMD !AMD240119C115 obars found 12/5/2023 12:30:00 PM
1/26/2024 12:16:07:819 AMD !AMD240119C115 obars found 12/5/2023 2:00:00 PM
1/26/2024 12:16:07:907 AMD !AMD240119C115 obars found 12/5/2023 2:30:00 PM
1/26/2024 12:16:08:000 AMD !AMD240119C115 obars found 12/5/2023 3:00:00 PM
1/26/2024 12:16:08:086 AMD !AMD240119C115 obars found 12/5/2023 3:30:00 PM
1/26/2024 12:16:08:174 AMD !AMD240119C115 obars found 12/5/2023 4:00:00 PM


Is this what you expected?
0
Cone8
 ( 27.64% )
- ago
#7
I can only guess what to expect because I don't have your code.

Based on this result, I'd have to guess that the first line is added to the debug log before you've requested the history, or before adding it to the dictionary, or both.
0
- ago
#8
QUOTE:
Based on this result, I'd have to guess that the first line is added to the debug log before you've requested the history,
No, it's added when the symbol key value is not found in the Dictionary.
QUOTE:
or before adding it to the dictionary
Yes.

Is the purpose of the dictionary to reduce unnecessary data requests, or to improve backtest performance, or both?

I don' t understand how the following code snippet works. Here's how I'm reading the code:
_obh[contractSymbol] only gets instantiated when _obh.ContainsKey(contractSymbol) is false. That means that as Execution proceeds to the following bars, bar data fetched again from the dictionary upon key match would be out-of-date.

I don't understand how the bar history data from the dictionary gets updated to the current bar. Does WL fetch it from file storage because as it regularly updates all symbols? Does the dictionary value get updated passively in background? There's definitely something I'm missing here.


CODE:
Position pos = FindOpenPositionAllSymbols(123); if (pos == null) { if (_sma.CrossesOver(_sma2, idx)) // || idx == bars.Count - 1) { // select the next highest $5 strike double strike = Math.Ceiling(bars.Close[idx] / _increment) * _increment; string contractSymbol = IBHistorical.Instance.GetOptionsSymbol(bars, OptionType.Call, strike, bars.DateTimes[idx], 14); if (_obh.ContainsKey(contractSymbol)) _obars = _obh[contractSymbol]; else { _obars = GetHistory(bars, contractSymbol); _obh[contractSymbol] = _obars; } if (_obars == null) { WriteToDebugLog(contractSymbol + " was null on " + bars.DateTimes[idx].ToShortDateTimeString()); return; } Transaction tn = PlaceTrade(_obars, TransactionType.Buy, OrderType.Market, 0, 123); tn.Quantity = _contractQty; } }
0
- ago
#9
I think I understand now. My hypothetical may be pertinent to strategies running in the SM (and SC?). However, for a standard backtest running in the SW, when the key-value is created it will have the entire bar history for up to the date of the run. Therefore, all bars necessary to complete the backtest are available in the dictionary entry and they don't require updating. Using a dictionary structure means you only have to fetch the bar history data for a specific symbol once from a data provider.

I suspect this approach is intended more for backtesting than live trading. With live trading in the SM, assuming the WL application is not restarted, the lifetime of the dictionary spans across future bars, indefinitely. The dictionary will only hold the bar history available at the time it was created, and since it will not be updated, there is a risk that the dictionary data would be unusable.
0
Cone8
 ( 27.64% )
- ago
#10
QUOTE:
I suspect this approach intended more for backtesting than live trading.
There's no difference.

QUOTE:
With live trading in the SM, assuming the WL application is not restarted, the lifetime of the dictionary spans across future bars, indefinitely.
??? Go back to Post #1, Post #3, and Post #5.
A "run" is executing the strategy once for a symbol. Each time it runs (for a symbol) the idea is to GetHistory once for each option contract required. You do it once for every run because there could be a new bar (or bars) added.
0
- ago
#11
That makes sense. Somehow, I got it into my head that the SM was only doing an execute loop on each new bar of live data. But that wouldn't make sense, as you point out, because new data could cause a new signal.

I think I was getting thrown off by comparing intraday data to daily data, but there really is no difference. A new bar is a new bar. And each bar gets a new run. It helps to think of it as a "run". In the SW, each run happens once. In the SM / SC, it happens each time there is a new bar of data depending on the data frequency.

Thanks for helping me get this straight.
1

Reply

Bookmark

Sort