Back

Writing a custom AlphaModel

Derek Melchin gave me the following code as example:

class MyAlphaModel(AlphaModel):
def __init__(self, algorithm):
fastPeriod = 20
slowPeriod = 60
self._tolerance = 1 + 0.001
self.IsUpTrend = False
self.IsDownTrend = False

symbol = algorithm.AddEquity("SPY", Resolution.Daily).Symbol
self._fast = algorithm.EMA(symbol, fastPeriod, Resolution.Daily)
self._slow = algorithm.EMA(symbol, slowPeriod, Resolution.Daily)

# Warm up history
history = algorithm.History(symbol, slowPeriod, Resolution.Daily).loc[symbol]
for idx, row in history.iterrows():
self._fast.Update(idx, row.close)
self._slow.Update(idx, row.close)

def Update(self, algorithm, slice):
if not (algorithm.UtcTime.hour == 16 and algorithm.UtcTime.minute == 0 and algorithm.UtcTime.second == 0):
return []

insights = []
for symbol in slice.Keys:
if symbol.SecurityType != SecurityType.Future:
continue
insights.append(Insight.Price(symbol, timedelta(minutes=59), InsightDirection.Up))

return insights

and I want to adjust it to IBS indicator.

So I have written the following:

class MyAlphaModel(AlphaModel):
def __init__(self, algorithm):

symbol = algorithm.AddEquity("SPY", Resolution.Daily).Symbol
symbolsIBS = dict()

# Warm up history
history = algorithm.History(symbol, 1, Resolution.Daily).loc[symbol]
for idx, row in history.iterrows():
c = row.close
h = row.high
l = row.low
o = row.open
hilo = h - l

if o * hilo != 0:
symbolsIBS[symbol] = (c - l)/hilo

self.Update(idx, symbolsIBS)

def Update(self, algorithm, slice):
if not (algorithm.UtcTime.hour == 16 and algorithm.UtcTime.minute == 0 and algorithm.UtcTime.second == 0):
return []

insights = []
for symbol in slice.Keys:
if symbol.SecurityType != SecurityType.Future:
continue
insights.append(Insight.Price(symbol, timedelta(minutes=59), InsightDirection.Up))

return insights

unfortunatelly this code fails with the following error:


During the algorithm initialization, the following exception has occurred: AttributeError : 'Timestamp' object has no attribute 'UtcTime'
at Initialize in main.py:line 39
:: self.SetAlpha(MyAlphaModel(self))
at __init__ in main.py:line 79
at Update in main.py:line 82
:: if not (algorithm.UtcTime.hour == 16 and algorithm.UtcTime.minute == 0 and algorithm.UtcTime.second == 0):
AttributeError : 'Timestamp' object has no attribute 'UtcTime'

any hint on how to write such custom AlphaModel?

Update Backtest







0

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.


Hi Islander,

There is no built-in IBS indicator, so we'll have to create our own. First, we define a method to calculate the latest indicator value when given the high, low, and close prices.

def UpdateIndicatorValue(self, high, low, close):
if high != low:
self.indicator_value = (close - low) / (high - low)
else:
self.indicator_value = None

Now, when we warm up the indicator in the constructor of MyAlphaModel, we simply call the method

history = algorithm.History(symbol, 1, Resolution.Daily).loc[symbol]
for idx, row in history.iterrows():
self.UpdateIndicatorValue(row.high, row.low, row.close)

We also set up a consolidator in the constructor so the alpha model receives the latest data from the SPY.

algorithm.Consolidate(symbol, timedelta(1), self.ConsolidationHandler)

The consolidation callback is then defined as

def ConsolidationHandler(self, consolidated):
self.UpdateIndicatorValue(consolidated.High, consolidated.Low, consolidated.Close)

To see this all in action, refer to the attached backtest. For more information, I recommend reviewing our documentation on data consolidation.

Best,
Derek Melchin

1

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.


Thank  Derek Melchin for your help.

This code is really interesting but it uses another asset time series to calculate the indicator value (SPY).

Using SP500Mini to calculate the indicator value instead of SPY is also possible? How?

I have tried several option and I am always getting an error message.

0

Hi Islander,

We can update the indicator with the data inside the Update method. To access this data, we first need to get the one symbol with symbol = slice.Keys[0]. Since we only subscribe to Future at a time, the front ES contract, slice.Keys[0] gets the first and only symbol from our list of one symbol. Then we can get the TradeBar of data from the slice with bar = slice.Bars[symbol].

I've shown how to do this in the attached backtest.

Best,
Shile Wen

0

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.


Thank you Shile Wen , very interesting.

However I need to calculate IBS with Daily resolution and I think your script uses 1 minute timeframe.

How can I change it?

0

Hi Islander,

