Besides importing other scripts we can also make our own scripts in the PowerLanguage .NET Editor. How do we create an indicator in MultiCharts .NET?

The PowerLanguage .NET Editor and creating indicators

The PowerLanguage .NET Editor is the primary tool for creating and editing MultiCharts .NET indicators, strategies, and functions (MultiCharts, 2014). Operations we can do in the PowerLanguage .NET Editor include exporting, editing, and removing scripts. All of those things, however, require that we have a script to work with.

We can make three types of scripts in the PowerLanguage .NET Editor: trading strategies, functions, and indicators. Indicators are typically used as a visual technical analysis tool that displays its calculated values with a plot like a line or histogram (MultiCharts Wiki, 2013), but indicators can also draw trend lines, arrows, and text boxes. Let’s see how we can create an indicator in MultiCharts .NET.

Creating an indicator in the PowerLanguage .NET Editor

To make a MultiCharts .NET indicator, we first start the PowerLanguage .NET Editor and then click on the small, downward pointing arrow besides the ‘New Study’ toolbar button ( ). We then select ‘New Indicator…’:

Create new script in the PowerLanguage .NET Editor

That brings up a window where we need to specify the indicator’s name and programming language. Let’s name our example indicator ‘Volume_Strength’ and set its language to C#. Then click ‘Ok’:

New Indicator Name window

We’re then presented with our indicator in the PowerLanguage .NET Editor:

New MultiCharts .NET indicator created

The default layout of a new MultiCharts .NET indicator

Our new indicator, just like all new MultiCharts .NET indicators, has the following code template to program our logic in:

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator{
    public class Volume_Strength : IndicatorObject {
        public Volume_Strength(object _ctx):base(_ctx){}
        private IPlotObject plot1;
        protected override void Create() {
            // create variable objects, function objects, plot objects etc.
            plot1 = AddPlot(new PlotAttributes("", EPlotShapes.Line, Color.Red));
        }
        protected override void StartCalc() {
            // assign inputs 
        }
        protected override void CalcBar(){
            // indicator logic 
            plot1.Set(Bars.Close[0]);
        }
    }
}

Personally, I find this default formatting very sloppy and so use Enter to structure the code like this:

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
    public class Volume_Strength : IndicatorObject
    {
        public Volume_Strength(object _ctx) : base(_ctx) { }

        private IPlotObject plot1;
        
        protected override void Create()
        {
            // create variable objects, function objects, plot objects etc.
            plot1 = AddPlot(new PlotAttributes("", EPlotShapes.Line, Color.Red));
        }

        protected override void StartCalc()
        {
            // assign inputs 
        }

        protected override void CalcBar()
        {
            // indicator logic 
            plot1.Set(Bars.Close[0]);
        }
    }
}

Now that we have a code template that’s easier to read, we can add the additional code that’s needed to implement the indicator.

Coding an example indicator in the PowerLanguage .NET Editor

This article’s example indicator has the following features:

  • Two inputs that set the length of two Exponential Moving Averages (EMAs).
  • Both EMAs are based on the instrument’s volume data.
  • The EMAs are plotted in the indicator’s subchart.
  • And a histogram shows the difference between both EMAs.

Let’s examine how to implement these four characteristics programmatically.

Adding user-definable inputs to a MultiCharts .NET indicator

Inputs allow for changing an indicator’s settings easily without having to edit and recompile the source code. We add inputs to a MultiCharts .NET indicator or trading strategy by placing the [Input] attribute just above a public property (MultiCharts, 2014). We place inputs typically at the top of the class file like so:

// Create the indicator's inputs
[Input]
public int ShortEMA { get; set; }

[Input]
public int LongEMA { get; set; }

We then need to give the inputs a default value. That way the indicator can always calculate when it’s added to a chart. Setting default values of inputs is done in the constructor (MultiCharts, 2014), which is a method that has the same name as the class (Sharp, 2013). In our case, we set ShortEMA and LongEMA to default values of 12 and 33 in the Volume_Strength() constructor:

public Volume_Strength(object _ctx) : base(_ctx) 
{
    // Set the inputs to their default values
    ShortEMA = 12;
    LongEMA  = 33;
}

Creating the plots and EMAs in the MultiCharts .NET script

