How to add functionality to the MessageBoxButton?

Created at 24 Jul 2022, 14:21
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
CT

ctid3999979

Joined 05.07.2021

How to add functionality to the MessageBoxButton?
24 Jul 2022, 14:21


Hi

I'm adding functionality to an indicator that will display a message stating that my daily target has been reached and tell me to close cTrader. I have a problem with over trading.

I'd like the message box to have an OK button, which when clicked will close cTrader. How do I add code to the method run when clicking OK? I presume the buttons can be customized as there is an option for YesNoCancel.

EDIT:

Ok, playing around. Is this on the right track?

MessageBoxResult targetMessageResult = MessageBox.Show(messageText, "Target Achieved", MessageBoxButton.OK, MessageBoxImage.Information);

            if (targetMessageResult == MessageBoxResult.OK)
            {
                Environment.Exit(0);
            }

 


@ctid3999979
Replies

PanagiotisCharalampous
25 Jul 2022, 12:26

Hi there,

It seems so :) Did you test it?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

ctid3999979
25 Jul 2022, 13:20

RE:

PanagiotisCharalampous said:

Hi there,

It seems so :) Did you test it?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

I did but I also converted it to .NET6 and I get errors when running it. All my indicators give me errors after converting to .NET6 so I'm just re-writing them from the ground up. I'll add this messagebox functionality later today and report back.


@ctid3999979

ctid3999979
25 Jul 2022, 14:52 ( Updated at: 25 Jul 2022, 14:53 )

RE:

PanagiotisCharalampous said:

Hi there,

It seems so :) Did you test it?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Unfortunately, indicator keeps crashing when DailyTargetHit method gets called with the following error. It briefly displayed the messagebox but immediately closed.

25/07/2022 11:53:15.439 | Crashed in Calculate with ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: y2. Actual value was: NaN.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class DailyProfitNET6 : Indicator
    {
        [Parameter("Daily Target (%)", DefaultValue = 12.0)]
        public double dailyTargetInput { get; set; }

        private TextBlock[] profitTextBlock = new TextBlock[4];
        private StackPanel profitPanel;

        Profits currentOpenProfits;
        Profits dailyprofits;

        protected override void Initialize()
        {
            currentOpenProfits = UpdateOpenPositionProfits();

            // Create a stackPanel for the textBlocks to display the profit output
            profitPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                BackgroundColor = Color.Black,
                Margin = 5
            };

            for (int i = 0; i < profitTextBlock.Count(); i++)
            {
                // Configure each of the textBlocks
                profitTextBlock[i] = new TextBlock
                {
                    Text = "",
                    ForegroundColor = Color.White
                };
                profitPanel.AddChild(profitTextBlock[i]);
            }
            Chart.AddControl(profitPanel);
        }

        public override void Calculate(int index)
        {
            currentOpenProfits = UpdateOpenPositionProfits();
            dailyprofits = UpdateDailyProfits(currentOpenProfits);

            // Display profit/loss information
            DisplayProfits(currentOpenProfits, dailyprofits);

            // If daily target achieved, inform the user.
            if (Positions.Count == 0 && dailyprofits.PercentageOfBalance >= dailyTargetInput)
            {
                DailyTargetHit(dailyprofits);
            }
        }

        public struct Profits
        {
            // Create Profits object
            public double Monetary;
            public double PercentageOfBalance;
        }

        public Profits UpdateOpenPositionProfits()
        {
            Profits profits = new Profits();

            if (Positions.Count > 0)
            {
                // If there are open positions, sum all the net profits and calculate percentage profit/loss of the balance
                profits.Monetary = Math.Round(Positions.Sum(p => p.NetProfit), 2);
                profits.PercentageOfBalance = Math.Round(profits.Monetary / Account.Balance * 100, 2);
            }
            else
            {
                profits.Monetary = 0.0;
                profits.PercentageOfBalance = 0.0;
            }

            return profits;
        }

        public Profits UpdateDailyProfits(Profits openPositionsProfits)
        {
            Profits dailyProfits = new Profits();
            double todaysClosedPositionValue;
            double todaysStartingBalance;

            //Gget account balance and cumulative total of todays trades. As this function initially gets called in
            // the initialize() method, it starts by getting todays starting balance
            if (History.Count > 0)
            {
                todaysClosedPositionValue = History.Where(p => p.ClosingTime.Date == Time.Date).Sum(p => p.NetProfit);
                todaysStartingBalance = History.Where(p => p.ClosingTime.Date == Time.Date).OrderBy(p => p.ClosingTime).Last().Balance;
            }
            else
            {
                todaysClosedPositionValue = 0.0;
                todaysStartingBalance= 0.0;
            }

            dailyProfits.Monetary = Math.Round(openPositionsProfits.Monetary + todaysClosedPositionValue, 2);
            dailyProfits.PercentageOfBalance = Math.Round(dailyProfits.Monetary / todaysStartingBalance * 100, 2);

            return dailyProfits;
        }

        // Set the foreground color of the monetary profit/loss text
        public Color ProfitTextForegroundColor(double profits)
        {
            if (profits > 0)
            {
                return Color.LimeGreen;
            } 
            else if (profits < 0)
            {
                return Color.Red;
            }
            else
            {
                return Color.White;
            }
        }

        public void DisplayProfits(Profits currentOpenProfits, Profits dailyProfits)
        {
            // Open trades cumulative profit/loss as monetary value
            profitTextBlock[0].Text = $"Open Positions Monetary Profit/Loss: £{currentOpenProfits.Monetary.ToString()}";
            profitTextBlock[0].ForegroundColor = ProfitTextForegroundColor(currentOpenProfits.Monetary);

            // Open trades cumulative profit/loss as percentage of balance
            profitTextBlock[1].Text = $"Open Positions Percentage Profit/Loss: {currentOpenProfits.PercentageOfBalance.ToString()}%";
            profitTextBlock[1].ForegroundColor = ProfitTextForegroundColor(currentOpenProfits.PercentageOfBalance);

            // Todays trades cumulative profit/loss as monetary value
            profitTextBlock[2].Text = $"Daily Monetary Profit/Loss: £{dailyProfits.Monetary.ToString()}";
            profitTextBlock[2].ForegroundColor = ProfitTextForegroundColor(dailyProfits.Monetary);

            // Todays trades cumulative profit/loss as percentage of balance
            profitTextBlock[3].Text = $"Daily Percentage Profit/Loss: {dailyProfits.PercentageOfBalance.ToString()}";
            profitTextBlock[3].ForegroundColor = ProfitTextForegroundColor(dailyProfits.PercentageOfBalance);

        }

        // Display a messagebox when daily percentage target has been reached.
        public void DailyTargetHit(Profits dailyProfits)
        {
            string targetMessageText = $"Daily Target Achieved.\nClick OK to close cTrader.\n" +
                $"Total Profit: £{dailyProfits.Monetary.ToString()}\n" +
                $"Total Percentage: {dailyProfits.PercentageOfBalance.ToString()}%";

            MessageBoxResult targetMessageResult = MessageBox.Show(targetMessageText, "Target Achieved", MessageBoxButton.OK, MessageBoxImage.Information);

            if (targetMessageResult == MessageBoxResult.OK)
            {
                Environment.Exit(0);
            }
        }
    }
}

 


