Evaluate indicator at close of bar

Created at 26 Jul 2023, 12:36
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!
SJ

sjolandersimon

Joined 26.07.2023

Evaluate indicator at close of bar
26 Jul 2023, 12:36


Hello,

 

I am working on a custom indicator that produces a “1” when the criteria is valid, else “0”.

I would like the code to be evaluated at the close of the bar, alternatively at the start of the new bar, whatever is the most convenient regarding the code.

The current issue is that the indicator produces signals for historical data, but not for live real-time data.

Do you guys have any idea  what the issue might be, and do you have any suggestions how improve the code?

 

using System;
using cAlgo.API;
using cAlgo.API.Indicators;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]

    #region Indicator

    public class CustomIndicator : Indicator
    {
        [Output("Main", LineColor = "Black", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries Result { get; set; }


        // Creating the ExponentialMovingAverage indicators with specified periods 
        private ExponentialMovingAverage ema100;
        private ExponentialMovingAverage ema200;
        private ExponentialMovingAverage ema999;
        
        // Creating the RSI indicators with specified period 
        private RelativeStrengthIndex rsi;
        
        // Creating the variable class lastIndex 
        private int lastIndex;
        
        #endregion

        #region Initialize

        protected override void Initialize()
        {
            // Initialize the ExponentialMovingAverage indicators with specified periods    
            ema100 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 100);
            ema200 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 200);
            ema999 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 999);
            
            // Initialize the RSI indicator with period of 5
            rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 5);
            
            // Initialize the lastIndex variable as the integer 0
            lastIndex = 0;
        }

        #endregion

        #region Calculate

        public override void Calculate(int index)
        {
            // If the current index is higher than the last index used in calculation, proceed with the calculation
            // This implies that the calculation is only run once per bar, in the start of the newly formed bar.
            if (index > lastIndex)
            {
               
            // Calculate if criteria for the first signal is met
            bool firstCriteriaMet = 
                Bars.ClosePrices[index] > ema200.Result[index] &&
                ema100.Result[index] > ema200.Result[index] &&
                ema200.Result[index] > ema999.Result[index] &&
                rsi.Result[index] < 20 && rsi.Result[index - 1] >= 20;
                
            // Calculate if criteria for the second signal is met
            bool secondCriteriaMet = 
                Bars.ClosePrices[index] < ema200.Result[index] &&
                ema100.Result[index] < ema200.Result[index] &&
                ema200.Result[index] < ema999.Result[index] &&
                rsi.Result[index] > 80 && rsi.Result[index - 1] <= 80;

            // Assign the Result value based on if any of the conditions are met
            bool conditionMet = firstCriteriaMet || secondCriteriaMet;
            Result[index] = conditionMet ? 1 : 0;

            // Save the current index as the last used index
            lastIndex = index;


            }

          }

           #endregion

       }
    }
}

 

Thank you!

Best Regards, 

Simon


@sjolandersimon
Replies

PanagiotisChar
26 Jul 2023, 13:06

Hi there,

The current issue is that the indicator produces signals for historical data, but not for live real-time data.

How did you come this conclusion?

Aieden Technologies

Need help? Join us on Telegram


 


@PanagiotisChar

sjolandersimon
26 Jul 2023, 13:18 ( Updated at: 21 Dec 2023, 09:23 )

RE: Evaluate indicator at close of bar

 

Thank you for the fast reply.

With the given code setup, the indicator produces signals for historical data, see the picture below for the example Gold. 

But when the indicator is live and evaluating the most recent real-time data, no signal is produced, even though the criteria is meet. I have come to this conclusion by watching new price bars forming.

PanagiotisChar said: 

Hi there,

The current issue is that the indicator produces signals for historical data, but not for live real-time data.

How did you come this conclusion?

Aieden Technologies

Need help? Join us on Telegram


 

 


@sjolandersimon

PanagiotisChar
26 Jul 2023, 13:37

Hi again,

Try removing this condition

if (index > lastIndex) 

It causes the problem and I don't see the point of it


@PanagiotisChar

PanagiotisChar
26 Jul 2023, 13:37

Hi again,

Try removing this condition

if (index > lastIndex) 

It causes the problem and I don't see the point of it


@PanagiotisChar

sjolandersimon
26 Jul 2023, 14:20

RE: Evaluate indicator at close of bar

PanagiotisChar said: 

Hi again,

Try removing this condition

if (index > lastIndex) 

It causes the problem and I don't see the point of it

 

Thanks for the reply. 

When I remove the line of codes related to the "private int lastIndex", the indicator produces signals meeting the criteria for real-time price data. Although it evaluates at ever tick, resulting in all to many signals.

What would you recommend using as code to make the indicator only to be evaluated at the start of a new bar?

 


@sjolandersimon

PanagiotisChar
27 Jul 2023, 05:21

Hi,

It's wrong to evaluate at the opening of the previous bar. This is what you were doing before and was not working. The indicator should be calculated on every tick until the bar closes. Regarding signals (I guess you are reading this from a cBot?) you should only consider closed bars.

Aieden Technologies

Need help? Join us on Telegram


 


@PanagiotisChar

sjolandersimon
31 Jul 2023, 20:05

RE: Evaluate indicator at close of bar

PanagiotisChar said: 

Hi,

It's wrong to evaluate at the opening of the previous bar. This is what you were doing before and was not working. The indicator should be calculated on every tick until the bar closes. Regarding signals (I guess you are reading this from a cBot?) you should only consider closed bars.

Aieden Technologies

Need help? Join us on Telegram


 

Thanks for the reply, I appreciate your effort!