In the next part we create plot and EMA instances so that we can use these in the indicator’s code. We first declare three IPlotObject variables (emaShortLong, emaLongLine, and emaDiffHist) and two XAverage variables (longEMA and shortEMA):

// Declare the plots and EMA functions
private IPlotObject emaShortLine, emaLongLine, emaDiffHist;
private XAverage longEMA, shortEMA;

Now we need to create instances of these (currently empty) objects, which we do in the Create() method. That method is executed one time, immediately after the indicator is added to a chart or Scanner/Watchlist window (see MultiCharts, 2014). In our example’s Create() method we do the following:

protected override void Create()
{
    // Create the plots
    emaShortLine = AddPlot(new PlotAttributes(
        "EMA Short", EPlotShapes.Line, Color.Blue));

    emaLongLine = AddPlot(new PlotAttributes(
        "EMA Long", EPlotShapes.Line, Color.Orange));

    emaDiffHist = AddPlot(new PlotAttributes(
        "EMA Difference", EPlotShapes.Histogram, Color.Red, 
        Color.Transparent, 3, EPlotStyle.Solid, false));

    // Create the moving averages
    longEMA  = new XAverage(this);
    shortEMA = new XAverage(this);
}

We first add three plots to the chart with AddPlot() and, inside that method, we use PlotAttributes() to set the plot’s properties (PowerLanguage .NET Help, n.d.). The first plot, which we name "EMA Short", is set to a line (EPlotShapes.Line) plotted in blue (Color.Blue). The second line ("EMA Long") is also a line but coloured orange (Color.Orange).

The last plot ("EMA Difference") is set to a histogram (EPlotShapes.Histogram) with a red foreground colour (Color.Red) and a transparent background colour (Color.Transparent). Its width is 3, its bars are solid (EPlotStyle.Solid), and the false Boolean ensures that the last price marker on the indicator’s price axis doesn’t display.

After that we create two instances of the XAverage class with C#’s new keyword. But we need to define their settings before we can use them.

Setting the options of moving averages in MultiCharts .NET

We set those EMA settings in StartCalc(). That method is executed once before the indicator calculates itself on all price bars (MultiCharts, 2014). In this method we set both the EMA length and the data they’re based on:

protected override void StartCalc()
{
    // Specify the moving averages' settings
    longEMA.Length = LongEMA;
    longEMA.Price  = Bars.Volume;

    shortEMA.Length = ShortEMA;
    shortEMA.Price  = Bars.Volume;
}

The length of the longEMA function is set to the LongEMA input (which we gave a default value of 33 earlier). Its “price” (meaning, the data series that the EMA is calculated on) is set to Bars.Volume. That way the EMA is calculated on the volume of the primary data series (see MultiCharts, 2014).

Similarly, the length of the shortEMA function is set to the ShortEMA input and the data it calculates on is set to Bars.Volume. Since we use the inputs to set the lengths of both EMAs, changing them in the indicator’s settings (see image below) will change the EMA periods also.

Now that we’ve created the plots and specified the EMA settings it’s time to plot the lines themselves. We do that in the CalcBar() method.

Plotting the indicator values on every bar

The CalcBar() method is the last part of our example. This method is executed once on every historical bar and once for each real-time tick of the last bar (when update on every tick is on) (MultiCharts, 2014; MultiCharts Wiki, 2014). In this method we do the actual plotting:

protected override void CalcBar()
{
    // Set the plots
    emaShortLine.Set(shortEMA[0]);
    emaLongLine.Set(longEMA[0]);
    emaDiffHist.Set(shortEMA[0] - longEMA[0]);
}

We display the plots on the chart by calling their Set() method and passing in the value that the plot should display for that bar (see PowerLanguage .NET Help, n.d.). So for the emaShortLine plot we call Set() and inside this method we type shortEMA[0], which is the instance of the EMA function we’ve created earlier. And with the zero between square brackets ([ and ]) it returns the EMA value for the current bar. Since we set the plot’s value each time CalcBar() executes (which is on every bar), the plot value is updated and after several bars the plot is a consecutive line of values.

We do the same for the emaLongLine plot, except that here we call the Set() method with longEMA[0] passed in. The histogram plot (emaDiffHist) is set to the difference between the long and short EMAs. That way the histogram displays positive values when the quicker EMA is above the slower EMA, and negative values when the short EMA has crossed below the long EMA.