We do not have daily data for Futures. Thus, we will need to consolidate the data into Daily bars, and compute the IBS within the consolidation function. These docs would be a great resource on how to do this.

Best,
Shile Wen

0

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.


Ok. Thanks Shile Wen 

But consider Derek Melchin example below.

When it adds equity with Daily resolution:

symbol = algorithm.AddEquity("SPY", Resolution.Daily).Symbol

Does it mean the value calculated in the past 24 hours?

Because in my understanding it should be taken from opening at 9:30AM EST and closing at 4:00PM EST.

But I have added some code to print self.indicator_value every hours and this value changes every hour.

So I don't think it makes sense. It seems it is considering the last 24 hours.

How can I change this?

Can you understand what I mean?

 

0


Hi Islander,

The algorithm above is using the Debug method to print the indicator values each hour. Debug messages are rate-limited, so it appears the indicator value is changing with each print. However, it is not. The timestamps that print with each line in the log file shows that each print corresponds to one day. If we use the Log method instead of Debug, the daily update of the indicator value is made clear.

See the attached backtest and logs for reference. Also, consider reviewing our documentation on Logging and Debugging.

Best,
Derek Melchin

0

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.


Ok Derek Melchin I got it.

However, consider the attached backtest where I only have changed some logging.

I am getting the following output:

2020-07-20 00:00:00 Launching analysis for ab3158c6993dc4cd5b54031735858886 with LEAN Engine v2.4.0.0.8998
2020-07-20 00:00:00 Market: 322.56, 319.74, 321.67
2020-07-20 00:00:00 indicator: 0.6843971631205714
2020-07-20 01:00:00 indicator: 0.6843971631205714
2020-07-20 02:00:00 indicator: 0.6843971631205714
2020-07-20 03:00:00 indicator: 0.6843971631205714
2020-07-20 04:00:00 indicator: 0.6843971631205714
2020-07-20 05:00:00 indicator: 0.6843971631205714
2020-07-20 06:00:00 indicator: 0.6843971631205714
2020-07-20 07:00:00 indicator: 0.6843971631205714
2020-07-20 08:00:00 indicator: 0.6843971631205714
2020-07-20 09:00:00 indicator: 0.6843971631205714
2020-07-20 10:00:00 indicator: 0.6843971631205714
2020-07-20 11:00:00 indicator: 0.6843971631205714
2020-07-20 12:00:00 indicator: 0.6843971631205714
2020-07-20 13:00:00 indicator: 0.6843971631205714
2020-07-20 14:00:00 indicator: 0.6843971631205714
2020-07-20 15:00:00 indicator: 0.6843971631205714
2020-07-20 16:00:00 indicator: 0.6843971631205714
2020-07-20 17:00:00 indicator: 0.6843971631205714
2020-07-20 19:00:00 indicator: 0.6843971631205714
2020-07-20 20:00:00 indicator: 0.6843971631205714
2020-07-20 21:00:00 indicator: 0.6843971631205714
2020-07-20 22:00:00 indicator: 0.6843971631205714
2020-07-20 23:00:00 indicator: 0.6843971631205714
2020-07-21 00:00:00 Market: 325.13, 320.62, 324.36

IBS calculation is correct, the problem is if I get data from Yahoo for instance I am getting:

Jul 20, 2020 3,214.50 3,250.50 3,190.25 3,245.25 3,245.25 1,401,168

which gives me IBS = 0.9128

I believe this difference because my strategy considers high/low/close at midnight instead of considering open at 9:30 and close at 16:00 ETC.

If so, how could I take these values?

0


Hi Islander,

The issue here is that the algorithm above updates the indicator value with prices from the SPY, not the selected E-mini contract. We can see this inside the Alpha model:

def __init__(self, algorithm):
self.algo = algorithm
symbol = algorithm.AddEquity("SPY", Resolution.Daily).Symbol

# Warm up history
history = algorithm.History(symbol, 1, Resolution.Daily).loc[symbol]
for idx, row in history.iterrows():
self.UpdateIndicatorValue(row.high, row.low, row.close)

algorithm.Consolidate(symbol, timedelta(1), self.ConsolidationHandler)

To update the indicator with data from the selected contract, we should remove the subscription to the SPY data and setup the consolidator in the OnSecuritiesChanged method.

def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.RemovedSecurities:
algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.myConsolidator)

for security in changes.AddedSecurities:
self.symbol = security.Symbol
algorithm.Consolidate(self.symbol, timedelta(1), self.ConsolidationHandler)

See the attached backtest for reference. Note the attached backtest doesn't warm-up the indicator when a new contract is selected yet. This can be implemented inside the OnSecuritiesChanged method in the same fashion that was done in the above algorithm. Just keep in mind that we would need to request intraday data to do so as we don't have daily futures data.

Best,
Derek Melchin

0

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.


Update Backtest





0

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.


Loading...

This discussion is closed