The MultiCharts .NET Command Line can add indicators (even a list of indicators) and trading strategies to the current price chart. This requires that the exact script name is specified; otherwise, the command fails at runtime. How can we verify a script’s name to prevent that?

Adding a script to a MultiCharts .NET price chart with the Command Line

The .iind Command Line command adds the indicator specified by its name parameter to the chart, while .isig and its name_N_ parameter do the same for trading strategies (MultiCharts Wiki, 2014). Both commands can be executed programmatically with ChartCommands.CommandLine() (PowerLanguage .NET Help, n.d.).

The basic use of these commands is as follows:

ChartCommands.CommandLine(".iind name=Keltner_Channel");
ChartCommands.CommandLine(".isig name1=Keltner_Channel_LE");

To learn more about .iind, see adding an indicator programmatically. And adding a trading strategy with the Command Line has more information on .isig.

When the .iind’s name or .isig’s nameN parameters don’t match an existing script’s name exactly, nothing happens when these commands are executed. That can be problematic, such as when you think that the exit strategy has been added to the chart and then enable auto-trading programmatically. So, how can we check whether a script exists?

An indicator or trading strategy’s class names in MultiCharts .NET

The script’s name used with .iind and .isig needs to match those from the ‘Insert Study’ window exactly (right-click the chart and select ‘Insert Study’):

Inserting a study to a MultiCharts .NET chart

These names are identical to the class names of the MultiCharts .NET scripts themselves. Like the Mov_Avg_Exponential indicator, for example:

namespace PowerLanguage.Indicator
{
    [SameAsSymbol(true)]
    public class Mov_Avg_Exponential : IndicatorObject
    {
        // Indicator code
    }
}

Here we see that this indicator’s class name is Mov_Avg_Exponential (the same as in the ‘Insert Study’ list), located in the PowerLanguage.Indicator namespace.

This is helpful to know because with C# we can generate a list that includes all of these class names. Then, by comparing the name of the script we want to add against elements in the list, we can determine programmatically whether the script’s name is correct or contains an error.

Getting a list of all indicator and trading strategy classes with C#’s reflection

Such a list can be retrieved with reflection. In brief, reflection is the process of inspecting an assembly at runtime (Albahari & Albahari, 2012). And an assembly is the compiled version of individual projects that contain the compiled code, resources, and metadata, which is detailed information about classes in the assembly (Albahari & Albahari, 2012; Sempf, Sphar, & Davis, 2010).

One way to use reflection is in the following method:

private bool ScriptExists(bool indicator, string scriptName)
{
    List<Type> types = Assembly.GetExecutingAssembly().GetTypes().ToList();

    string theNamespace = (indicator == true) ? 
        "PowerLanguage.Indicator" : 
        "PowerLanguage.Strategy";

    foreach (Type t in types)
    {
        if (t.Namespace == theNamespace &&
            t.Name == scriptName)
        {
            Output.WriteLine("The script '{0}' exists in {1}.",
                scriptName, t.Namespace);

            return true;
        }
    }

    Output.WriteLine("The '{0}' script couldn't be found.",
        scriptName);

    return false;
}

This method has two parameters: a Boolean variable (indicator) and the scriptName string variable. The first is used to determine whether the method should look for an indicator (when true) or trading strategy (with false) name. The second parameter contains the name of the script of which we want to know whether it exists.

Next, a generic list (List<Type>) is declared and populated with the types dynamically reflected from an assembly by calling GetTypes() on the Assembly object (see Albahari & Albahari, 2012). This way, a list with all types (including the class names) is retrieved from the current assembly.

Then a string variable (theNamespace) is declared and initialised with the conditional operator. Depending on the value of indicator, this string is either given the value of “PowerLanguage.Indicator” or “PowerLanguage.Strategy”. This narrows the search scope: when looking for an indicator, it resides in the first namespace; while trading strategies would be found in the second namespace.

Checking whether a script name exists in the MultiCharts .NET project

Then a foreach loop iterates over all elements in the types list. Inside the loop, an if statement evaluates if the namespace of the current type (t) matches the one in the theNamespace variable and if the type’s name equals the scriptName.

When both of those expressions evaluate to true, the script we’re looking for exists and this information is outputted to the Output Window. The ScriptExists() method then exits with return true, which also prematurely exits the foreach loop. When the script cannot be found, information about this is also printed and the ScriptExists() method returns false.

Checking if a script exists before adding it to the MultiCharts .NET chart

This ScriptExists() method is used as follows:

