Skip to main content Skip to footer

Indicator is one of the main concept of FinScript. It is an calculated information  based on price or volume which can be displayed on charts to help user with market analysis.

Basic concepts

To create an indicator user needs to create a class which should be inherited from one of the following classes:

  • VisualIndicatorOnBars - if it requires bars as an input data for indicator calculation;
  • VisualIndicatorOnSeries - if it requires only one series of double values as an input data for indicator calculation. This class has special parameter ParameterPriceType which defines price type to handle a case when instead of Series uses Bars as an input data.
  • VisualIndicatorOnNone - if it does not require any input data; 

The developer should set parameter CalculateMode in the constructor. This parameter determines how often the function of indicator calculation will be called. It can be one of the following:

  • OnEachTick - means that indicator calculation function will be called on every single tick;
  • OnPriceChange (default value) - means that indicator calculation function will be called once for for each price change;
  • OnBarOpen - means that indicator calculation function will be called only on new bar open;

Indicator can be located either on price chart or on separate panel. For managing it there is a parameter PlacementMode. It can take one of the following values:

  • PricePanel - draw indicator on the same panel as price chart;
  • SeparatePanel - draw indicator on separate panel;

There are 2 important properties which influence on indicator calculation

In order to have indicator displayed it needs to do the following:

1. Create a variable of special type Series which will store indicator calculated values. For example: private readonly Series<double> _main. 

2. Create a public property of type Plot or IPlot. For example  public IPlot Main {get;}. This property gives indicator users an access to read indicator series and change its display parameters.

3. In constructor it needs to inialize variable _main and property Main with help of using function AddPlot. The following snippet of the code shows how to do it:

var p=AddPlot("Main", new Stroke(Colors.Red, 1, DashStyle.Solid, 0), PlotStyle.Line);
_main = p.Values; Main = p.Plot;

All calculations of indicator values must perform in function OnCalculate

The following snippet of the code gathers together all above information and shows minimal necessary code for indicator creation.

using FinScript.Code;
    using FinScript.Rendering;
    using FinSysPlatform.Domain.Market.Data;
    using FinSysPlatform.Domain.Script;
    using System.ComponentModel.DataAnnotations;
    using System.Windows.Media;
    using FinSysPlatform.Domain.Script.Rendering;
    using FinSysPlatform.Domain.Market;
    using FinSysPlatform.Domain.Graphics;
    using FinScript.Data;
    using FinScript.StdLib.Indicators;
    using DashStyle = FinSysPlatform.Domain.Graphics.DashStyle;
    using Stroke = FinSysPlatform.Domain.Graphics.Stroke;

    namespace FinScript.CustomIndicators
    {
        /// <summary>
        /// SimpleInd
        /// </summary>
        [Unit(Name = "SimpleInd", Version = "1.0.0.0")]
        public class SimpleInd : VisualIndicatorOnBars
        {
             /// <summary>
            /// Writable internal buffer for <see cref="Main"/>
            /// </summary>
            private readonly Series<double> _main;

            /// <summary>
            /// Main
            /// </summary>
            public IPlot Main {get;}

            public SimpleInd()
            {
                CalculateMode = CalculateMode.OnEachTick;
                PlacementMode = ChartPanelUsing.PricePanel;

            var p=AddPlot("Main", new Stroke(Colors.Red, 1, DashStyle.Solid, 0), PlotStyle.Line);
                _main = p.Values; Main = p.Plot;
            }

            protected override void OnCalculate(CalculateContext ctx)
            {
                // Write your specific code to calculate indicator values
                ctx.Indexer(_main)[0] = 0;
                // or ctx.SetValue(_main, 0, 0);
                // or _main.SetValueAt(ctx.CurrentBarIndex, 0);
            }
         }
   }

User can track state of the indicator from setup, processing data, to termination. These states can be used for setting up or declaring various resources and properties. To do it user should use function OnStateChanged() 

protected override void OnStateChanged()
       {
             base.OnStateChanged();
              if (State == ScriptCalculationState.Configured)
              {
                     //Do something
              }
       }

Also there are other useful functions helping in indicator development:

If developer wants to have propeties which can be configured out of the code he should create public properties with special attribute. For example, the following code creates two properties Period and IsUseHighLow which can be set at the moment of placement indicator on chart.

[UnitProperty(Order=0, Name="Period", Description="Period", CategoryName="Parameters")]
public int Period { get; set; } = 1;

[UnitProperty(Name = "Use high-low", Order = 3)]
public bool IsUseHighLow { get; set; }

Developer is able to add horizontal line object on a chart using function AddLevel. The following example shows adding zero-level for Momentum indicator

public Momentum()
{
      _result = AddPlot(Resource.ScriptIndicatorNameMomentum, Colors.DarkCyan, useAutoColor: IndicatorPresetting.UsePlotAutoColorByDefault).Values;
      AddLevel(Resource.ScriptIndicatorZeroLine, Colors.SlateBlue, 0, true);
}

Also there is a property ChartBars which provides GUI access related methods and properties to the primary bars series configured on the Chart through the Data Series menu. This property can be useful if user wants to change color of bars. 

protected override void OnCalculate(CalculateContext ctx)
  {
            if (ChartBars != null)
            {
                var r = (byte)(ctx.CurrentBarIndex % 85);
                var g = (byte)(ctx.CurrentBarIndex % 170);
                var b = (byte)(ctx.CurrentBarIndex % 255);
                ChartBars.Fills.SetValueAt(ctx.CurrentBarIndex, new Argb(127, r, g, b));
                ChartBars.Strokes.SetValueAt(ctx.CurrentBarIndex, new Argb(255, r, g, b));
            }   
}

Also there is a possibility to add toolbar on a chart where user can place own buttons, checkboxes and other elements to manage some stuff. The following snippet of code shows how to do it

 private void AddToolBar()
        {
            var toolBar = ChartControl?.GetCustomToolbar(this);

            if (toolBar != null)
            {
                #region Check Box

                var stopOpeningCheckBox = toolBar.AddCheckBox();
                stopOpeningCheckBox.Caption = "Check box example";
                stopOpeningCheckBox.IsChecked = true;
                stopOpeningCheckBox.Command = new Command(delegate { MessageBox.Show($"Current state: {stopOpeningCheckBox.IsChecked}"); });
                stopOpeningCheckBox.Hint = "This is check box";

                #endregion

                #region

                var dropDownButton = toolBar.AddSubMenu();
                dropDownButton.Caption = "Sub Menu";
                dropDownButton.Hint = "This is submenu";

                var item1 = dropDownButton.AddButton();
                item1.Caption = "Sub Item 1";

                var item2 = dropDownButton.AddCheckBox();
                item2.Caption = "Sub Item 1";

                #endregion

                #region Trader Button

                var tradeButton = toolBar.AddButton();
                tradeButton.Hint = "Open Trader Window to send orders in manual mode";
                tradeButton.Caption = "Trader";

                tradeButton.Command = new Command(delegate
                {
                    var window = CreateChildWindow();
                    window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                    window.Title = "Trader";
                    window.Height = 400;
                    window.Width = 600;
                    window.Content = new TraderView(window, this);
                    window.Show();
                });

                #endregion
            }
        }

Cookies Notice

We use cookies to improve your experience, personalize content, and analyze our traffic. By clicking "Accept All Cookies," you agree to the storing of cookies on your device. You can manage your cookie preferences at any time by visiting our Cookie Settings.