Technical Indicators are used to aid in manual trading as well as be included in automated strategies by indicating trends and providing signals for potential changes in trend.
There have been a number of indicators developed over time by various statisticians and traders alike. Many of the most popular indicators are included in the platform as build in indicators.
Custom indicators maybe created using the cAlgo editor.
These indicators can be viewed in the cTrader as well as the cAlgo platforms. Moreover, you may download custom indicators build by other users from cTDN Indicators.
// 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.usingSystem;usingcAlgo.API;usingcAlgo.API.Internals;usingcAlgo.API.Indicators;// Define indicators within the cAlgo.Indicators namespacenamespacecAlgo.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)]publicclassNewIndicator:Indicator{// The parameter attribute is necessary if the program will contain user input. [Parameter(DefaultValue = 0.0)]publicdoubleParameter{get;set;}// The Output attribute is used to display the Output of // an Indicator series on the chart.[Output("Main")]publicIndicatorDataSeriesResult{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.protectedoverridevoidInitialize(){// Initialize and create nested indicators}// The calculate method cannot be ommited. // 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.publicoverridevoidCalculate(intindex){// Calculate value at specified index// Result[index] = ...}}}
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.
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. In this case, it is the difference of 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.
The High Minus Low Indicator calculates the difference between the current bar’s High and Low prices and displays this in an output series which is drawn on the chart as a line connecting the values at each bar.
The Indicator Attribute is required even if the properties in parenthesis are omitted, e.g.: [Indicator()].
As mentioned in the previous section the indicator must be an Indicator derived class:
1
publicclassMyIndicator:Indicator
The Output Attribute is applied to mark an IndicatorDataSeries as output to the chart. The property that is marked with the output attribute should be public so that it can be referenced from other classes.
As with the Indicator attribute, the Output attribute allows to specify characteristics such as:
The name will be displayed in the small panel that is displayed when you add an instance. From this panel you can change the other characteristics of the output, such as the color and line type.
IndicatorDataSeries is a list of doubles that can be indexed like an array. Hence, the value at each index in the list “Result” is assigned in the Calculate method as follows:
Most of the time indicators can vary according to user input. The Simple Moving Average is designed to accept as input parameters the price source and the period for the calculation.
Input must be preceded by the Parameter attribute like shown in the code below; the “Source” and the “Periods” properties are preceded by the Parameter attribute.
1 2 3 4 5 6 7 8 91011121314151617181920212223
publicclassSimpleMovingAverage:Indicator{[Parameter]publicDataSeriesSource{get;set;}[Parameter(DefaultValue = 14)]publicintPeriods{get;set;}[Output("Main", Color = Colors.Turquoise)]publicIndicatorDataSeriesResult{get;set;}publicoverridevoidCalculate(intindex){doublesum=0;for(vari=index-Periods+1;i<=index;i++){sum+=Source[i];}Result[index]=sum/Periods;}}
Like the Indicator and Output attributes discussed earlier, the Parameter attribute can define certain characteristics to the input:
In certain occasions it is necessary to use nested indicators. That is the value of one indicator depends on the value of other indicators. Such is the case with the SampeDeMarker indicator found in the platform.
When you use referenced indicators the referenced indicators are lazy loaded, it means the referenced indicator data is not calculated until you start using it's data.
If you access a referenced indicator Outputs data then cTrader starts loading the indicator data by calling it's Calculate method on past and future bars, otherwise the referenced indicator will be in idle and it will not consume any system resources.
If your indicator doesn't has any Output and you tried to access any of it's public properties you will get that property default value, to solve this issue you have to call the referenced indicator Calculate method manually from your own indicator Calculate method.
Levels can only be used when the indicator is not overlayed on the chart.
That is, the property IsOverlay is not set to true in the Indicator attribute like this: [Indicator("MyOscillator", IsOverlay = true)] This will not work.
IsOverlay is false by default so if it is omitted like in the following example the indicator will be displayed below the chart and the Levels will be displayed properly.
If multiple lines are necessary, then add a comma separated list of the values within the parenthesis.The following are some examples:
In certain cases we may need an indicator that requires to be calculated at the last bar.
Then, the IsLastBar property can be checked, to determine if as the name suggests, the index parameter of the Calculate method, is that of the last bar.
The following indicator displays the last open time in NY and Tokyo while the indicator is based on UTC time.
usingcAlgo.API;usingcAlgo.API.Indicators;usingSystem;namespacecAlgo{/// <summary>/// This indicator shows how to make a built-in cTrader indicator multi time frame and how to use cloud attribute/// </summary>[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None), Cloud("Top", "Bottom", Opacity = 0.2)]publicclassBollingerBandsMTFCloudSample:Indicator{privateBollingerBands_bollingerBands;privateBars_baseBars;[Parameter("Base TimeFrame", DefaultValue = "Daily")]publicTimeFrameBaseTimeFrame{get;set;}[Parameter("Source", DefaultValue = DataSeriesType.Close)]publicDataSeriesTypeDataSeriesType{get;set;}[Parameter("Periods", DefaultValue = 14, MinValue = 0)]publicintPeriods{get;set;}[Parameter("Standard Deviation", DefaultValue = 2, MinValue = 0)]publicdoubleStandardDeviation{get;set;}[Parameter("MA Type", DefaultValue = MovingAverageType.Simple)]publicMovingAverageTypeMaType{get;set;}[Output("Main", LineColor = "Yellow", PlotType = PlotType.Line, Thickness = 1)]publicIndicatorDataSeriesMain{get;set;}[Output("Top", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)]publicIndicatorDataSeriesTop{get;set;}[Output("Bottom", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)]publicIndicatorDataSeriesBottom{get;set;}protectedoverridevoidInitialize(){_baseBars=MarketData.GetBars(BaseTimeFrame);varbaseSeries=GetBaseSeries();_bollingerBands=Indicators.BollingerBands(baseSeries,Periods,StandardDeviation,MaType);}publicoverridevoidCalculate(intindex){varbaseIndex=_baseBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);Main[index]=_bollingerBands.Main[baseIndex];Top[index]=_bollingerBands.Top[baseIndex];Bottom[index]=_bollingerBands.Bottom[baseIndex];}privateDataSeriesGetBaseSeries(){switch(DataSeriesType){caseDataSeriesType.Open:return_baseBars.OpenPrices;caseDataSeriesType.High:return_baseBars.HighPrices;caseDataSeriesType.Low:return_baseBars.LowPrices;caseDataSeriesType.Close:return_baseBars.ClosePrices;default:thrownewArgumentOutOfRangeException("DataSeriesType");}}}publicenumDataSeriesType{Open,High,Low,Close}}
CloudAttribute constructor takes two output line names, and then it plots the cloud in between those outputs.
You can also set the opacity of cloud by using CloudAttribute Opacity property.
To set the cloud color you can use the FirstColor property of CloudAttribute, if you don't send the color then it will use the first output line color.
In Automate API there is a Color class, that you can use to set colors for chart objects, chart controls, and outputs.
The Color class contains several static properties for some of the most used colors that you can use without dealing with hexadecimal or color codes.
But to use custom colors you can use either their hexadecimal or ARGB codes.
For outputs you can set their Color by using their LineColor string property, you can use both named colors or hexadecimal color codes for LineColor property.
Let's see some code examples.
1234
_=Chart.DrawStaticText("NamedColor","This is text using Color class color name properties",VerticalAlignment.Center,HorizontalAlignment.Center,Color.Red);_=Chart.DrawStaticText("HexadecimalColor","This is text using Hexadecimal color",VerticalAlignment.Bottom,HorizontalAlignment.Center,Color.FromHex("#FF5733"));_=Chart.DrawStaticText("ARGBColor","This is text using ARGB color",VerticalAlignment.Top,HorizontalAlignment.Center,Color.FromArgb(255,200,100,60));_=Chart.DrawStaticText("ParsedNameColor","This is text using color name by parsing it from string",VerticalAlignment.Center,HorizontalAlignment.Left,Color.FromName("Yellow"));
1 2 3 4 5 6 7 8 910111213
varstackPanel=newStackPanel{Orientation=Orientation.Vertical,HorizontalAlignment=HorizontalAlignment.Center,VerticalAlignment=VerticalAlignment.Center};stackPanel.AddChild(newTextBlock{Text="Red Color property",BackgroundColor=Color.Red});stackPanel.AddChild(newTextBlock{Text="Hexadecimal Color code",BackgroundColor=Color.FromHex("#FF5733")});stackPanel.AddChild(newTextBlock{Text="ARGB Color",BackgroundColor=Color.FromArgb(200,100,40,80)});stackPanel.AddChild(newTextBlock{Text="Color Name",BackgroundColor=Color.FromName("Green")});Chart.AddControl(stackPanel);
If you get the color as input parameter from user then you have to use a string parameter as cTrader doesn't added a color parameter type yet, and then convert the user provided value to Color.
usingcAlgo.API;namespacecAlgo{[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]publicclassColorSample:Indicator{// User can use both color names or hexadecimal color codes[Parameter("Color", DefaultValue = "Blue")]publicstringColorString{get;set;}[Parameter("Color Alpha", DefaultValue = 255, MinValue = 0, MaxValue = 255)]publicintColorAlpha{get;set;}privateColor_color;protectedoverridevoidInitialize(){_color=GetColor(ColorString,ColorAlpha);Chart.ColorSettings.BackgroundColor=_color;}publicoverridevoidCalculate(intindex){}privateColorGetColor(stringcolorString,intalpha=255){varcolor=colorString[0]=='#'?Color.FromHex(colorString):Color.FromName(colorString);returnColor.FromArgb(alpha,color);}}}
IF you add the above parameter on an indicator/cBot you will see a multi option parameter that will allow you to select one of your Options Enum values.