Besides creating indicators and coding trading strategies we can also make functions that those indicators and strategies use. How do we create our own function in the PowerLanguage .NET Editor?

The PowerLanguage .NET Editor and creating functions

The PowerLanguage .NET Editor is the primary tool for working with indicators, strategies, and functions (MultiCharts, 2014). With this program we can, for example, export, remove, and edit scripts. For that, however, we do need to have a script to work with. Luckily, the PowerLanguage .NET Editor can also create indicators, trading strategies, and functions. Actually, this code editor is the only program that can create functions (Henry MultiCharts, 2013a).

MultiCharts .NET functions are independent procedures which are called from other scripts to perform a specific task (MultiCharts Wiki, 2013). The XAverage function, for example, is tasked with calculating the Exponential Moving Average (EMA). So other scripts simply need to use this function to have EMA values calculated.

These functions are different from what languages like TradingView Pine, R, Python, and JavaScript also call a function. In those languages a function acts like a C# method whereas functions in MultiCharts .NET have their own class and are contained in a separate file. Now, let’s look at how we can create our own function in MultiCharts .NET.

Creating a function in the PowerLanguage .NET Editor

To develop a function, we start the PowerLanguage .NET Editor and click on the small arrow besides the ‘New Study’ toolbar button ( ) or use the ‘File’ → ‘New’ menu items. Then we select ‘New Function…’:

Creating a new function in the PowerLanguage .NET Editor

This brings up the ‘Function Properties’ window:

Function Properties window in the PowerLanguage .NET Editor

Let’s explore these options before pressing ‘OK’ in this window.

Settings of the ‘Function Properties’ window

The ‘Function Properties’ window starts with the ‘Name’ field for specifying the function’s name. For this tutorial we type ‘Volume_Momentum’ in here.

The ‘Return Value’ setting allows specifying the function’s return type. Its pull-down menu has the following options:

Return values of a MultiCharts .NET function

