Situation
You want to know what triggered the calculation of a MultiCharts .NET indicator or trading strategy.

Programming example

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

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

        protected override void StartCalc()
        {
            Output.Clear();
        }

        protected override void CalcBar()
        {
            if (!Bars.LastBarOnChart)
                return;

            // Output calculation reason
            switch (Environment.CalcReason)
            {
                case CalculationReason.Default:
                    Output.WriteLine("{0} - Calculation based on a price update",
                        DateTime.Now.ToString("HH:mm:ss"));
                    break;

                case CalculationReason.Timer:
                    Output.WriteLine("{0} - Calculation based on a RecalcLastBarAfter timer",
                        DateTime.Now.ToString("HH:mm:ss"));
                    break;

                default:
                    break;
            }

            // Recalculate the script after 10 seconds.
            ExecControl.RecalcLastBarAfter(new TimeSpan(0, 0, 10));
        }

        // This method is called every time the RecalcLastBarAfter TimeSpan elapses
        protected override void OnRecalcLastBarAfterEvent()
        {
            this.CalcBar();
        }
    }
}

Output of the programming example

When applied to a chart, the indicator generates an output like the following:

06:56:52 - Calculation based on a price update
06:57:02 - Calculation based on a RecalcLastBarAfter timer
06:57:19 - Calculation based on a RecalcLastBarAfter timer
06:57:29 - Calculation based on a RecalcLastBarAfter timer
06:57:39 - Calculation based on a RecalcLastBarAfter timer
06:57:49 - Calculation based on a RecalcLastBarAfter timer
06:58:59 - Calculation based on a RecalcLastBarAfter timer
06:59:09 - Calculation based on a price update
06:59:19 - Calculation based on a RecalcLastBarAfter timer
06:59:29 - Calculation based on a RecalcLastBarAfter timer

Script calculation in MultiCharts .NET

Indicators and trading strategies in MultiCharts .NET are calculated on historical price bars and real-time price updates (MultiCharts Wiki, 2012). With the various ways to control MultiCharts .NET, scripts can also be recalculated programmatically, for example with a recalculation based on a time interval.

This can, however, make it unclear what caused a script calculation. For example, was the strategy calculation triggered by a new tick or was the calculation merely a time-based recalculation implemented to deal with slow markets? Luckily, the reason behind a calculation can be retrieved with the Environment.CalcReason property.

Determine the calculation reason in MultiCharts .NET

The Environment.CalcReason property returns an enumerator (from the CalculationReason enumeration) that specifies the calculation reason (see MultiCharts, 2013; PowerLanguage .NET Help, n.d.).

This property returns one of the following CalculationReason enumerators (see PowerLanguage .NET Help, n.d.):

  • Default: a calculation that is triggered by a new price update;
  • LeftMouseClick or RightMouseClick: when the calculation is triggered by either a left or right mouse click on the chart;
  • Timer: a calculation that is triggered by the expiration of the RecalcLastBarAfter() TimeSpan period;
  • MarketPositionChange: when the calculation of a trading strategy is triggered by a change in market position at the broker for the current instrument;
  • OrderFilled: when the calculation of a trading strategy is caused by filling an order of the trading strategy at the broker.

The difference between MarketPositionChange and OrderFilled is that OrderFilled only applies to orders sent by the strategy, while a MarketPositionChange can also be triggered by another strategy or manual order (see MultiCharts, 2013).

In the example below two possible calculation reasons (Default and Timer) are examined further.

MultiCharts .NET programming example

The example begins with a MultiCharts .NET class attribute:

[SameAsSymbol(true)]

Setting the SameAsSymbol attribute to true ensures that the indicator is plotted on the main price chart and not in a sub-chart.

Next the PowerLanguage .NET Output Window is cleared:

protected override void StartCalc()
{
    Output.Clear();
}

Since the StartCalc() method is executed once at the start of every full calculation cycle (see MultiCharts, 2013), calling Output.Clear() will empty the Output Window once the indicator has been applied to a chart.

‘Stopping’ a MultiCharts .NET indicator conditionally

The next part of the example is the CalcBar() override method. In this method we start with an if statement:

if (!Bars.LastBarOnChart)
    return;

When the current bar is not the last bar on the chart (evaluated with the ! logical not operator), the return statement is called and the calculation of the indicator is 'stopped'.

Working with a MultiCharts .NET script’s calculation reason

Next the switch statement is used to switch on one of two possible Environment.CalcReason enumerators:

// Output calculation reason
switch (Environment.CalcReason)
{
    case CalculationReason.Default:
        Output.WriteLine("{0} - Calculation based on a price update",
            DateTime.Now.ToString("HH:mm:ss"));
        break;

    case CalculationReason.Timer:
        Output.WriteLine("{0} - Calculation based on a RecalcLastBarAfter timer",
            DateTime.Now.ToString("HH:mm:ss"));
        break;

    default:
        break;
}

Both the Default and Timer enumerators from the CalculationReason enumeration are outputted in a similar way. Each calls the Output.WriteLine() method with a string argument formulated with a substitution parameter that includes the computer DateTime formatted to a string and a descriptive message of the calculation reason.

Recalculating a MultiCharts .NET script based on a time interval

To perform the time-based recalculation (i.e., the CalculationReason.Timer recalculations), first the ExecControl.RecalcLastBarAfter() method is called with a TimeSpan of 10 seconds:

// Recalculate the script after 10 seconds.
ExecControl.RecalcLastBarAfter(new TimeSpan(0, 0, 10));

When this time period has elapsed, the OnRecalcLastBarAfterEvent() method is called. That method triggers the actual recalculation of the CalcBar() method:

// This method is called every time the RecalcLastBarAfter TimeSpan elapses
protected override void OnRecalcLastBarAfterEvent()
{
    this.CalcBar();
}

To learn more, see how to periodically recalculate a MultiCharts .NET script.

Key points:

  • The Environment.CalcReason property returns an enumerator from the CalculationReason enumeration that specifies the calculation reason of the indicator or trading strategy;
  • This property can return one of 6 enumerators: RightMouseClick and LeftMouseClick for when the calculation is triggered by a mouse click;
  • Default signals a calculation by a new price update, while Timer highlights a time-based recalculation;
  • The recalculation of a trading strategy can be triggered by MarketPositionChange or OrderFilled.
References

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

MultiCharts Wiki (2012, February 23). How Scripts Work. Retrieved on July 15, 2014, from http://www.multicharts.com/trading-software/index.php/How_Scripts_Work

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