Hi
Thanks in advanced. I am still new and suspect I am not coding the strategy the correct way or maybe there is a better way. In fact I am sure it should be done with consolidators, but not sure how.
As you will see from the code I have automatic daily Bollinger Band indicator that is being applied to multiple stocks. What I want is a have is an indicator say the Daily Bollinger Bands calculated at the close and the result made available at the close. So I can then have the strategy place an order in the after market trading.
However it looks like the following is happening:
- The Automatic Bollinger band indicator is not calculated until midnight, not at the market close.
- The automatic Bollinger Band Updated event appears to not occur until the next day at the end of the first bar of the next day. Being 4:01 if pre-market trading data is on and 9:31 if pre-market data is off.
- The Updated event does not appear to have a way to know which underlying assest that trigger the Updated Bollinger Band event.
What I would like is to have the Automatic Indicator say Bollinger Band. Calculate at the market close and be available after the maket close 16:45 for after market trading.
I would also like to calculate indicators before the market close using the latest days OHLC to that point during the day. This at 30 minutes before the end of the day it would recalculate the daily indicator. This would all the strategy to scan multiple stock and determine if a stock had met the indicator requirements.
I think could be done by with each minute bar updating my own OHLCV variables as the day progresses. After 4:00PM using data history loading it into a rolling window and then creating a fake bar from the daily calculated variables and adding that to the rolling window. Finally calculating the indicator value of the rolling windows. Happy to use arries, dataframes or other object if Rolling Windows are not right.
However I am sure there is a better way using consolidators to do this. Below there is my code to show how I discovered the indicators appear to update and midnight and are not open till the first bar of the next day.
I have also include my code to do the method above. But can not do the following steps:
- Load data from the history into a rolling window,
- Create a fake daily bar and load into a rolling window.
- Calculate and incidator of a rolling window.
Ideally I would like to have is my rolling windows are dictionaries. So I can load up multiple stocks with rolling window as dictionary entries and each minute check if the rolling window for the dictionary is populated.
if the last entry was not the close of the previous delete the entry from the rolling windows and add the fake bar before calculating the indicator. This will save reloading the history data for every chosen stock every minute.
Excuse me for not hard coding any values. Make maintenance of code easier.
Could not find the answers in the Discussion wondering if anyone know how to do this. Habit form my old C programming days.
Thank you from a newbee
main.py (Show the daily indicator is not calculated until midnight and does not trigger an event until the first bar the next day.)
#region imports
from AlgorithmImports import *
#endregion
class OptionsPolarity(QCAlgorithm):
def Initialize(self):
self.starting_date = datetime.date(2022, 11, 1)
self.ending_date = datetime.date(2022, 11, 25)
self.starting_cash = 20000
self.benchmark_ticker = "SPY"
self.universe_tickers = ["SPY", "AAPL", "CMG", "TSLA", "SLB", "NFLX"]
self.bb_period = 20
self.bb_std_dev = 75
self.bb_windows_periods = 200
self.asset_minutes = dict()
self.asset_symbols = dict()
self.bb_indicators = dict()
self.current_date = None
self.current_time = None
self.last_date = None
self.last_time = None
self.last_day = -1
self.new_day = None
self.bb_new_bar = False
self.current_ticker = None
self.current_ticker_price = None
self.current_days_open = dict()
self.current_days_high = dict()
self.current_days_lower = dict()
self.current_days_close = dict()
self.SetStartDate(self.starting_date)
self.SetEndDate(self.ending_date)
self.SetCash(self.starting_cash)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, \
AccountType.Cash)
for local_ticker in self.universe_tickers:
self.current_ticker = local_ticker
self.asset_minutes[self.current_ticker] = self.AddEquity(self.current_ticker, Resolution.Minute, Market.USA, True, 0, True)
self.asset_symbols[self.current_ticker] = self.asset_minutes[self.current_ticker].Symbol
self.bb_indicators[self.current_ticker] = self.BB(self.asset_symbols[self.current_ticker], self.bb_period, self.bb_std_dev, MovingAverageType.Simple, Resolution.Daily)
self.bb_indicators[self.current_ticker].Updated += self.bb_indicators_updated
self.SetWarmUp(TimeSpan.FromDays(self.bb_windows_periods + self.bb_period))
self.SetBenchmark(self.benchmark_ticker)
def bb_indicators_updated(self, sender, updated):
self.bb_new_bar = True
self.current_date = self.Time.date()
self.current_time = self.Time.time()
self.Debug("BB Updated Event occured Date and Time: " + str(self.current_date) + " " + str(self.current_time))
self.Debug("bb_indicators_Updated sender: " + str(sender))
self.Debug("bb_indicators_Updated updated: " + str(updated))
def OnData(self,slice):
self.current_date = self.Time.date()
self.current_time = self.Time.time()
if self.bb_new_bar == True:
self.Debug("First Backtest Bar After New BB Update Event")
self.Debug("Current Bar Closing Date and Time: " + str(self.current_date) + " " + str(self.current_time))
self.Debug("Last Bar Closing Date and Time: " + str(self.last_date) + " " + str(self.last_time))
if self.Time.day != self.last_day:
self.last_day = self.Time.day
self.new_day = True
self.day_count = self.day_count + 1
self.Debug("New Day")
self.Debug("Bar Closing Date and Time: " + str(self.current_date) + " " + str(self.current_time))
self.last_date = self.Time.date()
self.last_time = self.Time.time()
self.bb_new_bar = False
self.new_day = False
for local_ticker in self.universe_tickers:
continue
main.py (this is my attempt to solve my challenge)
(Commented out the code at the end. It does not work but should show what I am trying to do.
#region imports
from AlgorithmImports import *
#endregion
from datetime import datetime
from datetime import timedelta
import self
class OptionsPolarity(QCAlgorithm):
def Initialize(self):
self.starting_date = datetime.date(2022, 11, 1)
self.ending_date = datetime.date(2022, 11, 25)
self.starting_cash = 20000
self.benchmark_ticker = "SPY"
self.universe_tickers = ["SPY"], "AAPL", "FB", "TSLA", "FAS", "NFLX"]
self.asset_analysis_period = 120
self.bb_period = 20
self.bb_std_dev = 75
self.bb_windows_periods = 30 #200
self.asset_minutes = dict()
self.asset_symbols = dict()
self.asset_bars = dict()
self.asset_windows = dict()
self.bb_indicators = dict()
self.current_date = None
self.current_time = None
self.current_datetime = None
self.last_date = None
self.last_time = None
self.last_day = -1
self.new_day = None
self.day_count = 0
self.current_ticker = None
self.is_market_open = None
self.was_market_open = None
self.market_just_opened = None
self.market_just_closed = None
self.current_ticker_price = None
self.current_days_open = dict()
self.current_days_high = dict()
self.current_days_lower = dict()
self.current_days_close = dict()
self.current_days_volume = dict()
self.SetStartDate(self.starting_date)
self.SetEndDate(self.ending_date)
self.SetCash(self.starting_cash)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, \
AccountType.Cash)
for local_ticker in self.universe_tickers:
self.current_ticker = local_ticker
self.asset_minutes[self.current_ticker] = self.AddEquity(self.current_ticker, Resolution.Minute, Market.USA, True, 0, True)
self.asset_symbols[self.current_ticker] = self.asset_minutes[self.current_ticker].Symbol
self.asset_bars[self.current_ticker] = self.History([self.current_ticker], TimeSpan.FromDays(self.bb_windows_periods), Resolution.Daily)
self.asset_windows = RollingWindow[TradeBar](self.bb_windows_periods)
if self.asset_analysis_period > self.bb_windows_periods + self.bb_period:
self.SetWarmUp(TimeSpan.FromDays(self.asset_analysis_period))
else:
self.SetWarmUp(TimeSpan.FromDays(self.bb_windows_periods + self.bb_period))
self.SetBenchmark(self.benchmark_ticker)
def OnData(self,slice):
self.current_date = self.Time.date()
self.current_time = self.Time.time()
self.current_datetime = datetime.combine(self.current_date, self.current_time)
if self.Time.day != self.last_day:
self.last_day = self.Time.day
self.new_day = True
self.day_count = self.day_count + 1
for local_ticker in self.universe_tickers:
self.current_ticker = local_ticker
self.is_market_open = self.IsMarketOpen(self.current_ticker)
self.market_just_opened = False \
if self.is_market_open and not self.was_market_open else True
self.market_just_closed = False \
if not self.is_market_open and self.was_market_open else True
self.current_ticker_price = self.Securities[self.current_ticker].Price
if self.market_just_opened:
self.current_days_open[self.current_ticker] = self.current_ticker_price
self.current_days_high[self.current_ticker] = self.current_ticker_price
self.current_days_lower[self.current_ticker] = self.current_ticker_price
self.current_days_close[self.current_ticker] = self.current_ticker_price
self.current_days_volume[self.current_ticker] = self.Securities[self.current_ticker].Volume
elif self.is_market_open or self.market_just_closed:
if self.current_days_high[self.current_ticker] < self.current_ticker_price:
self.current_days_high[self.current_ticker] = self.current_ticker_price
if self.current_days_lower[self.current_ticker] > self.current_ticker_price:
self.current_days_lower[self.current_ticker] = self.current_ticker_price
self.current_days_close[self.current_ticker] = self.current_ticker_price
self.current_days_volume[self.current_ticker] = \
self.current_days_volume[self.current_ticker] + \
self.Securities[self.current_ticker].Volume
if self.is_market_open:
self.trading_hours = self.Securities[self.current_ticker].Exchange.Hours
self.current_open = self.trading_hours.GetNextMarketOpen(self.Time, False)
self.current_close = self.trading_hours.GetNextMarketClose(self.current_open, False)
self.thirty_minutes_before_close = self.current_close - timedelta(minutes=30)
if self.thirty_minutes_before_close.strftime('%H:%M') <= self.current_datetime.strftime('%H:%M'):
pass
#if not self.tradeBarWindow.IsReady:
# for i in range(self.bb_windows_periods, 1, -1):
#This of course does not work. But hope it show what am trying to do
# self.asset_windows[self.current_ticker].Add( \
# self.asset_bars[self.current_ticker][i])
#else:
#This of course does not work. But hope it show what am trying to do
#self.asset_windows[self.current_ticker].Delete
#This of course does not work. But hope it show what am trying to do
#self.asset_windows[self.current_ticker].Add(self.current_datetime,\
# self.current_days_open[self.current_ticker], \
# self.current_days_high[self.current_ticker], \
# self.current_days_low[self.current_ticker], \
# self.current_days_close[self.current_ticker], \
# self.current_days_volume[self.current_ticker])
#This of course does not work. But hope it show what am trying to do
#self.bb_indicators[self.current_ticker] = self.BB( \
# self.asset_windows[self.current_ticker], \
# bb_period[self.current_ticker], \
# bb_std_dev[self.current_ticker], Resolution.Daily)
self.last_date = self.current_date
self.last_time = self.current_time
self.was_market_open = self.is_market_open
self.bb_new_bar = False
self.new_day = False
Louis Szeto
Hi Jackson
For the event flow of the backtest instance, please refer to here.
Best
Louis
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.
Jackson Dude
Thank you from I read on the link you provided. It appear like you said to not calculate automatic indicators until midnight. But how to I get it to calculate the daily indicator at the close or before.
Derek Melchin
Hi Jackson,
To accomplish this, we need to use a manual BB indicator. To update it, create a Calendar consolidator with a custom period so that it consolidates bars between the start and end time you want.
This is because the BB indicator in the algorithm above is set to update with daily consolidated bars. A custom consolidator period will fix this.
The updated argument of the consolidation handler is a TradeBar object, which contains the security Symbol.
Create a second set of indicators since the consolidation periods will be different.
The algorithm should create the indicators in the Initialize method, not the OnData method. There is no need for RollingWindow objects because the BB indicators store the trailing data anyways. Try solving this with consolidators.
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.
Jackson Dude
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!