Jared Broad, This is a follow-up to our discussion in Slack. Thanks so much for your response.
Is it possible, using history, rolling window, or something else, to select Universe based on whether today was a hammer at end of day?
One of my first attempts at this was based on the EMA Universe Selection tutorial in the Bootcamp. Here's a version of that attempt: this is giving me a bunch of Please register to receive data for symbol... errors:
class HammersUniverse(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 2, 20)
self.SetCash(10000)
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction)
self.hammers = { }
def CoarseSelectionFunction(self, universe):
selected = []
universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
# If I only want US stocks, is this the correct route?
universe = [c for c in universe if c.Price > 10 and c.Market == 'usa'][:10]
for security in universe:
symbol = security.Symbol
if symbol not in self.hammers:
history = self.History(symbol, 1, Resolution.Daily)
self.hammers[symbol] = SelectionData(self, history, symbol)
self.hammers[symbol].update(security.Time, security.Price)
if self.hammers[symbol].is_ready():
_hammer_value = self.hammers[symbol].Current.Value
if _hammer_value == 1 or _hammer_value == -1:
selected.append(symbol)
return selected[:10]
def OnSecuritiesChanged(self, changes):
for security in changes.RemovedSecurities:
# self.Liquidate(security.Symbol)
self.Debug(f"Added: { security.Symbol }")
for security in changes.AddedSecurities:
# self.SetHoldings(security.Symbol, 0.10)
self.Debug(f"Removed: { security.Symbol }")
class SelectionData():
def __init__(self, algo, history, symbol):
# Could not call CandleStickPatterns directly like we do EMA in the Bootcamp, so I pass the
# Also, for Hammer, I needed the symbol we are working with.
# Is this a good way to go?
self.hammer = algo.CandlestickPatterns.Hammer(symbol, Resolution.Daily)
for bar in history.itertuples():
tradebar = TradeBar(bar.Index[1], bar.Index[0], bar.open, bar.high, bar.low, bar.close, bar.volume)
self.hammer.Update(tradebar)
def is_ready(self):
return self.hammer.IsReady
def update(self, time, price):
self.hammer.Update(time, price)
I diverged from this based on some forum posts I'd seen, but none speak to this specific need directly, so I have been piecing things together).
In Slack, you'd mentioned that I am using the helper method, and that I need to use the actual class--the helpers are normally capitalized, but in the candle sections are lowercase. Where might I find the documentation on this? You are referring to the call to
algo.CandlestickPatterns.Hammer(symbol, Resolution.Daily), correct?
James Candan
Got it! Thanks Bootcamp!
Added an Alpha model, and was able to get hammers like so:
from datetime import timedelta class HammerAlpha(AlphaModel): def __init__(self): self.hammers = [] def OnSecuritiesChanged(self, algorithm, changes): # Initialize a daily Hammer indicator for each symbol. for security in changes.AddedSecurities: symbol = security.Symbol self.hammers.append({"symbol":symbol, "indicator":algorithm.CandlestickPatterns.Hammer(symbol, Resolution.Daily)}) def Update(self, algorithm, data): # Filter the list of dictionaries by any positive Hammers. _up_symbols = [h["symbol"] for h in self.hammers if h["indicator"].Current.Value == 1] # Build our list of insights. _insights = [Insight.Price(symbol, timedelta(1), InsightDirection.Up) for symbol in _up_symbols] # Make a comma separated list of Hammer symbols. _symbol_list = ", ".join([insight.Symbol.Value for insight in _insights]) # Output our list of symbols. algorithm.Debug( _symbol_list ) return Insight.Group(_insights)
Â
James Candan
Although, looking at the results more closely, the lists of Hammer symbols seem a bit off when compared with an external charting tool.
How might I output the tradebar values to help me debug?
How might I filter by Hammers with Low below the Open/Close of the previous? I imagine history will need to be involved.Â
Also, just want to be sure this filtering is appropriate for the Alpha step and not Universe Selection. Please advise.
James Candan
Okay, I feel I am getting the hang of this.
I saw that I do not need history. The data slice in the AlphaModel Update method has the price data I wanted. I also set the universe normalization to raw to get the price points to more closely match my third-party charting tools.
The other big change here is that I also added the necessary call to update each Hammer indicator item!
from datetime import timedelta class HammerAlpha(AlphaModel): def __init__(self): self.hammers = {} def OnSecuritiesChanged(self, algorithm, changes): # Initialize a daily Hammer indicator for each symbol. for security in changes.AddedSecurities: symbol = security.Symbol if symbol not in self.hammers: self.hammers[symbol] = algorithm.CandlestickPatterns.Hammer(symbol, Resolution.Daily) def Update(self, algorithm, data): for s in self.hammers.keys(): if data.Bars.ContainsKey(s) and s in self.hammers: self.hammers[s].Update(data[s]) _up_symbols = [s for s, h in self.hammers.items() if data.Bars.ContainsKey(s) and h.IsReady and h.Current.Value == 1] if len(_up_symbols) > 0: # Build our list of insights. _insights = [Insight.Price(symbol, timedelta(1), InsightDirection.Up) for symbol in _up_symbols] # Make a comma separated list of Hammer symbols. _symbol_list = ", ".join([str(data[symbol]) for symbol in _up_symbols]) # Output our list of symbols. algorithm.Log( _symbol_list ) return Insight.Group(_insights) return [] class HammersUniverse(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetCash(100000) self.UniverseSettings.Resolution = Resolution.Daily self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw self.AddUniverse(self.CoarseSelectionFunction) self.AddAlpha(HammerAlpha()) def CoarseSelectionFunction(self, universe): universe = sorted(universe, key = lambda c: c.DollarVolume, reverse = True) universe = [c for c in universe if c.Price > 10][:100] return [c.Symbol for c in universe]
Â
Derek Melchin
Hi James,
To get a universe of securities that have made a Hammer pattern with the last daily candle, we should move the indicator logic into the universe selection process. Refer to the EmaCrossUniverseSelectionAlgorithm for an example of having technical indicators inside a universe selection method.
Note that when adding this logic to universe selection we update the indicators manually instead of using the `algorithm.CandlestickPatterns.Hammer` method used above. The latter subscribes the indicator for automatic updates, which isn't consistent when done during universe selection. Refer to this algorithm for an example of manually updating a candlestick pattern with TradeBars.
For the coarse universe selection, consider sorting the CoarseFundamental objects by dollar volume and then make a History request in batches of 100 securities. When we have found sufficient hammers, we can then return.
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.
James Candan
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!