@ctid3999979

PanagiotisCharalampous
25 Jul 2022, 16:25

Hi,

Here is where your indicator crashes. 

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

ctid3999979
25 Jul 2022, 16:55 ( Updated at: 21 Dec 2023, 09:22 )

RE:

PanagiotisCharalampous said:

Hi,

Here is where your indicator crashes. 

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Interesting.

The indicator works fine other than the displaying of the messagebox. That line produces the expected output when the indicator is run.

I've been trying to debug with breakpoints by attaching the process to cTrader but it always tells me that the breakpoint won't be hit and no symbols have been loaded. I've tried adding var result = System.Diagnostics.Debugger.Launch(); to the Initialize function as per some instructions I saw but no luck.

 


@ctid3999979

PanagiotisCharalampous
25 Jul 2022, 17:00

Hi there,

The indicator does not work fine, it crashes as soon as I add it on the chart. If you check the reason above, it is obvious, the message self explanatory. You need to fix this in your code. You cannot call Last() if the sequence contains no elements.

Best Regards,

 

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

ctid3999979
25 Jul 2022, 17:08 ( Updated at: 21 Dec 2023, 09:22 )

RE:

PanagiotisCharalampous said:

Hi there,

The indicator does not work fine, it crashes as soon as I add it on the chart. If you check the reason above, it is obvious, the message self explanatory. You need to fix this in your code. You cannot call Last() if the sequence contains no elements.

Best Regards,

 

Panagiotis 

Join us on Telegram and Facebook

I'm certainly not doubting you. You know much more about this than I.

I'm just surprised because mine doesn't crash until it needs to display the messagebox. This is a screenshot of a fresh demo account with no trades performed.

What you said certainly explains the NaN. I was wondering why it was showing that. I'm thinking a simple IF statement, checking if History.Where(p => p.ClosingTime.Date == Time.Date) count is greater than 0 might help.


@ctid3999979