When the indicator is evaluated at every tick, a signal is produced every time the condition is met during the length of that bar.

I am using an email notification, and my actual problem is that I am receiving an email for every tick the condition is met during the length of the bar. I would like to only receive one email at the close of the bar if the condition is met at the close of that bar. Do you have any suggestion how to proceed based on this information?

Actually I am working with chatGPT to produce code. The AI can produce a lot of interesting code, but you have to be very specific and you often have to modify the code in some degree. 

 


@sjolandersimon

PanagiotisChar
01 Aug 2023, 07:32

Hi,

I would like to only receive one email at the close of the bar if the condition is met at the close of that bar. Do you have any suggestion how to proceed based on this information?

You need to have a flag that would check if an alert was triggered within that bar and send the alert only when it hasn't. Reset this flag on each bar change.

Aieden Technologies

Need help? Join us on Telegram


@PanagiotisChar

sjolandersimon
02 Aug 2023, 19:47

RE: Evaluate indicator at close of bar

PanagiotisChar said: 

Hi,

I would like to only receive one email at the close of the bar if the condition is met at the close of that bar. Do you have any suggestion how to proceed based on this information?

You need to have a flag that would check if an alert was triggered within that bar and send the alert only when it hasn't. Reset this flag on each bar change.

Aieden Technologies

Need help? Join us on Telegram

Hi Panagiotis,

Thanks for the reply and suggestion in how to improve the code.

I have made somewhat progress with the script. Below are two different scripts for the same criteria and is calculated at every tick respectively once at the close of the bar.

The 1st script below have the following prerequisites:

  • Calculations are done at every tick
  • Email notification is sent (and received) when the criteria is met. Several emails are sent due to the criteria is met several times during the length of a bar.
using System;
using System.Linq;
using System.Net.Mail;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class CustomIndicator : Indicator
    {
        [Output("Main", LineColor = "Black", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries Result { get; set; }

        private ExponentialMovingAverage ema100;
        private ExponentialMovingAverage ema200;
        private ExponentialMovingAverage ema999;
        private RelativeStrengthIndex rsi;


        protected override void Initialize()
        {
            ema100 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 100);
            ema200 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 200);
            ema999 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 999);
            rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 5);
        }

        public override void Calculate(int index)
        {


            bool firstCriteriaMet = 
                Bars.ClosePrices[index] > ema200.Result[index] &&
                ema100.Result[index] > ema200.Result[index] &&
                ema200.Result[index] > ema999.Result[index] &&
                rsi.Result[index] < 20 && rsi.Result[index - 1] >= 20;

            bool secondCriteriaMet =
                Bars.ClosePrices[index] < ema200.Result[index] &&
                ema100.Result[index] < ema200.Result[index] &&
                ema200.Result[index] < ema999.Result[index] &&
                rsi.Result[index] > 80 && rsi.Result[index - 1] <= 80;

            // Assign the Result value based on if any of the conditions are met
            Result[index] = (firstCriteriaMet || secondCriteriaMet) ? 1 : 0;

            // Send a notification if the condition is met
            if (firstCriteriaMet || secondCriteriaMet)
            {
                Notifications.SendEmail("XXX@outlook.com", "XXX@outlook.com", "cTrader alert", $"1h Mark up or down: {SymbolName}");
            }

        }
        
    }
}

The 2nd script below have the following prerequisites:

  • Calculations are done once per bar, which I have seen works in real time when the criteria has been met at the close of the bar.
  • Email notification is not sent, and no information message is logged. I know that I have the right settings for the email system since it works for the 1st script.
using System;
using System.Linq;
using System.Net.Mail;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class CustomIndicator : Indicator
    {
        [Output("Main", LineColor = "Black", LineStyle = LineStyle.Solid)]
        public IndicatorDataSeries Result { get; set; }

        private ExponentialMovingAverage ema100;
        private ExponentialMovingAverage ema200;
        private ExponentialMovingAverage ema999;
        private RelativeStrengthIndex rsi;
        private int lastIndex = -1;

        protected override void Initialize()
        {
            ema100 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 100);
            ema200 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 200);
            ema999 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 999);
            rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 5);
        }

        public override void Calculate(int index)
        {
            if (index > lastIndex)
            {
                OnBarClosed(lastIndex);
                lastIndex = index;
            }
        }

        private void OnBarClosed(int index)
        {
            bool firstCriteriaMet = 
                Bars.ClosePrices[index] > ema200.Result[index] &&
                ema100.Result[index] > ema200.Result[index] &&
                ema200.Result[index] > ema999.Result[index] &&
                rsi.Result[index] < 20 && rsi.Result[index - 1] >= 20;

            bool secondCriteriaMet =
                Bars.ClosePrices[index] < ema200.Result[index] &&
                ema100.Result[index] < ema200.Result[index] &&
                ema200.Result[index] < ema999.Result[index] &&
                rsi.Result[index] > 80 && rsi.Result[index - 1] <= 80;

            // Assign the Result value based on if any of the conditions are met
            Result[index] = (firstCriteriaMet || secondCriteriaMet) ? 1 : 0;

            // Send a notification if the condition is met
            if (firstCriteriaMet || secondCriteriaMet)
            {
                Notifications.SendEmail("XXX@outlook.com", "XXX@outlook.com", "cTrader alert", $"1h Mark up or down: {SymbolName}");
            }

        }
        
    }
}

So to the question. I am trying to get the 2nd script to work with regards to email notification being sent. My suspicion is that it has something to do with email notification system not working well in current conditions when it is evaluated once per bar?

What are your suggestion how to improve further with regards to the issues with email notification and the 2nd script?


@sjolandersimon