Click to Show Menu

Creating an Indicator

cTrader Automate Indicators are used to aid in manual trading as well as be included in automated strategies (cBots) for indicating trends and providing signals for potential changes in trends. There have been a number of indicators developed over time by various statisticians and traders alike. Some of the most popular indicators are included in the platform as built-in indicators and some examples with source code can be found in the indicators tab. Custom indicators can be created using the code editor. Moreover, you may download custom indicators built by other users from the cTDN Indicators section.

Creating a new Indicator starts with adding a new Indicator template.

1. To add a new template into the code editor click New to the upper right of the Indicator tab. New Indicator will appear to the bottom of the cBots list.

You can rename your Indicator at any time by typing in the new name or by right-clicking the Indicator preview and selecting Rename from the drop-down menu. Alternatively, click on your Indicator and press F2.

The Indicator will be created with the code from the default code template:

// These namespaces are required for a cAlgo indicator.
// They contain basic classes of the C# language and the cAlgo API.
// The last namespace is required for referencing build-in
// indicators such as SimpleMovingAverage, BollingerBands, etc.

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;

// Define indicators within the cAlgo.Indicators namespace
namespace cAlgo.Indicators
{
    // The Indicator class declaration must be preceded by the indicator attribute,
    // [Indicator()], and it should be a public
    // Indicator derived class

    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC)]
    public class NewIndicator : Indicator
    {
        // The parameter attribute is necessary if the program will contain user input.
       [Parameter(DefaultValue = 0.0)]
       public double Parameter { get; set; }

       // The Output attribute is used to display the Output of
       // an Indicator series on the chart.
       [Output("Main")]
       public IndicatorDataSeries Result { get; set; }
       // The Initialize method is called upon loading of an indicator.
       // It is typically used to initialize variables and series such as nested indicators.
        protected override void Initialize()
        {
            // Initialize and create nested indicators
        }

        // The calculate method cannot be omitted.
        // It is the main method of an indicator.
        // It is called on each historical bar defined by the index and in real time on each incoming tick.
        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = ...
        }
   }

Initialize Method

The Initialize() method is used to initialize variables mainly such as indicators, data series, lists, etc. In general, any variables that need to be calculated only once on start-up should be in the initialize method in order not to consume unnecessary resources.

Calculate Method

The Calculate method is the main method of the indicator. It is called for each historic bar starting from the beginning of the series up to the current bar and then on each incoming tick. In the case of multi-symbol/multi-timeframe implementation, it will be called on each tick of each symbol that is used in the indicator.

It is typically used for the calculation of an indicator based on a formula. For example, it is the difference between the High and the Low prices of each bar. The index parameter represents each bar, ranging from 0 up to the current (last) bar. So, at each bar, the Calculate method will be called and the Result will be assigned with the difference between the High and the Low of that bar.

2. Edit your Indicator using the syntax from the Class View. When done click Build to save changes. You can find the examples of working Indicators below in the Indicators Code Samples section.

3. Now your new Indicator is ready. To start using it click the plus icon (+) and select a Symbol from the drop-down list or using the advanced search.

Alternatively, select Add Instance from the Indicator Quick Menu by clicking on the arrow or right-clicking on an Indicator. In this case, an instance with EURUSD symbol by default will be created.

The new instance of the Indicator will be added below. You can select another Symbol for the Indicator and change the Timeframe.

Also, you can change the Indicator output line type, thickness, or color (Main in the present example).

NaN Arithmetic

The following is the code of Detrended Price Oscillator:

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];
}

As you can see we just wrote a general rule for calculation but did not check any boundary conditions.

For example, if we use a moving average of 10 periods, the first 9 values can not be properly calculated. So we can not use this formula for any index less than 9. Moreover, to calculate the value for a specified index, we use moving average value at index – Periods / 2 – 1. So in general we have to add such condition:

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

The code of the simple moving average also has to check that index >= Periods. Moreover, if we use another nested indicator, for example, another type of moving average, this condition must be different. Source series also may be result of another indicator and contain not calculated values at the beginning. All of these things make indicators development more complex, as we have to think about things that can be automatically handled.

To solve this problem the NaN Arithmetic can be used. Let’s say, if an indicator value is not defined at specified index it has some special value, let’s call it “Not a number” – NaN. If we use this value in our calculation we always get NaN as a result. If we use not calculated value or value at a negative index from data series, we want it to be NaN.

Fortunately, type for floating numbers – double already has such value: double.NaN, and it has needed behavior. When you perform some operations with NaN and usual number you always get NaN, e.g double.NaN + 1.4 == double.NaN. Since DataSeries returns NaN when you request value at negative index, you can miss all these pre-conditions and implement just general indicator calculation rule. If the result contains NaN at some index, this value can just not be drawn on a chart.

Recursive indicators

When you calculate recursive indicator, i.e. indicator which value depends on previous value of this indicator, you must handle NaN values explicitly, for example here is exponential moving average calculation:

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);
    }
}

In EMA, where current value depends on the previous one, the first value must be set explicitly. To check this we use double.IsNaN(previousValue) method. Note that we cannot use == operator like this previousValue == double.IsNaN because NaN == x always false even if x is NaN.