TakeProfit logo CommunityPlatform


To get you started quickly, let's write some indicators, starting with simple examples and gradually moving on to more complex ones.

Minimal indicator

Here is a minimal indicator for TakeProfit, which simply plots the 'close' price of the current chart instrument as a solid line:

# indie:lang_version = 2
from indie import indicator

@indicator('Example 1')
def main(ctx):
    return ctx.close[0]

Let us take a closer look to what is happening in this example. First of all, the entry point of every indicator is the main function (it must be named main to keep all things in a 'standardised' way). The main function is a function that is called per every candle of a chart instrument from left to right and after that it is continued to be called on every realtime update of the last (rightmost) candle. To sum up, it returns an indicator value for every candle of the main instrument context.

Context, another new term (represented by a ctx parameter of main function) is a representaion of a current instrument displayed on a candle chart, with all it's prices (open, high, low, close, volume, etc.), some state and any other possible attributes it may have. In our example we take a series of close prices ctx.close and apply a square brackets operator to it, to get the last (most recent) value of that price: ctx.close[0]. Zero offset always corresponds to the last value (value on the last candle). Offset 1 corresponds to the value of the previous candle and so on.

Our main function is decorated with a required @indicator decorator with a required title param (title is the first param of this decorator, but you may write it in a kwarg form: @indicator(title='Example 1')). In general, decorators (things which names start with a @ character) provide meta-information about indicators to TakeProfit's runtime. Meta-information describes indicator in some way, we will see a lot of this further.

Finally, please note, that we have to import symbols like indicator, because they are not a part of Indie's built-in symbols. For now, the list of things that are allowed to be imported in the indicator code is very limited. But as the platform grows, the library will be expanded accordingly.

After you type (or better copy-paste) the above code into the Code Editor (which is a widget and it should be added to your workspace first as More Widgets -> Indicators Code Editor) click on the button Add to Chart. As you can see, the indicator was added on a separate pane, below the main pane with candle chart.

Figure 1.1. The minimal indicator.
Figure 1.1. The minimal indicator.

Overlay main pane

If we want to add our indicator as an overlay on candle chart, we may add overlay_main_pane=True param to the @indicator decorator:

# indie:lang_version = 2
from indie import indicator

@indicator('Example 2', overlay_main_pane=True)
def main(ctx):
    return ctx.close[0]
Figure 1.2. Indicator which overlays the main pane with the candle chart.
Figure 1.2. Indicator which overlays the main pane with the candle chart.

Apply the SMA algorithm

TakeProfit has a library of standard algorithms, such as Simple Moving Average (SMA), let us import and use it:

# indie:lang_version = 2
from indie import indicator
from indie.algorithm import sma

@indicator('Example 3', overlay_main_pane=True)
def main(ctx):
    s = sma(ctx.close, 12)
    return s[0]
Figure 1.3. Usage of the SMA algorithm from the standard library.
Figure 1.3. Usage of the SMA algorithm from the standard library.

There are two essential parts that make it work: 1) import of the sma algorithm from package indie.algoritm and 2) invocation of sma in the indicator's code: sma(ctx.close, 12). Algorithms that process series of prices (like ctx.close) usually return series of numeric values (variable s).

Let us make our indicator more interesting and calculate two SMAs with different lengths:

# indie:lang_version = 2
from indie import indicator
from indie.algorithm import sma

@indicator('Example 4', overlay_main_pane=True)
def main(ctx):
    l = sma(ctx.close, 42)
    s = sma(ctx.close, 12)
    return l[0], s[0]

This indicator returns a tuple consisting of two values: l[0] and s[0], that is why it plots two lines.

Figure 1.4. Long and short SMAs in one indicator.
Figure 1.4. Long and short SMAs in one indicator.

Plot with different colors

There are two different ways to colorize indicator's plot lines. First one is to use one single color for the whole plot. In such a way, colors are actually not involved in calculation over the candle prices, they are part of indicator's meta-information. We use @plot decorator for such way of coloring:

# indie:lang_version = 2
from indie import indicator, color, plot
from indie.algorithm import sma

@indicator('Example 5', overlay_main_pane=True)
@plot(color=color.GRAY)
@plot(color=color.WHITE)
def main(ctx):
    l = sma(ctx.close, 42)
    s = sma(ctx.close, 12)
    return l[0], s[0]
Figure 1.5. Applying different colors to the plots of indicator.
Figure 1.5. Applying different colors to the plots of indicator.

What if we would like to make a multicolored plot line? We may want to calculate the color depending on the candle prices data. If so, we would return from main function not plain numbers, but Plot objects:

# indie:lang_version = 2
from indie import indicator, color, plot, Plot
from indie.algorithm import sma

@indicator('Example 6', overlay_main_pane=True)
@plot(color=color.GRAY)
def main(ctx):
    l = sma(ctx.close, 42)
    s = sma(ctx.close, 12)
    s_color = color.GREEN if s[0] > l[0] else color.RED
    return l[0], Plot(s[0], color=s_color)
Figure 1.6. Example of a dynamically colored plot (with red and green).
Figure 1.6. Example of a dynamically colored plot (with red and green).

Input parameters

It would be better not to hardcode the lengths of our two SMAs (literal constants 42 and 12) but instead use named parameters. Named parameters are very convenient because they can be modified in the indicator's Settings panel. For this purpose there are a whole set of decorators, starting with @param. prefix, for example: @param.int, @param.bool, @param.string and so on. Let us incorporate them in our example indicator:

# indie:lang_version = 2
from indie import indicator, color, plot, Plot, param
from indie.algorithm import sma

@indicator('Example 7', overlay_main_pane=True)
@param.int('long_length', default=42)
@param.int('short_length', default=12)
@plot(color=color.GRAY)
def main(ctx, long_length, short_length):
    l = sma(ctx.close, long_length)
    s = sma(ctx.close, short_length)
    s_color = color.GREEN if s[0] > l[0] else color.RED
    return l[0], Plot(s[0], color=s_color)
Figure 1.7. Indicator with integer input parameters.
Figure 1.7. Indicator with integer input parameters.