Skip to content

Create a technical indicator in cTrader

This article outlines the steps to create custom technical indicators, including tools for algorithmic trading or manual actions in cTrader.

In the Indicators tab of the Algo app, click the New button to open the algorithm creation wizard.

Enter a name for your indicator, then select a programming language between C# and Python.

Choose a creation method from:

  • From scratch – the new indicator will contain only a basic template.

  • Using a template – you will be able to select a premade algorithm from a list of Python# or C# templates, covering a wide range of indicator types, technical analysis tools and more.

Note

Premade algorithms already contain logic for calculations and customisable parameters. Such indicators are ready to be displayed on charts once you save and build them.

After you click Create, the code editor opens and you can start editing the indicator code.

Edit the code

Depending on your creation method, the indicator code sample should contain one or more of the following elements:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Indicator(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SimpleIndicator : Indicator
{
    [Parameter(DefaultValue = "Hello world!")]
    public string Message { get; set; }

    [Output("Main")]
    public IndicatorDataSeries Result { get; set; }

    protected override void Initialize()
    {
    // Called once when the indicator is launched
    // Initialise variables, nested indicators or series

        Print(Message);
    }

    public override void Calculate(int index)
    {
    // Called automatically on each historical bar
    // Also called in real-time on each tick
    // Place the indicator formula and logic here
    }

    // === Custom Methods ===
    // Add helper methods below to structure your indicator logic

}

The Indicator attribute, along with its optional properties such as TimeZone and AccessRights, precedes the indicator class (SimpleIndicator) declaration.

These methods are included in every indicator by default:

  • The Initialize() method is invoked once when your indicator starts. It is typically used to set up variables, nested indicators and series that need to be ready from the beginning.
  • The Calculate() method is invoked automatically on each historical bar and in real-time on every new tick. This is where you implement the indicator’s formula and define how results are calculated and displayed.

The [Output()] attribute specifies the values your indicator produces and how they appear on the chart. You can customise the name and style of each output, for example by setting its line colour.

The Initialize() and Calculate() methods form the foundation of every custom indicator and should never be omitted. You can add your own methods to extend functionality, just as you would when coding a cBot. To learn more about algorithms, begin with the C# basics guide and explore indicator code examples.

Note

References includes all classes, events, methods, variables, etc. for building algorithms in cTrader, while full algorithm examples and templates are available in a GitHub repository.

Apply your new knowledge to edit the indicator code and adapt it to your needs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class SimpleIndicator:
    def initialize(self):
        # Called once when the indicator is launched
        # Initialise variables, nested indicators or series
        api.Print(api.Message)

    def calculate(self, index):
        # Called automatically on each historical bar
        # Also called in real-time on each tick
        # Place the indicator formula and logic here
        api.Result[index] = 100 # Example calculation

    # === Custom Methods ===
    # Add helper methods below to structure your indicator logic

The SimpleIndicator class defines a custom indicator in Python.

These methods are included in every indicator by default:

  • The initialize(self) method is invoked once when your indicator starts. It is typically used to initialise variables, nested indicators and series that need to be ready from the beginning.
  • The calculate(self, index) method is invoked automatically on each historical bar and in real time on every new tick. This is where you implement the indicator’s formula and define how results are calculated and displayed.

The initialize(self) and calculate(self, index) methods form the foundation of every custom indicator and should never be omitted. You can also add your own helper methods inside the class to extend functionality, just as you would when coding a cBot. To learn more about algorithms, begin with Python basics and explore indicator code examples.

Apply your new knowledge to edit the indicator code and adapt it to your needs.

Save and build

Save your code by clicking the Save button at the top of the code editor or use the Ctrl+S shortcut.

Before you can use your indicator, you need to validate its code by building the indicator project. Click the Build button at the top of the code editor or press Ctrl+B.

Save your code by clicking the Save icon at the top of the code editor or use the Cmd+S shortcut.

Before you can use your indicator, you need to validate its code by building the indicator project. Click the Build icon at the top of the code editor or press Cmd+B.

When the build succeeds, you see a confirmation message in Build result. If the build fails, a summary of all errors encountered appears instead.

If there are changes to the code since the last build, an asterisk appears next to the Build icon. In this case, you should build the indicator again before adding an instance of it to any chart.

To use or display the indicator on a chart, add an instance of it, or you can continue modifying the indicator code as explained in the sections.

Use NaN arithmetic

Indicators perform calculations to output specific visuals, and it is essential that your code correctly handles fringe cases and boundary conditions during these calculations.

Consider the following snippet from an indicator that outputs a detrended price oscillator:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private MovingAverage movingAverage;

protected override void Initialize()
{
    movingAverage = Indicators.SimpleMovingAverage(Source, Periods);
}

public override void Calculate(int index)
{
    Result[index] = Source[index] - movingAverage.Result[index - Periods / 2 - 1];
}

The code above defines general calculation rules but omits boundary conditions. For example, if Periods is set to 10 and index falls within the range 0–9, the calculation will return NaN (Not a Number). This issue occurs because the indicator cannot calculate values for a bar chart with a negative index.

To address the problem, you can add a condition as shown below:

1
2
3
4
5
6
7
public override void Calculate(int index)
{
    if (index >= Periods + Periods / 2 + 1)
    {
        Result[index] = Source[index] - movingAverage.Result[index - Periods / 2 - 1];
    }
}

The code for the simple moving average itself must also check that index >= Periods. If you use a nested indicator, such as another type of moving average, the condition will differ to account for additional calculations.

Although you can define explicit boundary conditions, C# offers a convenient way to avoid these issues through NaN arithmetic. Specifically, the double data type fully supports NaN calculations. For example:

1
2
3
4
5
double result = double.NaN + 1.4; 
// result will be NaN

bool isNaN = double.IsNaN(result); 
// isNaN will be true

However, when any operand in a calculation is NaN, the result will also be NaN. As custom cTrader indicators operate on the DataSeries type, if you attempt to access a DataSeries element with a negative index, it will return NaN, and the value will not be drawn on the trading chart. This behaviour allows the indicator to continue operating without throwing exceptions. In most cases, you can safely ignore boundary conditions and focus only on the general calculation logic.

Add explicit checks

While NaN arithmetic simplify handling boundary conditions, some cases still require explicit NaN checks. Recursive indicators are a common example. A recursive indicator calculates its current value based on the previously calculated value.

Consider the following implementation of an exponential moving average:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public override void Calculate(int index)
{
    var previousValue = Result[index - 1];

    if (double.IsNaN(previousValue))
    {
        Result[index] = Source[index];
    }
    else
    {
        Result[index] = Source[index] * _exp + previousValue * (1 - _exp);
    }
}

When the indicator calculates the first period, the initial value must be explicitly set to a non-NaN type. Otherwise, all subsequent calculations will return NaN, rendering the indicator useless.

In the code above, this is handled with the double.IsNaN(previousValue) method. The == operator cannot be used for this check (previousValue == double.NaN) because any comparison of NaN with another value, including itself, always evaluates to false.

When you are satisfied with the indicator code, build it, then use it by adding an instance to a chart.

Image title