Full code of the MultiCharts .NET example indicator

After implementing the four steps above, the complete indicator’s code is:

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
    public class Volume_Strength : IndicatorObject
    {
        // Create the indicator's inputs
        [Input]
        public int ShortEMA { get; set; }

        [Input]
        public int LongEMA { get; set; }

        public Volume_Strength(object _ctx) : base(_ctx) 
        {
            // Set the inputs to their default values
            ShortEMA = 12;
            LongEMA  = 33;
        }

        // Declare the plots and EMA functions
        private IPlotObject emaShortLine, emaLongLine, emaDiffHist;
        private XAverage longEMA, shortEMA;
        
        protected override void Create()
        {
            // Create the plots
            emaShortLine = AddPlot(new PlotAttributes(
                "EMA Short", EPlotShapes.Line, Color.Blue));

            emaLongLine = AddPlot(new PlotAttributes(
                "EMA Long", EPlotShapes.Line, Color.Orange));

            emaDiffHist = AddPlot(new PlotAttributes(
                "EMA Difference", EPlotShapes.Histogram, Color.Red, 
                Color.Transparent, 3, EPlotStyle.Solid, false));

            // Create the moving averages
            longEMA  = new XAverage(this);
            shortEMA = new XAverage(this);
        }

        protected override void StartCalc()
        {
            // Specify the moving averages' settings
            longEMA.Length = LongEMA;
            longEMA.Price  = Bars.Volume;

            shortEMA.Length = ShortEMA;
            shortEMA.Price  = Bars.Volume;
        }

        protected override void CalcBar()
        {
            // Set the plots
            emaShortLine.Set(shortEMA[0]);
            emaLongLine.Set(longEMA[0]);
            emaDiffHist.Set(shortEMA[0] - longEMA[0]);
        }
    }
}

Now we click on the ‘Compile changed studies’ button on the toolbar ( ) or press the F7 keyboard shortcut. This compiles the script, and the icon in the ‘Studies’ window that’s before the ‘Volume_Strength’ indicator now changes from red ( ) to green ( ). That shows that the file compiled successfully and is ready to use on the chart.

Adding the example indicator to the chart

To add our indicator to a chart, we right-click on the chart and select ‘Insert Study…’ (or press the F7 keyboard shortcut):

Adding a MultiCharts .NET study to a chart

Then select the ‘Volume_Strength’ indicator, check the ‘Format’ checkbox, and press ‘OK’:

Add MultiCharts .NET indicator to a chart

That brings up the ‘Format Study’ window. In the first tab of that window we can customise our input values:

Setting the input options of an indicator

After we press ‘OK’ in the ‘Format Study’ window the indicator is added to the chart. It looks like:

Volume strength indicator added to a chart Volume strength indicator added to a chart

After we’ve created an indicator in the PowerLanguage .NET Editor, we can export the indicator, change its settings, or remove it. To learn how to create other scripts, see creating a trading strategy in the PowerLanguage .NET Editor and making a MultiCharts .NET function.

Summary

Indicators are created with the ‘New Study’ toolbar button or the ‘File’ menu item. New indicators have a default template that we use to fill in the different parts of the script. We set the default values for inputs in the constructor, a method that has the same name as the indicator. Plots, functions, and other objects are created in the Create() method, while we use the StartCalc() method to specify settings of used functions. In the CalcBar() method, which is executed on every bar, we code the actual behaviour of the indicator, such as calculating and plotting values.


References

MultiCharts (2014). MultiCharts .NET Programming Guide (version 1.1). Retrieved from http://www.multicharts.com/downloads/MultiCharts.NET-ProgrammingGuide-v1.1.pdf

MultiCharts Wiki (2013, May 6). Using Studies (PowerLanguage Editor). Retrieved on August 5, 2015, from https://www.multicharts.com/trading-software/index.php/Using_Studies_%28PowerLanguage_Editor%29

MultiCharts Wiki (2014, September 15). Indicator Settings. Retrieved on August 5, 2015, from http://www.multicharts.com/trading-software/index.php/Indicator_Settings

PowerLanguage .NET Help (n.d.). Retrieved on November 18, 2014, from http://www.multicharts.com/downloads/PowerLanguage.NET.chm

Sharp, J. (2013). Microsoft Visual C# 2013 Step by Step. Microsoft Press.