When Command Line commands are executed programmatically and we immediately reference values changed by this command, it can seem there is a delay with ChartCommands.CommandLine(). What’s going on here?

MultiCharts .NET’s asynchronous Command Line method

The ChartCommands.CommandLine() method executes Command Line commands programmatically (PowerLanguage .NET Help, n.d.). This is an asynchronous method (MultiCharts Support, personal communication, November 17, 2014).

Most methods in C# are synchronous, meaning that these do their work before returning to the calling method (Albahari & Albahari, 2012). For example, if Main() calls the Console.WriteLine() method, Main() will only continue with the next statement when Console.WriteLine() has finished.

Asynchronous methods, on the other hand, do most or all of their work after returning to the calling method (Albahari & Albahari, 2012). In that case, Main() won’t wait on the method to complete but simply move on. With the asynchronous method working in parallel to its caller method, code is typically executed quicker since the calling method doesn’t have to wait on the asynchronous method to complete (Albahari & Albahari, 2012).

However, a problem can arise when the calling method references a value that depends on the work of the asynchronous method. To see how that affects the ChartCommands.CommandLine() method in MultiCharts .NET, let’s look at the example.

Changing the bar spacing with an asynchronous MultiCharts .NET method

The .eds Command Line command displays the entire data series (MultiCharts Wiki, 2014) by adjusting the bar spacing. One way to use this command is the following:

private bool alreadyExecuted = false;

protected override void CalcBar()
{
    if (Bars.LastBarOnChart && !alreadyExecuted)
    {
        Output.WriteLine("Before: bar spacing is {0}px.",
            Environment.BarSpacing);

        ChartCommands.CommandLine(".eds");

        Output.WriteLine("Immediately after: bar spacing is {0}px.",
            Environment.BarSpacing);

        alreadyExecuted = true;
    }
}

//> Before: bar spacing is 8px.
//> Immediately after: bar spacing is 8px.

When the current bar is the last bar and alreadyExecuted is false, the current bar spacing (Environment.BarSpacing) is outputted and .eds is executed programmatically with ChartCommands.CommandLine(). The bar spacing is then outputted again followed by setting alreadyExecuted to true to prevent the code from executing repeatedly.

But the output shows that the bar spacing before and after is 8, while the chart’s bar spacing did change. What happened? Because the asynchronous ChartCommands.CommandLine() method works in parallel to it calling method (CalcBar() here), it hadn’t yet completed its work before we outputted the bar spacing again.

Dealing with asynchronous methods in MultiCharts .NET

One way to deal with this is by incorporating a small pause so that ChartCommands.CommandLine() can complete its asynchronous work:

private bool alreadyExecuted = false;

protected override void CalcBar()
{
    if (Bars.LastBarOnChart && !alreadyExecuted)
    {
        Output.WriteLine("Before: bar spacing is {0}px.",
            Environment.BarSpacing);

        ChartCommands.CommandLine(".eds");

        Thread.Sleep(100);

        Output.WriteLine("100ms after: bar spacing is {0}px.",
            Environment.BarSpacing);

        alreadyExecuted = true;
    }
}

//> Before: bar spacing is 8px.
//> 100ms after: bar spacing is 0,5px.

This is the same example as above. But instead of immediately outputting the bar spacing after calling ChartCommands.CommandLine(), first the Thread.Sleep() method is called with a value of 100. This method delays the script for a specified amount of milliseconds (Stellman & Greene, 2010) by pausing the current thread (Albahari & Albahari, 2012).

Now the output is correct: Environment.BarSpacing returns 8 before executing .eds and 0.5 after.

This Thread.Sleep() approach with the asynchronous ChartCommands.CommandLine() method can, for example, be used with changing the bar spacing and showing the entire data series.

Summary

Command Line commands are executed programmatically with ChartCommands.CommandLine(): an synchronous method that works in parallel to its calling method. When ChartCommands.CommandLine() changes values you want to retrieve immediately afterwards, a small delay with Thread.Sleep() needs to be added.

Complete MultiCharts .NET indicator example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Threading;         // For Thread.Sleep()

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

        private bool alreadyExecuted = false;

        protected override void CalcBar()
        {
            if (Bars.LastBarOnChart && !alreadyExecuted)
            {
                Output.WriteLine("Before: bar spacing is {0}px.",
                    Environment.BarSpacing);

                ChartCommands.CommandLine(".eds");

                Thread.Sleep(100);

                Output.WriteLine("100ms after: bar spacing is {0}px.",
                    Environment.BarSpacing);

                alreadyExecuted = true;
            }
        }

        //> Before: bar spacing is 8px.
        //> 100ms after: bar spacing is 0,5px.

        //private bool alreadyExecuted = false;

        //protected override void CalcBar()
        //{
        //    if (Bars.LastBarOnChart && !alreadyExecuted)
        //    {
        //        Output.WriteLine("Before: bar spacing is {0}px.",
        //            Environment.BarSpacing);

        //        ChartCommands.CommandLine(".eds");

        //        Output.WriteLine("Immediately after: bar spacing is {0}px.",
        //            Environment.BarSpacing);

        //        alreadyExecuted = true;
        //    }
        //}
        //> Before: bar spacing is 8px.
        //> Immediately after: bar spacing is 8px.
    }
}

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 21, 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.