Situation
You want to know how to recalculate a MultiCharts .NET indicator or trading strategy with a mouse click, for example when your script needs to output data or make external connections again.

Programming example

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

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

        protected override void StartCalc()
        {
            PrintWithTime("StartCalc(): beginning calculating..");
        }
        
        protected override void CalcBar()
        {
            if (Bars.CurrentBar < (Bars.FullSymbolData.Count - 10))
                return;

            if (Environment.CalcReason == CalculationReason.LeftMouseClick)
            {
                PrintWithTime("Calculating due to a left mouse click. Bar #" +
                    Bars.CurrentBar.ToString());
            }
            else
            {
                PrintWithTime("Calculating on bar #" + Bars.CurrentBar.ToString());
            }
        }

        protected override void OnMouseEvent(MouseClickArgs arg)
        {
            if (arg.buttons != MouseButtons.Left)
                return;

            if (arg.keys == Keys.Control)
            {
                PrintWithTime("Control + left click: recalculating on all bars.");
                ExecControl.Recalculate();
            }
            else if (arg.keys == Keys.Shift)
            {
                PrintWithTime("Shift + left click: recalculating current bar.");
                this.CalcBar();
            }
        }

        private void PrintWithTime(string message)
        {
            Output.WriteLine("{0} - {1}",
                DateTime.Now.ToString("HH:mm:ss.fff"),
                message);
        }
    }
}

Output of the programming example

The example generates the following output:

07:32:08.767 - StartCalc(): beginning calculating..
07:32:08.769 - Calculating on bar #408
07:32:08.769 - Calculating on bar #409
07:32:08.769 - Calculating on bar #410
07:32:08.769 - Calculating on bar #411
07:32:08.769 - Calculating on bar #412
07:32:08.769 - Calculating on bar #413
07:32:08.769 - Calculating on bar #414
07:32:08.769 - Calculating on bar #415
07:32:08.769 - Calculating on bar #416
07:32:08.769 - Calculating on bar #417
07:32:12.410 - Shift + left click: recalculating current bar.
07:32:12.410 - Calculating due to a left mouse click. Bar #418
07:32:13.739 - Shift + left click: recalculating current bar.
07:32:13.739 - Calculating due to a left mouse click. Bar #418
07:32:15.489 - Shift + left click: recalculating current bar.
07:32:15.489 - Calculating due to a left mouse click. Bar #418
07:32:19.215 - Shift + left click: recalculating current bar.
07:32:19.215 - Calculating due to a left mouse click. Bar #418
07:32:21.497 - Control + left click: recalculating on all bars.
07:32:21.500 - StartCalc(): beginning calculating..
07:32:21.501 - Calculating on bar #408
07:32:21.501 - Calculating on bar #409
07:32:21.501 - Calculating on bar #410
07:32:21.501 - Calculating on bar #411
07:32:21.501 - Calculating on bar #412
07:32:21.501 - Calculating on bar #413
07:32:21.502 - Calculating on bar #414
07:32:21.502 - Calculating on bar #415
07:32:21.502 - Calculating on bar #416
07:32:21.502 - Calculating on bar #417
07:32:23.694 - Shift + left click: recalculating current bar.
07:32:23.694 - Calculating due to a left mouse click. Bar #418

Working with mouse clicks in MultiCharts .NET

Programmatically recognising if a mouse click occurred on a price chart provides a wide range of possibilities to programmatically control MultiCharts .NET. For example, mouse clicks can be used to reload price data, turn a script on or off, or submit trading orders.

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

Processing mouse clicks in MultiCharts .NET requires two things:

  • The MouseEvents attribute needs to be added;
  • The OnMouseEvent() method, used for processing mouse clicks (see PowerLanguage .NET Help, n.d.), needs to be implemented.

One way to work with mouse events is to recalculate scripts based on mouse clicks.

Recalculating scripts immediately in MultiCharts .NET

The immediate recalculation of a script is done by calling the ExecControl.Recalculate() method (PowerLanguage .NET Help, n.d.). This method forces the script to be calculated again, beginning with the StartCalc() override method and followed by executing the CalcBar() method on every price bar.

See recalculating a script immediately and recalculating a script periodically to learn more about script recalculation in MultiCharts .NET.

MultiCharts .NET programming example

The example begins with setting several MultiCharts .NET attributes:

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

MouseEvents set to true enables processing mouse clicks, while SameAsSymbol set to true prevents the indicator from creating a separate sub-chart. The UpdateOnEveryTick attribute set to false only lets the indicator calculate on bar close.

