Situation
You only want to calculate a MultiCharts .NET script with mouse clicks, which is helpful for operations that are better not performed on every price update (such as reading text from a file).

Programming example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Windows.Forms;         // Added

namespace PowerLanguage.Indicator
{
    [UpdateOnEveryTick(false), SameAsSymbol(true), MouseEvents(true)]
    public class Example_OnlyCalcWithMouseClick : IndicatorObject
    {
        public Example_OnlyCalcWithMouseClick(object _ctx) : base(_ctx) { }
        
        protected override void StartCalc()
        {
            ExecInfo.MaxBarsBack = 20;
            Output.Clear();
        }
        
        protected override void CalcBar()
        {
            if (Environment.CalcReason != CalculationReason.LeftMouseClick)
                return;

            Output.WriteLine("{0} - Recalculating due to a left mouse click.\r\n\t" +
                "Average volume last 10 bars is: {1}",
                DateTime.Now.ToString("HH:mm:ss.fff"),
                AvgVolume(10));
        }

        private int AvgVolume(int barsBack)
        {
            int avgVolume = 0;

            for (int i = 0; i < barsBack; i++)
                avgVolume += (int)Bars.Ticks[i];

            return avgVolume / barsBack;
        }

        protected override void OnMouseEvent(MouseClickArgs arg)
        {
            if (arg.keys == Keys.None && arg.buttons == MouseButtons.Left)
                this.CalcBar();
        }
    }
}

Output of the programming example

With a few clicks on the chart the output is as follows:

11:38:12.276 - Recalculating due to a left mouse click.
    Average volume last 10 bars is: 662236
11:38:13.156 - Recalculating due to a left mouse click.
    Average volume last 10 bars is: 662401
11:38:13.873 - Recalculating due to a left mouse click.
    Average volume last 10 bars is: 662589

Working with mouse clicks in MultiCharts .NET

MultiCharts .NET scripts can process mouse clicks and this provides several ways to programmatically control MultiCharts .NET, such as turning a script on or off, submitting trading orders, or reloading price data.

See working with mouse events and combining mouse clicks with keyboard keys to learn more about working with MultiCharts .NET’s mouse events.

Processing mouse clicks in MultiCharts .NET has two requirements:

  • The MouseEvents attribute needs to be enabled;
  • The OnMouseEvent() method, which programmatically deals with mouse clicks on the chart (see PowerLanguage .NET Help, n.d.), needs to be added.

One way to use mouse clicks is by controlling the (re)calculations of an indicator or trading strategy.

Performing a (re)calculation in MultiCharts .NET

The (re)calculation of a script can be influenced in different ways (e.g., see MultiCharts, 2013; PowerLanguage .NET Help, n.d.):

  • A complete recalculation (from the first to the last price bar) is triggered by calling the ExecControl.Recalculate() method;
  • The current price bar can be recalculated by executing the CalcBar() override method again;
  • When using mouse clicks, the OnMouseEvent() method can call other methods, in effect bypassing the CalcBar() method completely (see only execute methods with a mouse click);
  • The calculation reason (returned by the Environment.CalcReason property) can be used to only execute statements when a certain calculation reason occurs.

See recalculating a script with mouse clicks to learn about recalculating a complete script or just the current price bar with mouse clicks.

The example uses the last option: statements are only executed when the calculation is triggered by a left mouse click.

MultiCharts .NET programming example

The example begins with setting several MultiCharts .NET attributes:

[UpdateOnEveryTick(false), SameAsSymbol(true), MouseEvents(true)]

UpdateOnEveryTick set to false ensures that the indicator is only calculated on bar close, while SameAsSymbol set to true will plot the indicator on the main price chart. Setting MouseEvents to true enables the processing of mouse clicks.

Setting the MaxBarsBack of an indicator programmatically

Next is the StartCalc() method:

protected override void StartCalc()
{
    ExecInfo.MaxBarsBack = 20;
    Output.Clear();
}

The ExecInfo.MaxBarsBack property is used here to set the MaxBarsBack programmatically to 20 to prevent a recalculation due to an automatically determined MaxBarsBack.