A function that’s set to ‘System.Double’ returns a decimal number, with ‘System.Boolean’ a true/false (Boolean) value is returned, and an integer number is returned when it’s set to ‘System.Int32’. Functions can also return textual strings (‘System.String’) or DateTime values (`System.DateTime’). Since we’re going to calculate rational numbers in this tutorial, we set our function to ‘System.Double’.

The third setting in the ‘Function Properties’ window is ‘Language’, which can be C# or VB .NET (Visual Basic). We set this option to C# and then continue to the ‘Base Study’ setting that can either be ‘Simple’ or ‘Series’.

‘Simple’ functions execute some operation over the arguments sent to the function and return the result (MultiCharts, 2014). These functions always return the same value as long as its argument values are identical. Examples of these are the built-in HighestBar, AvgPrice, and StdError functions.

‘Series’ functions, on the other hand, store certain information, like the result from previous calculations (MultiCharts, 2014). That means these functions return a value that depends on the value it calculated on the previous bar. Examples of such functions are BarNumber, RSI, and Stochastic.

In this article we set this option to ‘Simple’ and then press ‘OK’ in the ‘Function Properties’ window. Our new function now opens in the PowerLanguage .NET Editor:

New function created in the PowerLanguage .NET Editor

The default layout of a MultiCharts .NET function

Our ‘Volume_Momentum’ function starts, just like all functions, with the following default template:

using System;
using System.Drawing;
using System.Linq;


namespace PowerLanguage
{
    namespace Function
    {
        public sealed class Volume_Momentum : FunctionSimple<System.Double>
        {
            public Volume_Momentum(CStudyControl _master) : base(_master) { }
            public Volume_Momentum(CStudyControl _master, int _ds) : base(_master, _ds) { }

            protected override void Create()
            {
                // create variable objects and function objects
            }

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

            protected override System.Double CalcBar()
            {
                // function logic
                return default(System.Double);
            }
        }
    }
}

This template provides the structure in which we’ll code the different parts of the function.

Coding an example function in the PowerLanguage .NET Editor

The function that we’re going to make calculates ‘volume momentum’ and has the following features:

  • It calculates an EMA based on the volume. We determine the momentum value by subtracting two EMA values from each other.
  • The function has three settings: the volume type, EMA length, and momentum length. Each of these settings can then be configured by other scripts that use our function.

Let’s see how to programmatically implement this.

Adding settings to a MultiCharts .NET function

First we add the function’s settings. That’s implemented with C#’s properties in MultiCharts .NET, and with these properties other scripts can set the values that our function uses (see Liberty & MacDonald, 2009; Sharp, 2013). And so we create three properties:

public ISeries<double> VolumeType { get; set; }
public int EMALength { get; set; }
public int MomentumLength { get; set; }

The first property is named VolumeType and set to an ISeries<double>, which is a series of double values that’s similar to a bar’s data series (see PowerLanguage .NET Help, n.d.). The EMA that we’re going to calculate is based on this VolumeType data series. That means other scripts can specify through this property which data the EMA should be based on (we’ll look at an example of this later).

The other two properties (EMALength and MomentumLength) are both integers; the first sets the number of bars that the EMA is calculated on, the second defines the momentum period. So these two values also need to be set by any indicator or strategy that uses our function.

Creating an EMA and variable series in a MultiCharts .NET function

Now we need to make the other things that we’re going to use in the function: an EMA function (so we can easily calculate the EMA values) and a variable series to store the EMA values in. First, we declare both of them:

private XAverage EMA;
private VariableSeries<double> emaValues;

The instance of the XAverage function calculates the EMA values and is named EMA accordingly. We use the emaValues name for the double variable series (VariableSeries<double>).

A variable series is a series with values that allows access to values from previous bars (Henry MultiCharts, 2013b). It has the same length as the symbol it’s applied to. We access its historical values with a positive integer between square brackets ([ and ]); just like we for instance do with Bars.Close and Bars.Volume.

After naming the EMA and variable series we create them with C# new keyword in the Create() method. That method is called first and only once, immediately after another script creates a new object from our function (MultiCharts, 2014).

protected override void Create()
{
    // Create the EMA and variable series
    EMA       = new XAverage(this);
    emaValues = new VariableSeries<double>(this);
}

Setting the EMA values and calculating the volume momentum

Next is the StartCalc() method that’s executed before the script starts processing the first price bar (MultiCharts, 2014). In it, we specify the EMA function settings:

protected override void StartCalc()
{
    // Set the EMA's settings
    EMA.Price  = VolumeType;
    EMA.Length = EMALength;
}

Here we set the data that our EMA calculates on, its Price property, to the VolumeType setting of the function. And so the scripts that use our function can change on which data the EMA is calculated on by changing the function’s VolumeType property (we’ll see an example of that below). Similarly, we set the Length property of the EMA function to EMALength. That latter is also a property of our function and is therefore settable by the scripts that implement our function.

After setting up the EMA in StartCalc() we perform the function’s calculations in the CalcBar() method:

protected override System.Double CalcBar()
{
    // Calculate the EMA
    emaValues.Value = EMA[0];

    // Calculate the momentum
    double momentum = emaValues[0] - emaValues[MomentumLength];

    // Return the calculated value
    return momentum;
}

This method is executed at least once per bar, starting with the very first bar and ending with the last (MultiCharts, 2014). We do three things here.

First, we place a zero in square brackets after the EMA instance (EMA[0]). That returns the calculated EMA value for the current bar. To access previous EMA values we store each bar’s EMA value in the emaValues variable series. We do so by assigning the EMA value to the Value property of the variable series (see Henry MultiCharts, 2013b).

Then we calculate the momentum. First, we create a double variable named momentum. Then we assign this variable the difference between the current bar’s EMA of volume (emaValues[0]) and the volume EMA of MomentumLength bars ago (emaValues[MomentumLength]). This MomentumLength value is one of the function’s properties and is set by the script that uses our function.

The last statement in CalcBar() returns the momentum value we’ve just calculated with return. This ‘sends’ the value of the momentum variable to the script that uses our function. That script, in turn, can then generate trades with it or plot it on the chart.

Complete code of the MultiCharts .NET example function

After we’ve coded the parts discussed above, the complete function code is:

using System;
using System.Drawing;
using System.Linq;

namespace PowerLanguage
{
    namespace Function
    {
        public sealed class Volume_Momentum : FunctionSimple<System.Double>
        {
            public ISeries<double> VolumeType { get; set; }
            public int EMALength { get; set; }
            public int MomentumLength { get; set; }

            private XAverage EMA;
            private VariableSeries<double> emaValues;
            
            public Volume_Momentum(CStudyControl _master) : base(_master) { }
            public Volume_Momentum(CStudyControl _master, int _ds) : base(_master, _ds) { }

            protected override void Create()
            {
                // Create the EMA and variable series
                EMA       = new XAverage(this);
                emaValues = new VariableSeries<double>(this);
            }

            protected override void StartCalc()
            {
                // Set the EMA's settings
                EMA.Price  = VolumeType;
                EMA.Length = EMALength;
            }

            protected override System.Double CalcBar()
            {
                // Calculate the EMA
                emaValues.Value = EMA[0];

                // Calculate the momentum
                double momentum = emaValues[0] - emaValues[MomentumLength];

                // Return the calculated value
                return momentum;
            }
        }
    }
}

Now we need to click on the ‘Compile changed studies’ button on the toolbar ( ) or press the F7 keyboard shortcut. This compiles our function and the icon before the function’s name in the ‘Studies’ window then changes from red ( ) to green ( ). The function is now compiled successfully and ready to use.

Creating a MultiCharts .NET indicator that plots the function’s values

To see our function in action, we either need to create a trading strategy or an indicator that uses it. That’s because a function cannot be added to a MultiCharts .NET chart. So we’re going to create an indicator that plots the function’s values on the chart.

For that we click on the arrow besides the ‘New Study’ toolbar button ( ) and select ‘New Indicator…’:

Creating a new MultiCharts .NET indicator

We name our indicator ‘Volume_Momentum’ and set its language to C#:

Naming the new MultiCharts .NET indicator

Programming a MultiCharts .NET indicator that plots function values

The ‘Volume_Momentum’ indicator now opens in the PowerLanguage .NET Editor. It has a default code template in which we’ll program the features.

We first add two inputs to the indicator. With those we can easily change the values used in the indicator from inside MultiCharts .NET without having to edit and recompile the indicator again. To add inputs to an indicator or trading strategy, we place the [Input] attribute above a public property (MultiCharts, 2014). They’re typically placed in the top of the script like this:

// Make inputs
[Input]
public int EMALength { get; set; }

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

Now we need to give these inputs a default value. That way we can add the indicator to a chart without having to configure it first. We set inputs to a default value in the constructor (MultiCharts, 2014), which is a method with the same name as the class (Dorman, 2010). In our case, that’s the Volume_Momentum() method and so we give EMALength and MomentumLength a default value there:

public Volume_Momentum(object _ctx) : base(_ctx) 
{
    // Set the inputs to their default values
    EMALength      = 5;
    MomentumLength = 7;
}

Creating the MultiCharts .NET indicator’s plot and function

We then declare an IPlotObject variable named volMomPlot and an instance of our function that we name volMomentum. But instead of using the function’s name (Volume_Momentum) here, we need to prefix it with Function.. That clarifies that we mean the function, and not the indicator that’s also named Volume_Momentum.

// Declare plot and function
private IPlotObject volMomPlot;
private Function.Volume_Momentum volMomentum;

Then we create instances of the plot and function in order to use them in the indicator. We do that in Create(), a method that’s executed immediately when the indicator is added to a chart or Scanner/Watchlist window (see MultiCharts, 2014):

protected override void Create()
{
    // Create plot and function
    volMomPlot = AddPlot(new 
        PlotAttributes("Volume Momentum", EPlotShapes.Histogram, Color.Navy,
        Color.Transparent, 5, EPlotStyle.Solid, true));

    volMomentum = new Function.Volume_Momentum(this);
}

We create the plot with the AddPlot() method and specify its properties with PlotAttributes() (PowerLanguage .NET Help, n.d.). We name the plot “Volume Momentum”, and set it to a histogram (EPlotShapes.Histogram) in navy blue (Color.Navy) with a transparent background colour (Color.Transparent). That latter colour is, by the way, only used in the Scanner/Watchlist window (see MultiCharts Wiki, 2012a).

We set the plot’s size to 5 (which is slightly thicker than the default width of 1) and make it solid (EPlotStyle.Solid). The last argument, the Boolean true value, enables the plot’s last price marker which is displayed on the indicator’s price axis (PowerLanguage .NET Help, n.d.).

We also create an instance of the Volume_Momentum function here with C#’s new keyword. Note that we use the Function. prefix here again to remove the ambiguity between the function and indicator with the same name.

Specifying the function’s settings in the indicator

Next in the example is StartCalc(). That method is executed once before the indicator starts processing the first price bar (MultiCharts, 2014). In this method we configure the Volume_Momentum indicator:

protected override void StartCalc()
{
    // Set function's settings
    volMomentum.EMALength      = EMALength;
    volMomentum.MomentumLength = MomentumLength;
    volMomentum.VolumeType     = Bars.Volume;
}

As you recall, we added three inputs to the function earlier: EMALength (which sets the length of the volume EMA), MomentumLength (for specifying the momentum length), and VolumeType, which was the data series that the EMA was calculated on.

Here in the StartCalc() method we configure our volMomentum instance of the Volume_Momentum function. We set its EMALength to the EMALength indicator input that we made earlier. Likewise, the function’s MomentumLength setting is set to the indicator’s MomentumLength input. The last setting (VolumeType) is set to Bars.Volume to make the function calculate on the bar’s volume data. We could also set this option to Bars.UpTicks or Bars.DownTicks` to calculate the ‘volume momentum’ on the up ticks and down ticks volume of the primary data series (see MultiCharts Wiki, 2012b, 2012c).

Plotting the function’s values on a MultiCharts .NET price chart

We end the example with CalcBar(), a method that’s executed at least once on every price bar, starting from the first up to the very last bar (MultiCharts, 2014). Here we set the plot’s values:

protected override void CalcBar()
{
    // Update plot
    volMomPlot.Set(volMomentum[0]);
}

We set the plot’s value with its Set() method (PowerLanguage .NET Help, n.d.). In it, we pass the function with a 0 in square brackets (volMomentum[0]). That causes the function to return the current bar’s value. More specifically, it invokes the function’s CalcBar() method which returns a value with return (see function source code above).

Full code of the MultiCharts .NET indicator

After implementing the above steps, the indicator that plots our function looks like:

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

namespace PowerLanguage.Indicator
{
    public class Volume_Momentum : IndicatorObject
    {
        // Make inputs
        [Input]
        public int EMALength { get; set; }

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

        public Volume_Momentum(object _ctx) : base(_ctx) 
        {
            // Set the inputs to their default values
            EMALength      = 5;
            MomentumLength = 7;
        }

        // Declare plot and function
        private IPlotObject volMomPlot;
        private Function.Volume_Momentum volMomentum;
        
        protected override void Create()
        {
            // Create plot and function
            volMomPlot = AddPlot(new 
                PlotAttributes("Volume Momentum", EPlotShapes.Histogram, Color.Navy,
                Color.Transparent, 5, EPlotStyle.Solid, true));

            volMomentum = new Function.Volume_Momentum(this);
        }
        
        protected override void StartCalc()
        {
            // Set function's settings
            volMomentum.EMALength      = EMALength;
            volMomentum.MomentumLength = MomentumLength;
            volMomentum.VolumeType     = Bars.Volume;
        }
        
        protected override void CalcBar()
        {
            // Update plot
            volMomPlot.Set(volMomentum[0]);
        }
    }
}

Now we click on the ‘Compile changed studies’ button the toolbar ( ) or press the F7 keyboard shortcut. This compiles the script and changes the icon before its name in the ‘Studies’ window from red ( ) to green ( ). After our indicator compiled successfully we can use it in the MultiCharts .NET program.

Adding the ‘volume momentum’ indicator to a price chart

To add the indicator to the chart, we right-click on the chart and select ‘Insert Study…’ (F7):

Adding a MultiCharts .NET study to the chart

Then we select the ‘Volume_Momentum’ indicator from the ‘Indicators’ tab, check the ‘Format’ checkbox, and press ‘OK’:

Adding the Volume_Momentum indicator to the chart

Now the ‘Format Study’ window opens. We can set the indicator’s inputs here, but for now we keep them at their default values and click ‘OK’:

Volume Momentum indicator - default settings

The indicator is now added to the chart. It looks like this when applied to an EUR/USD symbol with volume data:

Example of Volume_Momentum indicator & function Example of Volume_Momentum indicator & function Example of Volume_Momentum indicator & function
Tip: By the way, if we change a function that’s implemented by indicators or trading strategies added to a MultiCharts .NET chart, Scanner/Watchlist window, or Portfolio Trader, then we need to remove and re-add those scripts before the effect of the updated function is visible. This is because MultiCharts .NET doesn’t analyse scripts to see which functions are used and whether they were modified (Henry MultiCharts, 2013a).

After creating a function and its accompanying indicator, we can export these scripts, remove them, or browse through the help contents for ideas on what to implement next. To create other scripts than functions, see creating an indicator and programming a trading strategy in MultiCharts .NET.

Summary

We create a function in the PowerLanguage .NET Editor with the ‘New Study’ button or through the ‘File’ → ‘New’ menu. A new function’s template provides the structure to implement the different parts of a function. With public properties in the function’s class other scripts can change the function’s settings. In the Create() method in a function we create variable series and any other functions, while we specify the settings of other functions in the StartCalc() method. We perform the function’s actual calculations in the CalcBar() method, and also return the calculated value here. That makes the function’s output available to the scripts that implement the function.


References

Dorman, S. (2010). Sams Teach Yourself Visual C# 2010 in 24 Hours. Indianapolis, IN: Sams/Pearson Education.

Henry MultiCharts (2013a, December 13). MultiCharts .NET FAQ - forum discussion. Retrieved on August 13, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&t=45848#p100797

Henry MultiCharts (2013b, May 31). VariableObject - why use it? Forum discussion. Retrieved on August 12, 2015, from http://www.multicharts.com/discussion/viewtopic.php?f=19&p=70279#p70248

Liberty, J. & MacDonald, B. (2009). Learning C# 3.0: Master the Fundamentals of C# 3.0. Sebastopol, CA: O’Reilly Media.

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

MultiCharts Wiki (2012a, February 19). Plot. Retrieved on August 8, 2015, from https://www.multicharts.com/trading-software/index.php/Plot

MultiCharts Wiki (2012b, February 28). UpTicks. Retrieved on August 12, 2015, from http://www.multicharts.com/trading-software/index.php/UpTicks

MultiCharts Wiki (2012c, February 28). DownTicks. Retrieved on August 12, 2015, from http://www.multicharts.com/trading-software/index.php/DownTicks

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

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.