The MultiCharts .NET Command Line can be used to reload price data and reload internet connectivity-related data gaps. But how can we programmatically deal with ‘wrong’ prices?

Reloading data to deal with data spikes in MultiCharts .NET

The .rld Command Line command reloads price data on the chart (MutiCharts Wiki, 2014a) and can be executed with the ChartCommands.CommandLine() method (PowerLanguage .NET Help, n.d.). To learn more, see reloading data with the Command Line.

‘Spikes’ in price data can be caused by an erroneous price. These outliers can be fixed in two ways: by reloading price data or by editing the data manually in the QuoteManager (Henry MultiCharts, 2013).

When a chart is reloaded, new data is downloaded from the data source (MultiCharts Wiki, 2014b). This means that faulty prices are only fixed through reloading if the data feed provider has cleaned its historical data.

Note: By the way, data reloaded from Interactive Brokers is by default not downloaded again but retrieved from the cache in order to avoid the data pacing violation limitation (MultiCharts Wiki, 2014c). This can be changed by disabling the option “Utilization of cache for real-time price data”. For that, open the QuoteManager and go to ‘Tools’, click on ‘Data Sources’ and select the settings of Interactive Brokers to find this setting:
Changing Interactive Brokers settings in MultiCharts .NET

Dealing with MultiCharts .NET data spikes programmatically

One way to determine price spikes is by comparing a bar’s range to the average range of all price bars: when the bar’s range is substantially larger, odds are it contains a price spike.

For example, this AUD/CAD chart has a price spike around 560 pips higher than the other prices:

Reloading price spikes in MultiCharts .NET - before

When the example indicator is added to the chart, the spike triggers a chart reload. With the correct data downloaded from MB Trading, the spike disappears:

Reloading MultiCharts .NET price spikes - after

Determining the average range of all price bars in MultiCharts .NET

The example begins with calculating the average range of all bars:

private double avgRangeAllBars;

protected override void StartCalc()
{
    for (int i = 0; i < Bars.FullSymbolData.Count; i++)
    {
        avgRangeAllBars = avgRangeAllBars + 
            (Bars.FullSymbolData.High[-i] - Bars.FullSymbolData.Low[-i]);
    }
    avgRangeAllBars = avgRangeAllBars / Bars.FullSymbolData.Count;
}

Here we first declare a double variable (avgRangeAllBars) which is later used to store the average range of all price bars.

That average is calculated in the StartCalc() method with a for loop that iterates over all price bars. Inside the loop, each bar’s range is added to the avgRangeAllBars variable. Since the StartCalc() method is executed once at the beginning of a script’s calculation (MultiCharts, 2013), all data series’ price bars are future price bars relative to StartCalc(). That is why a negative index (-i) is used here to access a bar’s high and low prices.

When the loop is done, the avgRangeAllBars variable (which at that point holds the sum of all bar ranges) is divided by the total number of bars on the chart (returned by the Bars.FullSymbolData.Count property; MultiCharts, 2013).

Reloading price data programmatically with price gaps in MultiCharts .NET

The next part analyses bars for an exceptional range:

private bool alreadyReloaded = false;

protected override void CalcBar()
{
    if (Bars.Range() > (10 * avgRangeAllBars))
    {
        Output.WriteLine("This bar's range is {0} (High: {1}" + 
            ", Low: {2}) while the average range is {3}.",
            Bars.Range(),
            Bars.High[0],
            Bars.Low[0],
            avgRangeAllBars);

        if (alreadyReloaded == false)
        {
            ChartCommands.CommandLine(".rld");

            alreadyReloaded = true;
        }
    }
}

//> This bar's range is 0,05667 (High: 1,00123, Low: 0,94456) 
//>     while the average range is 0,000702148664343789.

Here we first declare the Boolean variable alreadyReloaded and initialise it to false. This variable is used later to only reload the price data once.

The if statement in the CalcBar() method evaluates whether the current bar’s range (returned by Bars.Range(); PowerLanguage .NET Help, n.d.) is larger than 10 times the average range. This value of 10 holds no special meaning, but is chosen because it’s small enough to capture a spike but large enough to prevent false positives. Another approach is to use the standard deviation, if one assumes that prices are normally distributed.

When that if statement expression evaluates to true, Output.WriteLine() prints information to the Output Window and the nested if statement evaluates whether alreadyReloaded is false. When it is, ChartCommands.CommandLine() is called with the .rld command and the alreadyReloaded variable is set to true. Since that invalidates the if statement, the chart is only reloaded once.

Other potential applications of monitoring price spikes are, for example, turning off auto-trading or changing the symbol to another data feed when the data displays spikes.

Summary

The .rld command reloads the chart’s price data and can be executed programmatically with the ChartCommands.CommandLine() method. Price spikes can be solved by reloading the chart with new data from the data feed, provided the data provider has cleaned these faulty prices from its data.

Complete MultiCharts .NET indicator example

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

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

        private double avgRangeAllBars;

        protected override void StartCalc()
        {
            for (int i = 0; i < Bars.FullSymbolData.Count; i++)
            {
                avgRangeAllBars = avgRangeAllBars + 
                    (Bars.FullSymbolData.High[-i] - Bars.FullSymbolData.Low[-i]);
            }
            avgRangeAllBars = avgRangeAllBars / Bars.FullSymbolData.Count;
        }

        private bool alreadyReloaded = false;

        protected override void CalcBar()
        {
            if (Bars.Range() > (10 * avgRangeAllBars))
            {
                Output.WriteLine("This bar's range is {0} (High: {1}" + 
                    ", Low: {2}) while the average range is {3}.",
                    Bars.Range(),
                    Bars.High[0],
                    Bars.Low[0],
                    avgRangeAllBars);

                if (alreadyReloaded == false)
                {
                    ChartCommands.CommandLine(".rld");

                    alreadyReloaded = true;
                }
            }
        }

        //> This bar's range is 0,05667 (High: 1,00123, Low: 0,94456) 
        //>     while the average range is 0,000702148664343789.
    }
}

References

Henry MultiCharts (2013, October 22). how do I fix a price spike in multicharts - forum discussion. Retrieved on December 20, 2014, from http://www.multicharts.com/discussion/viewtopic.php?f=1&t=45296#p99091

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

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

MultiCharts Wiki (2014b, January 22). Reloading Charts. Retrieved on December 20, 2014, from http://www.multicharts.com/trading-software/index.php/Reloading_Charts

MultiCharts Wiki (2014c, November 20). Interactive Brokers. Retrieved on December 20, 2014, from http://www.multicharts.com/trading-software/index.php/Interactive_Brokers

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