Back

Custom indicator in python algorithm

We have added a new feature yesterday: custom indicator for python algorithm.
It is quite simple! Basically we just need to create a class with an Update method:

class MyCustomIndicator:
def __init__(self, params):
self.params = params
def Update(self, input):
pass

where input can be any IBaseData object (Tick, TradeBar, QuoteBar, etc).

The Update method with one argument is important because if we want to register the indicator for automatic updates, the engine will look for that method in order to pass an IBaseData object.

Here is an example of a simple moving average indicator:

# Python implementation of SimpleMovingAverage.
# Represents the traditional simple moving average indicator (SMA).
class CustomSimpleMovingAverage:
def __init__(self, name, period):
self.Name = name
self.Time = datetime.min
self.Value = 0
self.IsReady = False
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)

# Update method is mandatory
def Update(self, input):
self.queue.appendleft(input.Close)
count = len(self.queue)
self.Time = input.EndTime
self.Value = sum(self.queue) / count
self.IsReady = count == self.queue.maxlen

We advice users to implement the boolean IsReady attribute, since it is ofter used when dealing with built-in indicators.

Like the built-in indicators, we can register the indicator in Initialize method:

# In Initialize
self.custom = CustomSimpleMovingAverage('custom', 60)
self.RegisterIndicator("SPY", self.custom, Resolution.Minute)

C# users, please check out this tutorial: How Do I Create an Indicator?

Update Backtest






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.



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, Alexandre,

How can I use existing indicator in custom ones by python?

To use e.g. BB, we need to specify symbol, which is only available from "input" parameter in Update function?

Thanks for help. 

0

the symbol does not have to be set!

just define your bolinger band and update it with the value you  have. whatever it is.

0

Hello all,

  I am new to the platform so please forgive me if I am missing something obvious. I think I have a similar question to @21pinegrove but am not sure how to implement to the solution mentioned by Michael. 

I would like to use an indicator as an input to my custom indicator with something along the lines of this:

class testIndicatr:
'''
Custom Indicator info:
https://www.quantconnect.com/forum/discussion/3383/custom-indicator-in-python-algorithm
'''
def __init__(self, name):
self.Name = name
self.Time = datetime.min
self.Value = 0
self.IsReady = False
self.queue = deque(maxlen=2)
self.Last_Value = 0
self.Roc = QCAlgorithm.ROC(period=1, selector=Field.Close)


def __repr__(self):
return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value)

# Update method is mandatory
def Update(self, input):
# append left makes sure most recent value = [0]
self.queue.appendleft(input.Volume)
count = len(self.queue)
self.Time = input.EndTime
self.IsReady = count == self.queue.maxlen

Of course, this doesn't work. I am not sure I am approaching it in the correct way. 

The desired result is that the indicator can take a look at the ROC indicator value and use that to calculate the custom indicator. 

Any pointers would be greatly appreciated!

0

Hi Dave,

I'm also trying to make use of a built-in indicator (LWMA in my case) within my custom indicator, also quite lost. From your code I can only point out that putting the call to Roc where you have on line 13 won't do anything because there is no context about what the current data bar is (like there would be in the initial algorithm module 'main.py' that you start with). I had more luck putting my call to LWMA inside the 'Update' function. I believe the parameter passed to 'Update' is of type 'IBaseData', however it's not as simple as passing 'input.Close' to your Roc function... I also tried using 'Field.Close' here but it complained it was the wrong type. It turns out it actually needs a 'selector', so what you should type instead is something like: Func[IBaseData, Decimal](self.convert)

...and then write a separate function called 'convert(self, bar)' that takes the current IBaseData as input and returns a decimal. I figured this out from the 'IndicatorSuiteAlgorithm.py' example posted on this page:

https://www.quantconnect.com/docs/algorithm-reference/indicators

Hope this helps you... though I'm still stuck. This seems to satisfy the compiler but my LWMA values are just returning zeros. 

0

Alexandre,

I have cloned your code above and run it. I get the error below. I am running into the same error when creating my custom indicator. Do you know what's causing this?

I'd really appriciate any help with this. 

65435_1565375187.jpg

65435_1565375193.jpg

0

Hi Omid,

Thanks for pointing out the error. This is due to a recent refactor of custom indicator in Python on LEAN. Add return self.IsReady in the Update() function will solve the problem. The update function should look like this:

def Update(self, input):
self.queue.appendleft(input.Close)
count = len(self.queue)
self.Time = input.EndTime
self.Value = sum(self.queue) / count
self.IsReady = count == self.queue.maxlen
return self.IsReady

Thanks for your support!

2

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 Alethea, it worked!

0

Hi,

When I try to plot my custom python indicator I get this error:

 

Runtime Error: ArgumentException : QCAlgorithm.Plot(): The last argument should be a QuantConnect Indicator object, <class 'TSI.TrueStrengthIndex'> was provided.

Thank you in advance for your help!

0

I found a fix: Just need to add .Value to the argument given to Plot, like:

self.Plot("TSI", self.tsi.Value)

 

Also for the previous question of how to use another indicator in your custom indicator, what I did is:/
In __init__ put:
 

self.ema = ExponentialMovingAverage("Example EMA", 25)

Then in Update put:

self.ema.Update(IndicatorDataPoint(input.EndTime, input.Close))

Then you can use the value of that indicator to compute the value of your own indicator like this:

self.Value = 100 * self.ema.Current.Value

 

0

Seems it is not compatible with IndicatorExtensions.

When I do:

IndicatorExtensions.EMA(self.tsi, 13)

I get the following error:


During the algorithm initialization, the following exception has occurred: InvalidCastException : cannot convert object to target type
at Python.Runtime.PyObject.AsManagedObject (System.Type t) [0x00011] in <c56ab175820d412caf052e079c2ab9ef>:0
at QuantConnect.Indicators.IndicatorExtensions.EMA (Python.Runtime.PyObject left, System.Int32 period, System.Nullable`1[T] smoothingFactor, System.Boolean waitForFirstToReady) [0x00007] in <a16263fe48934e838e1ef015e10df92b>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0
at Initialize in main.py:line 35
InvalidCastException : cannot convert object to target type
at Python.Runtime.PyObject.AsManagedObject (System.Type t) [0x00011] in <c56ab175820d412caf052e079c2ab9ef>:0
at QuantConnect.Indicators.IndicatorExtensions.EMA (Python.Runtime.PyObject left, System.Int32 period, System.Nullable`1[T] smoothingFactor, System.Boolean waitForFirstToReady) [0x00007] in <a16263fe48934e838e1ef015e10df92b>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <b0e1ad7573a24fd5a9f2af9595e677e7>:0

 

0

I found the solution. Turns out there's a new way to make custom python indicators. It needs to look like this:

class CustomSimpleMovingAverage(PythonIndicator):
def __init__(self, name, period):
self.Name = name
self.Value = 0
self.queue = deque(maxlen=period)
# Update method is mandatory
def Update(self, input):
self.queue.appendleft(input.Value)
count = len(self.queue)
self.Value = sum(self.queue) / count
return count == self.queue.maxlen

Notice the PythonIndicator after the classname and notice that IsReady is gone (you must remove it). Instead Update method needs to return True once the indicator is ready.

Once the indicator is made that way, it will work will IndicatorExtensions as well as all other method which take an indicator.

0

Hi Bob,

Thanks for providing the solution. For completeness, I've attached an example backtest below.

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