private bool executedOnce = false;

protected override void CalcBar()
{
    if (Bars.LastBarOnChart && !executedOnce)
    {
        if (ScriptExists(true, "12345"))
            ChartCommands.CommandLine(".iind name=12345");

        if (ScriptExists(true, "Momentum"))
            ChartCommands.CommandLine(".iind name=Momentum");

        if (ScriptExists(false, "A_Nonexisting_StrategyName"))
            ChartCommands.CommandLine(".isig name1=A_Nonexisting_StrategyName");

        if (ScriptExists(false, "RSI_LE"))
            ChartCommands.CommandLine(".isig name1=RSI_LE");

        executedOnce = true;
    }
}

//> The '12345' script couldn't be found.
//> The script 'Momentum' exists in PowerLanguage.Indicator.
//> The 'A_Nonexisting_StrategyName' script couldn't be found.
//> The script 'RSI_LE' exists in PowerLanguage.Strategy.

Here we declare a Boolean variable (executedOnce) and set it to false. This variable is used later on to prevent the scripts from being added more than once.

In the CalcBar() method, the first if statement checks whether the current bar is the last bar on the chart (Bars.LastBarOnChart will then returns true) and if executedOnce is false, evaluated here with the logical not operator (!).

When those expressions evaluate to true, four different if statements use the ScriptExists() method. The first two method calls verify if the ‘12345’ and ‘Momentum’ indicators exists before adding them to the chart with ChartCommands.CommandLine(). The last two check if the ‘A_Nonexisting_StrategyName’ and ‘RSI_LE’ trading strategies exists before adding them to the chart.

When that is done, the executedOnce variable is set to true. That makes the expression of the first if statement in CalcBar() false, and so the scripts are only added once to the chart.

Summary

The .iind (insert indicator) and .isig (insert signal) Command Line commands require a script’s exact name to work. With reflection we can check if a script exists before trying to add it by verifying if its class name exists in the indicator or trading strategy namespaces.

Complete MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Collections.Generic;       // For List
using System.Reflection;                // For reflection

namespace PowerLanguage.Indicator
{
    [SameAsSymbol(true)]
    public class Example_VerifyIfScriptExists : IndicatorObject
    {
        public Example_VerifyIfScriptExists(object _ctx) : base(_ctx) { }

        private bool executedOnce = false;

        protected override void CalcBar()
        {
            if (Bars.LastBarOnChart && !executedOnce)
            {
                if (ScriptExists(true, "12345"))
                    ChartCommands.CommandLine(".iind name=12345");

                if (ScriptExists(true, "Momentum"))
                    ChartCommands.CommandLine(".iind name=Momentum");

                if (ScriptExists(false, "A_Nonexisting_StrategyName"))
                    ChartCommands.CommandLine(".isig name1=A_Nonexisting_StrategyName");

                if (ScriptExists(false, "RSI_LE"))
                    ChartCommands.CommandLine(".isig name1=RSI_LE");

                executedOnce = true;
            }
        }
        //> The '12345' script couldn't be found.
        //> The script 'Momentum' exists in PowerLanguage.Indicator.
        //> The 'A_Nonexisting_StrategyName' script couldn't be found.
        //> The script 'RSI_LE' exists in PowerLanguage.Strategy.

        private bool ScriptExists(bool indicator, string scriptName)
        {
            List<Type> types = Assembly.GetExecutingAssembly().GetTypes().ToList();

            string theNamespace = (indicator == true) ? 
                "PowerLanguage.Indicator" : 
                "PowerLanguage.Strategy";

            foreach (Type t in types)
            {
                if (t.Namespace == theNamespace &&
                    t.Name == scriptName)
                {
                    Output.WriteLine("The script '{0}' exists in {1}.",
                        scriptName, t.Namespace);

                    return true;
                }
            }

            Output.WriteLine("The '{0}' script couldn't be found.",
                scriptName);

            return false;
        }
    }
}

References

Albahari, J. & Albahari, B. (2012). C# 5.0 in a Nutshell: The Definitive Reference (5th edition). Sebastopol, CA: O’Reilly Media.

MultiCharts Wiki (2014, August 18). MultiCharts Work Area: Understanding Command Line. Retrieved on December 12, 2014, from http://www.multicharts.com/trading-software/index.php/MultiCharts_Work_Area#Understanding_Command_Line

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

Sempf, B., Sphar, C., & Davis, S.R. (2010). C# 2010 All-In-One for Dummies. Hoboken, NJ: John Wiley & Sons.