To learn more about MaxBarsBack, see what are MaxBarsBack and how do they work?.

The Output.Clear() method is called to clear the PowerLanguage .NET Editor Output Window.

Calculating on left mouse clicks only in MultiCharts .NET

The next part is the CalcBar() override method:

protected override void CalcBar()
{
    if (Environment.CalcReason != CalculationReason.LeftMouseClick)
        return;

    Output.WriteLine("{0} - Recalculating due to a left mouse click.\r\n\t" +
        "Average volume last 10 bars is: {1}",
        DateTime.Now.ToString("HH:mm:ss.fff"),
        AvgVolume(10));
}

The if statement evaluates whether the calculation reason of the script (returned by the Environment.CalcReason enumerator) is unequal to a left mouse click. When that is the case, the return statement is executed. This statement immediately exits the current method (Stellman & Greene, 2010), causing the remaining statements in the CalcBar() method to be skipped.

To learn more about return, see how to ‘stop’ an indicator from calculating and turning a script on and off with mouse clicks.

P.S. Adding the System.Windows.Forms namespace (see line 5) makes referencing the Keys and MouseButtons enumerations easier.

When the calculation is triggered by a left mouse click, the return statement is not executed and a message is printed to the Output Window (lines 25-28). Its string argument is formatted with substitution parameters and the \r\n\t escape characters (which insert a newline and a Tab). Two values are inserted in the string: the current computer DateTime formatted to a string and the value returned by the AvgVolume() method.

Calculating the average volume for the last few bars

This AvgVolume() method is created as follows:

private int AvgVolume(int barsBack)
{
    int avgVolume = 0;

    for (int i = 0; i < barsBack; i++)
        avgVolume += (int)Bars.Ticks[i];

    return avgVolume / barsBack;
}

Several things are done in this method. First, an integer variable is declared and initialised to zero (line 33).

Then a for loop iterates over the historical price bars, starting from the current bar and continuing as long as i is less than the barsBack parameter. During each iteration, the price bar volume data (Bars.Ticks) is added to the avgVolume variable with the += self-assignment operator. This operator is a shorthand way to write avgVolume = avgVolume + (int)Bars.Ticks[i] (see Liberty & MacDonald, 2009). Because avgVolume is an integer variable while Bars.Ticks returns a double variable, explicit casting to int is needed (i.e., (int)Bars.Ticks[i]).

The last statement (line 38) returns the average volume by dividing the sum of volume by the number of bars back.

Processing mouse clicks in MultiCharts .NET

The last part of the example is the OnMouseEvent() method:

protected override void OnMouseEvent(MouseClickArgs arg)
{
    if (arg.keys == Keys.None && arg.buttons == MouseButtons.Left)
        this.CalcBar();
}

The if statement verifies two expressions here: whether no keyboard key was pressed during the mouse click (Keys.None) and if the click was done with the left mouse button (MouseButtons.Left).

See combining mouse clicks with keyboard keys and using mouse clicks to turn a script on or off to learn more about mouse buttons and keyboard keys.

When both expressions evaluate to true, the CalcBar() method is executed again for the current bar. The this keyword refers to the current instance of an object (Liberty & MacDonald, 2009), and is used here to make an explicit reference.

Calling the CalcBar() method only performs a recalculation for the current bar. Use ExecControl.Recalculate() to recalculate the script on all price bars.

What happens in this example indicator is the following: a left mouse click processed by the OnMouseEvent() method triggers a recalculation of the CalcBar() override method (see lines 43-44). This causes the calculation reason of the script to become CalculationReason.LeftMouseClick, so the return statement is not triggered (see lines 22-23). And when return is not called, all statements in the CalcBar() method are executed. All programming code of the indicator is therefore only executed with a left mouse click.

Key points:

  • Working with mouse clicks requires adding the MouseEvents attribute and implementing the OnMouseEvent() method;
  • Calling the CalcBar() method in the OnMouseEvents() method causes a recalculation of the current price bar due to a mouse click;
  • When using the return statement conditionally in the CalcBar() method, certain programming code can be skipped when specific conditions occur.
References

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

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

PowerLanguage .NET Help (n.d.). Retrieved on May 16, 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.