Hello,
I am trying to use volume bars by implementing ClassicalRenkoConsolidator.
I am getting an error:
Runtime Error: 'QuoteBar' object has no attribute 'Volume'
at <lambda>
self.equivolume_consolidator = ClassicRenkoConsolidator(int(volume_daily_mean / 10) in main.py: line 100
I don't understand where QuoteBars comes from.
Here is the code (can't attach code with error):
# region imports
from AlgorithmImports import *
# endregion
class WellDressedFluorescentYellowFly(QCAlgorithm):
def Initialize(self):
# params
self.frequency = Resolution.Minute
# set up
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2020, 3, 1)
self.SetCash(100000)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
# Add QC500 Universe
equity = self.AddEquity("SPY", Resolution.Minute)
self.spy = equity.Symbol
self.Securities[self.spy].SetDataNormalizationMode(DataNormalizationMode.Raw)
self.SetBenchmark(lambda dt: self.Securities[self.spy].Price)
self.AddUniverse(self.CoarseSelectionFunction)
self.UniverseSettings.Resolution = Resolution.Minute
# init
self.Data = {}
self.excess_window = RollingWindow[float](10)
self.day = -1
def CoarseSelectionFunction(self, coarse):
# rebalancing
if self.day == self.Time.day:
return Universe.Unchanged
self.day = self.Time.day
# filter n stocks with highest dollar volume
filtered_coarse = [x for x in coarse if x.HasFundamentalData and x.AdjustedPrice > 5]
selected = sorted(filtered_coarse, key=lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in selected[:5]]
def OnSecuritiesChanged(self, changes):
# added securities
def DataDictInitialization():
for security in changes.AddedSecurities:
symbol = security.Symbol
if symbol not in self.Data:
self.Data[symbol] = SelectionData(self, symbol)
self.Train(DataDictInitialization)
# removed securities
for security in changes.RemovedSecurities:
symbol = security.Symbol
if symbol in self.Data:
symbolData = self.Data.pop(symbol, None)
def OnData(self, data):
# if there are no bars data (only stok splits, dividends etc) than cont
if self.spy not in data.Bars: return
if not data.Bars.ContainsKey(self.spy): return
if not data.ContainsKey(self.spy): return
# calculate sums of above and below and their difference
self.Debug(f"Dat keys {self.Data.keys()}")
self.Debug(f"Data diff window {[list(self.Data[symbol].excess_diff_window) for symbol in self.Data.keys()]}")
class SelectionData(object):
def __init__(self, algorithm, symbol):
# set up
self.algorithm = algorithm
self.symbol = symbol
# rolling windows
self.close_window = RollingWindow[float](100)
self.excess_diff_window = RollingWindow[float](10)
self.daily_volume_window = RollingWindow[float](6)
# consolidators
self.daily_consolidator = self.algorithm.Consolidate(symbol, Resolution.Daily, self.DailyBarHandler)
# warm up daily volume
history = self.algorithm.History([self.symbol], 6 + 1, Resolution.Daily)
if history.shape[0] == 0:
self.algorithm.Log('DataFrame is empty!')
return
for tuple in history.loc[self.symbol].itertuples():
self.daily_volume_window.Add(tuple.volume)
# classical renko volume bar
if self.daily_volume_window.IsReady:
volume_window = list(self.daily_volume_window)
volume_daily_mean = sum(volume_window) / len(volume_window)
self.algorithm.Debug(f"Daily mean volume is {int(volume_daily_mean / 10)}.")
self.equivolume_consolidator = ClassicRenkoConsolidator(int(volume_daily_mean / 10), selector = lambda data: data.Volume)
self.equivolume_consolidator.DataConsolidated += self.OnDataConsolidated
self.algorithm.SubscriptionManager.AddConsolidator(self.symbol, self.equivolume_consolidator)
# warm up volume bars
if self.daily_volume_window.IsReady:
history = self.algorithm.History([symbol], 500, Resolution.Minute)
if history.shape[0] == 0:
self.algorithm.Log('DataFrame is empty!')
return
if 'volume' not in history.columns:
self.algorithm.Log(f"No volume: {symbol}\n{history.to_string()}")
return
for tuple in history.loc[self.symbol].itertuples():
tradebar = TradeBar(tuple.Index, self.symbol, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume)
self.equivolume_consolidator.Update(tradebar)
def DailyBarHandler(self, consolidated):
if "Volume" is consolidated.values():
self.Debug("No volume!")
return
self.daily_volume_window.Add(consolidated.Volume)
def OnDataConsolidated(self, sender, data):
self.close_window.Add(data.Close)
if self.close_window.IsReady:
pass
# def update(self, price):
# self.close_window.Add(price)# Your New Python Fileimport numpy as np
Louis Szeto
Hi Mislav
The selector argument was not meant to use Volume as input. Instead, there is another optional argument of volumeSelector to do so (see here). You may refer to this implementation in LEAN as an example.
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.
Mislav Sagovac
Louis Szeto , actually I have seen the LEAN example, but I does't look like volume bar tome . Shouldn't this code
create bars depending in the calculated average price, not volume bars? Actually, I can't figure out what does volume do here? I need "simple" volume bars.
Mislav Sagovac
Can you show how would you create volume bars for 2 stocks?
Derek Melchin
Hi Mislav,
If we define volume bars as bars that contain the OHLC of the security price and the volume is a fixed value, we can't create volume bars with the Renko consolidators. To be notified when volume bars are available, subscribe to GitHub Issue #3754.
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.
Mislav Sagovac
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!