Hi, I'm new to Quantconnect.
I started this with adding 1 ticker via the AddEquity-function - then I had everything working, rolling windows of EMAs, VWAP and the symbol price.
Now I am trying to convert everything to use a custom universe, but I am stuck.
Been reading dozens of different forum topics to try and find someone seeking help for something similar, but I still can't understand what I am doing wrong. As the code is now, it's a mix of different snippets from different topics..
Can someone please look at this and advice me?
#region imports
from AlgorithmImports import *
#endregion
class FirstTest(QCAlgorithm):
def Initialize(self):
self.SetCash(100000)
self.SetTimeZone(TimeZones.NewYork)
# Start and end dates for backtest
self.SetStartDate(2022,5,23)
self.SetEndDate(2022,6,23)
# Maximum Price offset for stop order
self.initialStopRisk = 0.03
# for testing purposes - adding symbols one by one
#self.symbol = self.AddEquity("BHAT", Resolution.Minute, Market.USA, True, 1, True).Symbol
self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseFilter))
self.UniverseSettings.ExtendedMarketHours = True
self.UniverseSettings.Resolution = Resolution.Minute
self.universe = []
self.AddEquity("SPY", Resolution.Minute)
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(9, 31), self.SelectUniverse)
self.previous_close_by_symbol = {}
#Initiate Indicators:
self.indicators = {}
self.EMA_Period_Fast = 10
self.EMA_Period_Slow = 20
emaL_is_true=0
self.deadVWAP=0.0001
#Schedules:
#self.rebuyTime=datetime.min # if I want to minimize rebuys within e.g. 10 mins
#Sell all before market close
#self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 15), self.ClosePositions)
def CoarseFilter(self, coarse):
selected = [c for c in coarse if c.HasFundamentalData and c.Price>100]
selected = sorted(selected, key=lambda x: x.DollarVolume, reverse=True)[:10]
self.Debug(f"Universe size after coarse filter: {len(selected)}")
self.previous_close_by_symbol = {}
for l in selected:
self.previous_close_by_symbol[l.Symbol] = l.AdjustedPrice
return list(self.previous_close_by_symbol.keys())
def SelectUniverse(self):
self.universe = []
for symbol, previous_close in self.previous_close_by_symbol.items():
if symbol not in self.CurrentSlice.Bars:
continue # return?
open_price=self.CurrentSlice.Bars[symbol].Open
gap=(open_price - previous_close) / previous_close
#self.Debug(str(symbol)+" not gapping up at" + str(self.Time))
if gap>0.01:
self.universe.append(symbol)
self.Log(str(symbol) + str(self.Time) + "Gap is " + str(gap * 100))
self.Debug(f"Universe size after looking for gaps: {len(self.universe)}")
def OnSecuritiesChanged(self, changes):
# Create indicator for each new security
for security in changes.AddedSecurities:
self.indicators[security.Symbol] = SymbolData(security.Symbol, self, self.EMA_Period_Fast, self.EMA_Period_Slow)
self.Debug("Added indicators for" + str(security.Symbol))
for security in changes.RemovedSecurities:
if security.Invested:
self.Liquidate(security.Symbol, "Universe Removed Security") # sell the removed security
if security in self.indicators:
self.indicators.pop(security.Symbol, None) # removes the indicator
if security.Symbol in self.data:
del self.data[security.Symbol]
#Nope, self.Bars would only be accessible in SymbolData class.
# In OnData method in youralgo class, you would call self.Data[symbol].Bars[0].Close.
# In the above example, since the dictionary value has been called as a variable,
# you can call symbolData.Bars[0].Close in the line that I hashtaged # your actions
def OnData(self, data):
#self.Plot("Data Chart", self.symbol, self.Securities[self.symbol].Low) # plots the chart of the testing symbol
for symbol in self.universe:
self.Log(str(self.Securities[symbol])+str(self.Time))
if not data.ContainsKey(symbol):
continue
if data[symbol] is None:
continue
if not symbol in self.indicators:
continue
if not self.indicators[symbol].slow_ema.IsReady: # Ensure indicators are ready to update rolling windows
continue
# Update EMA rolling windows
self.indicators[symbol].fast_ema_window.Add(self.indicators[symbol].get_fast_EMA())
self.indicators[symbol].slow_ema_window.Add(self.indicators[symbol].get_slow_EMA())
self.indicators[symbol].vwap_window.Add(self.indicators[symbol].get_VWAP())
# Check for Indicator Readiness within Rolling Window
#-------------------------------------------------------
if not (self.indicators[symbol].fast_ema_window.IsReady and self.indicators[symbol].slow_ema_window.IsReady and self.indicators[symbol].vwap_window.IsReady):
continue
#SymbolData=data[symbol]
if SymbolData.IsReady(self): #and SymbolData.WasJustUpdated(self, self.Time):
continue
if (self.Time.hour == 9 and self.Time.minute == 33):
max_of_opening_highs=max(SymbolData.Bars[1].High, SymbolData.Bars[2].High)
self.Debug("Max of ORH 2 last minutes:" +str(max_of_opening_highs))
self.Debug("High at this time:" +str(SymbolData.Bars[0].High))
if SymbolData.Bars[0].High > max_of_opening_highs:
self.LowOfBuyBar = SymbolData.Bars[0].Low
self.Debug("Buy order created")
self.SetHoldings(symbol, 0.25, False, "ORH BUY") # buy with 25% of account
# old way
#def CustomBarHandler(self, bar):
# self.rollingWindow.Add(bar)
def OnOrderEvent(self, orderevent):
# check if orderevent is a fill
if orderevent.Status == OrderStatus.Filled:
symbol = orderevent.Symbol
fill_price = orderevent.FillPrice
current_price = self.Securities[symbol].Price
self.Debug("Fill price of order is: " +str(orderevent.FillPrice))
self.BuyPrice=fill_price
# Create trailing stop loss if invested
if self.Securities[symbol].Invested:
# If no order exists, send stop-loss
if not self.Transactions.GetOpenOrders(symbol):
self.stopMarketTicket = self.StopMarketOrder(symbol, \
-self.Portfolio[symbol].Quantity, \
(1-min(self.initialStopRisk, 1-(self.LowOfBuyBar/self.BuyPrice)))*self.BuyPrice-0.01, "STOPLOSS") # setting stop 1 cent below
self.Debug("Stop loss set at: "+ str((1-min(self.initialStopRisk, 1-(self.LowOfBuyBar/self.BuyPrice)))*self.BuyPrice-0.01))
## should be called at market close, if wanted
# def ClosePositions(self):
# for security in self.universe:
# if self.Securities[security.Symbol].Invested:
# self.Liquidate(security.Symbol)
class SymbolData(object):
rolling_window_length = 5
def __init__(self, symbol, context, fast_ema_period, slow_ema_period):
self.symbol = symbol
self.BarPeriod = timedelta(minutes=1)
self.Bars = RollingWindow[IBaseDataBar](2)
self.fast_ema_period = fast_ema_period
self.slow_ema_period = slow_ema_period
self.vwap = VolumeWeightedAveragePriceIndicator(20) #60*24 = 1440 minutes in a day
self.fast_ema = context.EMA(symbol, self.fast_ema_period, Resolution.Minute) #, fillDataForward = True, leverage = 1, extendedMarketHours = False)
self.slow_ema = context.EMA(symbol, self.slow_ema_period, Resolution.Minute) #, fillDataForward = True, leverage = 1, extendedMarketHours = False)
#self.vwap = context.VWAP(symbol) #, fillDataForward = True, leverage = 1, extendedMarketHours = False)
self.fast_ema_window = RollingWindow[float](self.rolling_window_length)
self.slow_ema_window = RollingWindow[float](self.rolling_window_length)
self.vwap_window = RollingWindow[float](self.rolling_window_length)
### old way rollingwindow, now testing self.Bars
#self.rollingWindow = RollingWindow[TradeBar](4)
#self.Consolidate(self.symbol, Resolution.Minute, self.CustomBarHandler)
# Warm up indicators
history = context.History([symbol], slow_ema_period + self.rolling_window_length, Resolution.Minute)
for time, row in history.loc[symbol].iterrows():
self.fast_ema.Update(time, row["close"])
self.slow_ema.Update(time, row["close"])
# self.vwap.Update(time, row["close"]) # vwap does not support this method of updating according to error message so did below
tradeBar = TradeBar(time, symbol, row.open, row.high, row.low, row.close, row.volume, timedelta(minutes=1))
self.vwap.Update(tradeBar)
# Warm up rolling windows ## check indentation ?
if self.fast_ema.IsReady:
self.fast_ema_window.Add(self.fast_ema.Current.Value)
if self.slow_ema.IsReady:
self.slow_ema_window.Add(self.slow_ema.Current.Value)
if self.vwap.IsReady:
self.vwap_window.Add(self.vwap.Current.Value)
self.consolidator = TradeBarConsolidator(Resolution.Minute)
self.consolidator.DataConsolidated += self.consolidation_handler
context.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
def IsReady(self):
return self.Bars.IsReady
def WasJustUpdated(self, current):
return self.Bars.Count > 0 and self.Bars[0].Time == current - self.BarPeriod
def consolidation_handler(self, sender, consolidated):
self.vwap.Update(consolidated)
def get_fast_EMA(self):
return self.fast_ema.Current.Value
def get_slow_EMA(self):
return self.slow_ema.Current.Value
def get_VWAP(self):
return self.vwap.Current.Value
Jimmy Fransson
I see now that I was mixing up self.indicators with self.data / symboldata!
Jimmy Fransson
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!