The Command Line can be used, amongst other things, to change the chart symbol. But how can we use it to cycle through a list of symbols?

Cycling through a list of symbols in MultiCharts .NET

The .csy Command Line command changes symbols on the chart (MultiCharts Wiki, 2014) and is executed programmatically with the ChartCommands.CommandLine() method (PowerLanguage .NET Help, n.d.).

To alternate between symbols we first need a collection that holds these symbols. In C#, the easy-to-use List<T> can be used for that. The <T> means it’s generic: it works with all types, such as an int, string, or class object (Stellman & Greene, 2010).

Creating a list and outputting symbol information in MultiCharts .NET

Before values can be pulled from a list, the list needs to be created and populated. We’ll also output symbol information to monitor the indicator, like this:

private List<String> symbolList = new List<String>()
{
    ".csy name=EUR/USD, df=LMAX",
    ".csy name=EUR/GBP, df=MB Trading",
    ".csy name=EX#, df=IQFeed"
};

protected override void StartCalc()
{
    Output.WriteLine("Current symbol: {0} ({1})",
        Bars.Info.Name,
        Bars.Info.DataFeed);
}

//> Current symbol: @ES# (IQFeed)
//> Current symbol: EUR/GBP (MB Trading)
//> Current symbol: EX# (IQFeed)
//> Current symbol: EUR/USD (LMAX)
//> Current symbol: EUR/GBP (MB Trading)
//> Current symbol: EX# (IQFeed)

Here a List<String> collection named symbolList is created that contains three string elements. These are the .csy commands to change the symbol to either LMAX’s EUR/USD, MB Trading’s EUR/GBP, or EX# (EuroStoxx 50 continuous future) from IQFeed.

Because .csy’s dnum (data series number) and res (resolution) parameters are missing, the primary data series’ symbol is changed with the resolution unaffected. For more on .csy parameters, see changing the symbol with the Command Line.

In the StartCalc() method, executed once at the start of each calculation cycle (MultiCharts, 2013), symbol information is outputted with Bars.Info.Name and Bars.Info.DataFeed. These properties return the symbol and data feed of the primary data series, respectively (see PowerLanguage .NET Help, n.d.).

Processing mouse clicks and switching the symbol

Changing the chart to another symbol is done by processing mouse click events in the OnMouseEvent() method:

protected override void OnMouseEvent(MouseClickArgs arg)
{
    if (arg.buttons == MouseButtons.Left && arg.keys == Keys.Control)
    {
        int currentIndex = 0, indexNextSymbol;

        for (int i = 0; i < symbolList.Count; i++)
        {
            if (symbolList[i].Contains(Bars.Info.Name))
            {
                currentIndex = i;
                break;
            }
        }

        if (currentIndex == (symbolList.Count - 1))
            indexNextSymbol = 0;
        else
            indexNextSymbol = currentIndex + 1;

        ChartCommands.CommandLine(symbolList[indexNextSymbol]);
    }
}

The first if statement evaluates whether the mouse click on the chart was a left mouse click with the Control key. When that is the case, two integer variables (currentIndex and indexNextSymbol) are declared and a for loop begins.

This loop begins at zero and continues as long as i is less than the list’s length, which is returned by its Count property. Since index numbers of a list are zero-based, while Count is not (see Liberty & MacDonald, 2009), this loop iterates over the complete list.

Changing the symbol to one of the list with the Command Line

In the loop an if statement checks whether the current list element contains the chart’s symbol (symbolList[i].Contains(Bars.Info.Name)). This Contains() methods returns a Boolean value that indicates if the substring (here Bars.Info.Name) occurs within the string (here symbolList[i]) (Microsoft Developer Network, n.d.). So if the chart is an EUR/USD chart, this method returns true for the first list element (".csy name=EUR/USD, df=LMAX") and false for the other elements.

When Contains() returns true, the currentIndex variable is assigned the value of the i loop variable followed by stopping the loop with break. Now that we know the location of the current chart symbol in the list, the next symbol can be determined in the if-else statement.

If the index of the current symbol (currentIndex) equals the last list element (symbolList.Count - 1), the indexNextSymbol is assigned a value of 0. That way it cycles back to the beginning of the list instead of going past the end of the list. The else part of the if-else statement adds 1 to the current index so that the chart ‘jumps’ to the next symbol in the list.

The very last statement passes the next list element (symbolList[indexNextSymbol]) to the ChartCommands.CommandLine() to perform the actual switching to the next symbol.

Summary

The Command Line .csy command can change the chart symbol. With the help of a list that contains .csy commands, a chart can be cycled through by passing each list item to the ChartCommands.CommandLine() method in turn.

Complete code of the MultiCharts .NET indicator

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Collections.Generic;   // Added for List
using System.Windows.Forms;         // Added for Keys and MouseButtons enumerations

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

        private List<String> symbolList = new List<String>()
        {
            ".csy name=EUR/USD, df=LMAX",
            ".csy name=EUR/GBP, df=MB Trading",
            ".csy name=EX#, df=IQFeed"
        };

        protected override void StartCalc()
        {
            Output.WriteLine("Current symbol: {0} ({1})",
                Bars.Info.Name,
                Bars.Info.DataFeed);
        }

        protected override void OnMouseEvent(MouseClickArgs arg)
        {
            if (arg.buttons == MouseButtons.Left && arg.keys == Keys.Control)
            {
                int currentIndex = 0, indexNextSymbol;

                for (int i = 0; i < symbolList.Count; i++)
                {
                    if (symbolList[i].Contains(Bars.Info.Name))
                    {
                        currentIndex = i;
                        break;
                    }
                }

                if (currentIndex == (symbolList.Count - 1))
                    indexNextSymbol = 0;
                else
                    indexNextSymbol = currentIndex + 1;

                ChartCommands.CommandLine(symbolList[indexNextSymbol]);
            }
        }

        //> Current symbol: @ES# (IQFeed)
        //> Current symbol: EUR/GBP (MB Trading)
        //> Current symbol: EX# (IQFeed)
        //> Current symbol: EUR/USD (LMAX)
        //> Current symbol: EUR/GBP (MB Trading)
        //> Current symbol: EX# (IQFeed)

        protected override void CalcBar() { } 
    }
}

References

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

Microsoft Developer Network (n.d.). String.Contains Method. Retrieved on November 29, 2014, from http://msdn.microsoft.com/en-us/library/dy85x1sa%28v=vs.110%29.aspx

MultiCharts (2013). MultiCharts .NET Programming Guide (version 1.0). Retrieved from http://www.multicharts.com/downloads/MultiCharts.NET-ProgrammingGuide-v1.0.pdf

MultiCharts Wiki (2014, August 18). MultiCharts Work Area: Understanding Command Line. Retrieved on November 18, 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

Stellman, A. & Greene, J. (2010). Head First C#: A Brain-Friendly Guide (2nd edition). Sebastopol, CA: O’Reilly Media.