Output information at the start of every calculation cycle

Next is the StartCalc() override method:

protected override void StartCalc()
{
    PrintWithTime("StartCalc(): beginning calculating..");
}

This method, executed once at the start of every calculation cycle (MultiCharts, 2013), outputs information with the PrintWithTime() method to keep track of the indicator.

This PrintWithTime() method is implemented as follows:

private void PrintWithTime(string message)
{
    Output.WriteLine("{0} - {1}",
        DateTime.Now.ToString("HH:mm:ss.fff"),
        message);
}

The method calls Output.WriteLine() to output data to the Output Window. The outputted string is generated with substitution parameters and contains the current computer DateTime formatted to a string and the message parameter. This small method makes for a convenient way to print a message with the current time.

Processing MultiCharts .NET price bars

The CalcBar() method is the next part:

protected override void CalcBar()
{
    if (Bars.CurrentBar < (Bars.FullSymbolData.Count - 10))
        return;

    if (Environment.CalcReason == CalculationReason.LeftMouseClick)
    {
        PrintWithTime("Calculating due to a left mouse click. Bar #" +
            Bars.CurrentBar.ToString());
    }
    else
    {
        PrintWithTime("Calculating on bar #" + Bars.CurrentBar.ToString());
    }
}

This method consists out of two parts. First, an if statement evaluates if the current bar (Bars.CurrentBar) is less than the total number of bars minus 10 (Bars.FullSymbolData.Count - 10). When that is the case, the return statement is used to skip the remainder of the CalcBar() method. This causes the indicator to only print its output on the last few bars, which keeps the Output Window uncluttered.

See access any historical price bar to learn more about FullSymbolData. And to learn more about return, see how to ‘stop’ a script from calculating.

By the way, the return statement causes the method (CalcBar() in this case) to exit immediately, returning control to the calling method (Stellman & Greene, 2010).

The second part is an if-else statement (lines 24-32) that uses the enumerator returned by the Environment.CalcReason property to see if the calculation is triggered by a left mouse click (CalculationReason.LeftMouseClick). When that is the case, an accompanying message is printed (lines 26-27); otherwise, a default message is printed (line 31). This shows how the calculation reason can be used in an indicator or trading strategy.

Processing mouse clicks in MultiCharts .NET

To process the mouse clicks, the OnMouseEvent() method is implemented as follows:

protected override void OnMouseEvent(MouseClickArgs arg)
{
    if (arg.buttons != MouseButtons.Left)
        return;

    if (arg.keys == Keys.Control)
    {
        PrintWithTime("Control + left click: recalculating on all bars.");
        ExecControl.Recalculate();
    }
    else if (arg.keys == Keys.Shift)
    {
        PrintWithTime("Shift + left click: recalculating current bar.");
        this.CalcBar();
    }
}

Both the if statement and if-else statement use the arg variable in their expressions. This variable contains the data of the MouseClickArgs struct, which has several fields with mouse click information (such as location and type of mouse button).

P.S. Both the Keys and MouseButtons enumerations are located in the System.Windows.Forms namespace. To not having to provide this namespace repeatedly, it is included with the using keyword (line 5).

The if statement (lines 37-38) checks to see if the mouse click button (arg.buttons) is not equal to a left mouse button (MouseButtons.Left). Since only left mouse buttons are meant to be processed, the return statement is called for any other button to prematurely exit the OnMouseEvent() method.

In the if-else statement (lines 40-49) the keyboard keys accompanying the mouse click are processed. When a mouse click was registered while the Control key was pressed down (Keys.Control), a message is printed and the ExecControl.Recalculate() method is called to recalculate the indicator on all price bars.

A mouse click that was accompanied with a pressed down Shift key (Keys.Shift) will also have a message printed but will only cause the current bar to be recalculated. This is done by using the this keyword, which refers to the current instance of the object (Liberty & MacDonald, 2009), and the CalcBar() override method, which processes the current price bar (see MultiCharts, 2013).

Depending on the keyboard key accompanying the mouse click, the indicator will be recalculated from the first price bar to the last or only on the last price bar.

Key points:

  • Working with mouse events requires adding the MouseEvents attribute and implementing the OnMouseEvent() method;
  • A script can be recalculated on all price bars (with the ExecControl.Recalculate() method) or only again on the current bar (with this.CalcBar());
  • The Environment.CalcReason property returns an enumerator from the CalculationReason enumeration that is used to determine the (re)calculation reason of a script.
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.