I would like to build some custom indicators for an Alpha Model.
in this case I would like to replace a standard momentum indicator with a exponetial slope, like suggested by Andreas Clenow in his book.
Does someone have an clue why this is not working. During debugging I do not get any value for input.Close in the class for the custom indicator, but i'm just using this example which is similar
https://www.quantconnect.com/forum/discussion/3383/custom-indicator-in-python-algorithm/p1
Thanks
Carsten
from datetime import timedelta
import numpy as np
from scipy import stats
from collections import deque
class CustomSlope(PythonIndicator):
def __init__(self, name, period):
self.Name = name
self.Time = datetime.min
self.Value = 0
self.queue = deque(maxlen=period)
# Update method is mandatory
def Update(self, input):
y= [np.log(float(data)) for data in input.Close]
x = [range(len(y))]
slope,r_value = stats.linregress(x,y)[0],stats.linregress(x,y)[2]
return slope
class MOMAlphaModel(AlphaModel):
def __init__(self):
self.mom = []
self.cslope = CustomSlope('custom', 100)
if not self.cslope.IsReady:
return
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
symbol = security.Symbol
#self.mom.append({"symbol":symbol, "indicator":algorithm.MOM(symbol, 100, Resolution.Daily)})
algorithm.RegisterIndicator(symbol, self.cslope, Resolution.Daily)
self.mom.append({"symbol":symbol, "indicator":self.cslope.Value})
def Update(self, algorithm, data):
insights = []
ordered = sorted(self.mom, key=lambda kv: kv["indicator"].Current.Value, reverse=True)[:4]
for x in ordered:
symbol = x['symbol']
insights.append( Insight.Price(symbol, timedelta(1), InsightDirection.Up) )
return insights
Carsten
The issue abouve is solved, indicator is working, but its not warming up.
I commented some lines which shuld warm it up, but lead to errors i do not understand.
specially the it does not like self.IsReady=True
Shile Wen
Hi Carsten,
Our first issue is that we don't initialize nor update the IsReady property of an Indicator. Furthermore, we don't add the data passed in on Update to our deque, so we can't do any calculations. We also want to access the value using .Value instead of .Current.Value. Finally, I made a few other changes to make the code work. Please see the changes in the attached backtest.
Furthermore, I suggest warming up the indicators as shown in this BootCamp
Best,
Shile Wen
Carsten
Hi Shile,
first thank you very much for your help, the code works fine, but have some questions.
When i did the tutorial, i found a lot of times that i need to warm up the indicators, as well in the tutorial you suggested, they call historical data and than update the indicator.
The code you did looks very clean to me and I like it very much, but I don't see any warm up. (Even the warmup part in the custom indicator its gone now). So I don't worry about warming up any more if I use the quantopian frame work? But i need the empty def OnData(self, data): part, right? This is were the indeicators get filled with historical data?
Regarding the current value, I would like to grab the yesterday value. I guess i need to use x[-1] ? (in AlphaModel / Update)
ordered = sorted(self.mom.items(), key=lambda x: x[1].Value, reverse=True)[:4]
To check my indicators, can i plot it somehow for one of the symbols? I tried different ways but faild, could you just give me an hint.
Thanks Carsten
Carsten
Hi Shile I can't edit my text,
please neglect that question regarding: ordered = sorted(self.mom.items(), key=lambda x: x[1].Value, reverse=True)[:4]
it does not make sence,
Carsten
Hi Shile
i got basicly almoust everything running, thank you
The only small issue I have is the IsReady Property. In line 95, I set the self.IsReady = False but with no effect on the code
Carsten
Carsten
Hi Shile,
the code above was not function correctly. I programmed everthing like shom in the this BootCamp you suggested.
Now I get this error:
Runtime Error: NotImplementedException : Indicator.IsReady must be implemented. Please implement this missing method in dict or use PythonIndicator as base:
I tried already with PythonIndicator but no changes.
What is missing?
thankx Carsten
As i did not got an backtest I can notpost the algo the usual way, i will copy it below
from datetime import timedelta import numpy as np from scipy import stats from collections import deque class ModulatedMultidimensionalReplicator(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 6, 1) #self.SetEndDate(2020, 1, 1) self.SetCash(50000) tickers = ["QQQ","IYC","IYK","IGV","SMH","GLD","TLH","TLT"] self.sym=[] for x in tickers: self.sym.append(Symbol.Create(x, SecurityType.Equity, Market.USA)) self.SetUniverseSelection( ManualUniverseSelectionModel(self.sym) ) self.UniverseSettings.Resolution = Resolution.Daily self.AddAlpha(MOMAlphaModel()) self.Settings.RebalancePortfolioOnInsightChanges = False self.Settings.RebalancePortfolioOnSecurityChanges = False self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.DateRules.Every(DayOfWeek.Monday))) self.SetExecution(ImmediateExecutionModel()) def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' # if not self.Portfolio.Invested: # self.SetHoldings("SPY", 1) pass class MOMAlphaModel(AlphaModel): def __init__(self): self.indicator = {} self.securities = [] def OnSecuritiesChanged(self, algorithm, changes): ''' Description: Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm ''' # add new securities for security in changes.AddedSecurities: self.securities.append(security) symbol = security.Symbol # Call history to get an array of 200 days of history data history = algorithm.History(symbol, 100, Resolution.Daily) # Adjust SelectionData to pass in the history result self.indicator[symbol] = SelectionData(history, 100) # RegisterIndicator algorithm.RegisterIndicator(symbol, self.indicator, Resolution.Daily) # remove securities for security in changes.RemovedSecurities: if security in self.securities: self.securities.remove(security) def Update(self, algorithm, data): insights = [] # momentum ordered = sorted(self.indicator.items(), key=lambda x: x[1].Value, reverse=True)[3] for x in ordered: symbol = x[0] insights.append( Insight.Price(symbol, timedelta(1), InsightDirection.Up) ) return insights class SelectionData(): # Update the constructor to accept a history array def __init__(self,history, period): self.IsReady = False self.Value = 0 self.ex_reg = CustomSlope('CSlope', period) #4. Loop over the history data and update the indicators for bar in history.itertuples(): self.ex_reg.Update(bar.Index[1], bar.close) def is_ready(self): return self.ex_reg.IsReady def Update(self, time, price): self.ex_reg.Update(time, price) class CustomSlope: def __init__(self, name, period): self.Name = name self.Time = datetime.min self.IsReady = False self.Value = 0 self.Slope = 0 self.Corr = 0 self.queue = deque(maxlen=period) def __repr__(self): return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value) def Update(self, time, value): self.queue.appendleft(value) count = len(self.queue) self.Time = time self.IsReady = count == self.queue.maxlen #### start here the indicator calulation if self.IsReady: y = np.log(self.queue) x = [range(len(y))] slope, corr = stats.linregress(x, y)[0], stats.linregress(x, y)[2] self.Slope = slope self.Corr = corr self.Value = slope * corr #### finish the custom indicator return self.IsReady
Shile Wen
Hi Carsten,
The error is because we are trying to Register the entire dict as an indicator, so we need to first index the dict. Then the SelectionData isn't a proper indicator class, so we can instead just register the .ex_reg field instead. I've shown the changes as well as a few other bug fixes in the attached backtest.
Best,
Shile Wen
Jared Broad
How to manage collections of many objects is covered in Boot Camp. Look for the SymbolData class in the universe tutorials as an example.
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.
Carsten
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!