cTrader Automate Custom Indicators — Coding Basics

If you have already read our cTrader platform review, it is now time to explore possibilities offered by cTrader Automate — an algorithmic trading part of the platform. Here, you will find the basic programming language constructions that are used to code custom indicators. You will also go through a sample source code with a detailed explanation of how it works, so that you could create your own cTrader indicators.

cTrader Automate

cTrader Automate (previously called cAlgo) is now a part of the normal cTrader installation and offers quite a few examples of both indicators and robots. There are also hundreds of algorithms available from cTrader website. You can also find there cTrader reference documentations, including some guides to coding.

As the trading platform uses C# for the algorithm coding, you can expect some level of familiarity with the code if you have any experience with C#. Unfortunately, you will find that for some of the APIs and classes specific to trading, the explanations or descriptions in the official documentation are lacking.

Custom indicator structure

Basically, each custom indicator's code can be divided into the following sections:

  • Declaration of necessary namespaces
  • Creation of indicator's class:
    • Definition of input parameters
    • Definition of outputs
    • Declaration of supplementary objects
    • Implementation of Initialize() function
    • Implementation of Calculate() function
    • Implementation of additional functions

Necessary namespaces

The namespaces you will need are defined within the main cAlgo.API namespace. Any custom indicator requires cAlgo.API namespace to work. Additionally, cAlgo.API.Indicators namespace can be loaded to work with standard indicators inside your custom indicator's code.

Standard C# namespaces (such as System or System.Timers) may be employed if you wish to access their classes.

Indicator's class

An indicator should be declared inside a special cAlgo.Indicators namespace. [Indicator] attribute is necessary for the indicator class declaration. Additionally, this attribute can define some optional properties of the indicator:

  • a text name for display in cTrader;
  • IsOverlay property that can be set to true if you want to display indicator in the main chart window; otherwise, it will be displayed in a separate indicator window below the main one;
  • ScalePrecision that sets the number of decimal places for the indicator output;
  • AutoRescale, which can be set to true for the indicator to rescale the chart automatically.
  • TimeZone — sets the time zone of the indicator.

There is also an optional [Levels] attribute that can be used to set custom level lines for the separate window indicator. For example, 30 and 70 for the RSI indicator.

Here is the standard beginning of declaration:

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true)]
    public class GrailIndicator : Indicator
    {

Input parameters

It is not necessary for the indicator to have input parameters. Each declared parameter needs a [Parameter] attribute. This attribute can be used to set input parameters properties, such as the text name (as it appears to users), default value, minimum and maximum values. Each parameter is then declared as a public class member. { get; set; } accessors should be applied to an input parameter if you want users to see and modify its value (and why else would you declare it as an input parameter?) A cTrader custom indicator can have as many input parameters as you need.

        [Parameter(DefaultValue = 14, MinValue = 2)]
        public int Periods { get; set; }

Outputs

An indicator can have zero to any number of outputs. An output is the result of the indicator's execution and it is what is displayed on the chart. For example, a moving average's output is a line. It is an analogue of plot in MetaTrader. An output is declared as a public class member with the same { get; set; } accessors as an input parameters, but with a different attribute - [Output]. This attribute can set such properties as text name, color, and plot type (line, histogram, etc.), line style (dots, solid, etc.), and thickness.

        [Output("Result", LineColor = "Orange")]
        public IndicatorDataSeries Result { get; set; }

Supplementary objects

This section is optional, but any more or less useful indicator will need extra objects to calculate its output. Such objects could be other indicators - e.g., if you want to code an indicator based on an MA, you do not need to write your own code of a moving average, but rather declare a moving average object inside your indicator class:

        private MovingAverage movingAverage;

It could be a simple variable used throughout the methods of your class:

        private double exp;

Or some special kind of data series (for example, median or typical price):

        private TypicalPrice typical;

Or some standard C# object:

        private readonly Timer _timer = new Timer();

Initialize()

The Initialize() method is a standard function called by cTrader when the indicator is attached to a chart. The best use for it is to calculate values that become known upon indicator initialization and do not change later (for instance, input parameters):

        protected override void Initialize()
        {
            exp = 2.0 / (Periods + 1);
        }

Or to assign standard indicators if they were declared earlier:

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

Since Initialize() is a standard method of a basic Indicator class, the override modifier is required when you replace it with your own implementation.

Calculate()

Calculate() is also a standard method of the cTrader Indicator class. It is called on each tick and is equal to start() of MetaTrader 4 and to OnCalculate() of MetaTrader 5. It is the main subroutine of a custom indicator. It has one parameter - int index, which represents the number of the bar being processed. By the way, the chart bars are ordered from left to right in cTrader - the oldest bar has the index of 0, while the newest bar has the highest index.

The implementation of Calculate() is the right place to assign values to the previously declared outputs:

        public override void Calculate(int index)
        {
            Result[index] = MarketSeries.Low[index] - movingAverage.Result[index];        
        }

Notice how the code snippet above uses the Result output of the previously declared moving average object. It also uses a standard cAlgo object for data series - MarketSeries (in this case, Low price is retrieved.)

Additional functions

Any other language constructs (functions or event handlers) you might need to code a cTrader custom indicator are put inside the class implementation.

For example, this event handler that is called on a timer event:

        private void OnTimedEvent(object sender, ElapsedEventArgs e)
        {
            //...
        }

Or this factorial function:

        private void Factorial(int n)
        {
            if (n == 1) return 1;
            return n * Factorial(n - 1);
        }

Sample indicator code explained

Now that you know the parts that compose a generic custom indicator in cTrader Automate, let's look at a sample indicator code with detailed explanation of every statement. The following code is a Sample EMA Indicator that is included in the cAlgo installation. It was coded by Spotware to demonstrate the exponential moving average calculation. My explanations are given in a form of code commentary just above each statement:

// Adds System namespace to the code's scope. 
// It is not required here because none of its names are used.
using System;
// Basic cAlgo API namepsace that contains pretty everything used in this 
// (or any other) custom indicator.
using cAlgo.API;
// Contains declarations of the standard indicators.
using cAlgo.API.Indicators;

// Adds the next indicator class declaration to cAlgo indicators' namespace.
namespace cAlgo.Indicators
{
    // Attribute that tells cAlgo that the next declaration is an indicator. 
    // IsOverlay is set to true to display indicator directly in the main chart window.
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    // Indicator class declaration.
    // The new class is called SampleEMA and it is derived from basic Indicator class.
    public class SampleEMA : Indicator
    {
        // Parameter attribute tells cAlgo that the next declaration is an input parameter.
        [Parameter]
        // The input parameter is called Source and it is a data series. 
        // It can be either some kind of price or an output from another indicator.
        // { get; set; } modifiers allow user modification of the input parameter.
        public DataSeries Source { get; set; }

        // This Parameter attribute uses DefaultValue property to set 
        // Periods input parameter to 14 as default.
        [Parameter(DefaultValue = 14)]
        // Periods input parameter of type integer.
        public int Periods { get; set; }

        // Output attribute that tells cAlgo to use the next declaration as indicator's output. 
        // It also uses properties to set output's name to Main and color to Turquoise.
        [Output("Main", LineColor = "Turquoise")]
        // Result output is of the type IndicatorDataSeries.
        public IndicatorDataSeries Result { get; set; }

        // Variable exp of type 'double' declared to be accessible 
        // in every member of the indicator class.
        private double exp;

        // Standard initialization function declaration. 
        // Override keyword is used to 'overwrite' the Initialize() declaration of Indicator class, 
        // which this custom indicator class is derived from.
        protected override void Initialize()
        {
            // Since Periods becomes known right after indicator attachment 
            // and does not change during the runtime, it is safe to calculate exp value here.
            exp = 2.0 / (Periods + 1);
        }

        // Declaration of standard indicator calculation function. It will be called every tick.
        public override void Calculate(int index)
        {
            // Get the value of the indicator calculated at previous bar.
            var previousValue = Result[index - 1];

            // If this value is not a number (NaN)
            if (double.IsNaN(previousValue))
            {
                // Assign the unaltered source data (price or whatever the indicator 
                // is attached to) to the output.
                Result[index] = Source[index];
            }
            // Otherwise
            else
            {
                // Calculate the output value using standard exponential moving average formula
                // and the constant calculated at initialization.
                Result[index] = Source[index] * exp + previousValue * (1 - exp);
            }
        }
    }
}

Try coding your own indicator

As you can see, there is nothing too difficult in the process of creation of your custom indicators for cTrader via its Automate module. It also looks much simpler than in MetaTrader 5, for example, lacking the peculiarities of MQL5 language. At the same time, C# is a popular enough language, which is known to many Forex traders.

Now you know enough to modify any of the bundled custom indicators and to create a completely new one from scratch. If it does not contain any errors, after building your indicator, you will be able to attach it to cTrader charts. Consider sharing your custom indicators on cTrader community website. You can also download a lot of example indicators from there.

If you are interested to learn more about programming for cTrader, you will also enjoy our guide on the basics of robot coding in cTrader Automate.

If you have some questions about coding custom indicators for cTrader using the Automate module of the trading platform you can discuss them on our forum on trading platforms.


If you want to get news of the most recent updates to our guides or anything else related to Forex trading, you can subscribe to our monthly newsletter.

© 2005–2021

EarnForex.com

Design — Mart Studio

Forex trading bears intrinsic risks of loss. You must understand that Forex trading, while potentially profitable, can make you lose your money. Never trade with the money that you cannot afford to lose! Trading with leverage can wipe your account even faster.

CFDs are leveraged products and as such loses may be more than the initial invested capital. Trading in CFDs carry a high level of risk thus may not be appropriate for all investors.