Help me with correct use of Switch-Case Operator

 

Happy Weekend

I am trying to use "switch-case" operator and have following issue.

I have defined timeFrames locally as ENUM_TIMEFRAMES.

If I pass in this variable case mTFH01, I get error 'mTFH01' - constant expression required and if I pass in case PERIOD_H1, I get inconsistent results e.g. passed in pTimeFrame is mTFM15, and it gives result for mTFM01.

2022.10.01 16:53:45.336 2022.01.05 19:51:00   CStrategyBase::IsDoubleBottom: [PERIOD_M15] Double Bottom At Idx[1]

2022.10.01 16:53:45.336 2022.01.05 19:51:00   CStrategyBase::IsDoubleBottom: [PERIOD_M15] Double Bottom At Idx[1]

2022.10.01 16:53:45.336 2022.01.05 19:51:00   CStrategyBase::IsDoubleBottom: [PERIOD_M15] Double Bottom At Idx[1]

2022.10.01 16:53:45.337 2022.01.05 19:51:00   CStrategyBase::IsDBMethodII_M01: idxFB[13] Double Bottom[true]

I have tried to search in the forum for "constant expression required" but most of them are for array to be defined. However in my case there is no array of TimeFrames.

Also please guide me in terms of CPU Performance does "if-else" v/s "switch-case" operator make any difference ?

Look forward to resolve the error with support from experts here.

  
ENUM_TIMEFRAMES	    	mTFM01;
  ENUM_TIMEFRAMES	    	mTFM05;
  ENUM_TIMEFRAMES	    	mTFM15;
  ENUM_TIMEFRAMES	    	mTFH01; 

//+-----------------------------------------------------------------------------------------------------------------------------+
//| METHOD:     	IsDoubleBottom()
//| APPLICATION:  A SINGLE CALL METHOD TO FIND DOUBLE BOTTOM WITH METHOD[I] OR METHOD [II]
//+-----------------------------------------------------------------------------------------------------------------------------+
bool CStrategyBase::IsDoubleBottom(ENUM_TIMEFRAMES pTimeFrames,int pIndex=1) {

	int k = pIndex;

	switch(pTimeFrames) {
		case PERIOD_M15:
			PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
			if(IsDBMethod_I(mTFM15,k) || IsDBMethodII_M15(k))							return(true);
		case PERIOD_M5:
			PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
			if(IsDBMethod_I(mTFM05,k) || IsDBMethodII_M05(k))							return(true);
		case PERIOD_M1:
			PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
			if(IsDBMethod_I(mTFM01,k) || IsDBMethodII_M01(k))							return(true);
		default:													return(false);
	};

} // End of method IsDoubleBottom() 

Reversal patterns: Testing the Double top/bottom pattern
Reversal patterns: Testing the Double top/bottom pattern
  • www.mql5.com
Traders often look for trend reversal points since the price has the greatest potential for movement at the very beginning of a newly formed trend. Consequently, various reversal patterns are considered in the technical analysis. The Double top/bottom is one of the most well-known and frequently used ones. The article proposes the method of the pattern programmatic detection. It also tests the pattern's profitability on history data.
 

I think it's working fine, but you're missing a "break;" at the end of each case, otherwise all of them are executed. In my opnion, what happens is that it's entering the first case, the IF is false so no return, then there's no break and the second case is entered, same here, then the third case is run... Put a break at the end of each case, not inside of any if, but just at the end of the case. That'll break the code free from the Switch after entering a "case".

 
Carlos Moreno Gonzalez #:

I think it's working fine, but you're missing a "break;" at the end of each case, otherwise all of them are executed. In my opnion, what happens is that it's entering the first case, the IF is false so no return, then there's no break and the second case is entered, same here, then the third case is run... Put at break at the end of each case, not inside of any if, but just at the end of the case. That'll break the code free from the Switch after entering a "case".

Thanks Carlos

YES I was also thinking what you have mentioned " In my opinion, what happens is that it's entering the first case, the IF is false so no return, then there's no break and the second case is entered, same here, then the third case is run...". Thanks for confirming my thought.

About second suggestion, did you mean like this ?

        switch(pTimeFrames) {
                case PERIOD_M15:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM15,k) || IsDBMethodII_M15(k))                               return(true);
                        break;
                case PERIOD_M5:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM05,k) || IsDBMethodII_M05(k))                               return(true);
                        break;
                case PERIOD_M1:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM01,k) || IsDBMethodII_M01(k))                               return(true);
                        break;
                default:                                                                                return(false);
        };

In this case if it finds true value, then break is fine, but how will it react if found false ?

That is the confusion I have ...

 
Anil Varma #:

Thanks Carlos

YES I was also thinking what you have mentioned " In my opinion, what happens is that it's entering the first case, the IF is false so no return, then there's no break and the second case is entered, same here, then the third case is run...". Thanks for confirming my thought.

About second suggestion, did you mean like this ?

In this case if it finds true value, then break is fine, but how will it react if found false ?

That is the confusion I have ...

Well, they way you have it, you're gonna get an error stating not all paths return a value, which is true. I mean inside each "case" you have an "if" and in case it's true, you return "true", but then if it's false you're not saying anything. You must do something in those cases. But instead of having a return(true) and a return(false) in every single "case" I'd simplify a bit this way:

        bool result = false;
        switch(pTimeFrames) {
                case PERIOD_M15:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM15,k) || IsDBMethodII_M15(k))
                                result = true;
                        break;
                case PERIOD_M5:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM05,k) || IsDBMethodII_M05(k))
                                result = true;
                        break;
                case PERIOD_M1:
                        PrintFormat("%s: [%s] Double Bottom At Idx[%i]",(string)__FUNCTION__,EnumToString(pTimeFrames),pIndex);
                        if(IsDBMethod_I(mTFM01,k) || IsDBMethodII_M01(k))
                                result = true;
                        break;
        };
        return(result);
 
Adding the breaks will fix the problem, as will creating the boolean variable.
if(IsDBMethod_I(mTFM15,k) || IsDBMethodII_M15(k)) return(true);
But since you want to return true or false, you can simplify your code without the breaks.
return IsDBMethod_I(mTFM15,k) || IsDBMethodII_M15(k);
          Increase Order after stoploss - MQL4 programming forum #1.3 (2017)
 
William Roeder #
Adding the breaks will fix the problem, as will creating the boolean variable.
But since you want to return true or false, you can simplify your code without the breaks.
          Increase Order after stoploss - MQL4 programming forum #1.3 (2017)

Thanks William

Can you let me know how to include other user also in the reply ?

yup the simplified method you suggested sounds good. However clarify me one thing, switch(mTimeFrame) have 'mTFM15' as variable of ENUM_TIMEFRAME type. This variable should be compared in case statement and enter it that matches. It should not enter into other case statement, that is the purpose of switch-case operator, I feel so.

give me your thoughts on it. 

 
Carlos Moreno Gonzalez #:

Well, they way you have it, you're gonna get an error stating not all paths return a value, which is true. I mean inside each "case" you have an "if" and in case it's true, you return "true", but then if it's false you're not saying anything. You must do something in those cases. But instead of having a return(true) and a return(false) in every single "case" I'd simplify a bit this way:

Hi Carlos

Please check my reply to William's post. I din't knew how to include your name in that reply, so here is this notification.

Thanks a lot  

 
Anil Varma #:

Hi Carlos

Please check my reply to William's post. I din't knew how to include your name in that reply, so here is this notification.

Thanks a lot  

Hi Anil,

Yes, it's supposed to work this way, but "switch" is a bit special. If you don't include "break;" it will enter the "case" that matches the conditions, not the "case" before that, BUT... after that it'll execute every line in the "switch" until it finds a "break". For example, if you "TF15" was in the middle of the switch, the flow won't enter the first "case", it will enter the second because the condition matches, but if you don't have a "break" then it'll execute also the third "case".  Don't ask me why - it's just like that. 

Therefore the first part is true, and only the right "case" is entered, but then every line is executed since there was no "break;" sentence. It's a bit special - you just have to know it's like that. Good luck.

 
You could look into the MA code from Examples folder.

Depending on which calculation method (SMA/EMA/SMMA/LWMA) is picked in the inputs there is a different function activated by precisely a switch case function.

Then if you really want to look at it run through the lines of code put stopping points on every line of the switch function and click through it in the debugger.

Also by using different Styler settings the nested functions which make up switch case are arranged in different ways that can help you understand their hierarchies by various indentations.
 
Carlos Moreno Gonzalez #:

Hi Anil,

Yes, it's supposed to work this way, but "switch" is a bit special. If you don't include "break;" it will enter the "case" that matches the conditions, not the "case" before that, BUT... after that it'll execute every line in the "switch" until it finds a "break". For example, if you "TF15" was in the middle of the switch, the flow won't enter the first "case", it will enter the second because the condition matches, but if you don't have a "break" then it'll execute also the third "case".  Don't ask me why - it's just like that. 

Therefore the first part is true, and only the right "case" is entered, but then every line is executed since there was no "break;" sentence. It's a bit special - you just have to know it's like that. Good luck.

Hi Carlos 

yes this is very help full information about switch-case. I will rather go back to if .. else statement which was earlier working well.

Thanks a lot for updating my knowledge 

 
Tobias Johannes Zimmer #:
You could look into the MA code from Examples folder.

Depending on which calculation method (SMA/EMA/SMMA/LWMA) is picked in the inputs there is a different function activated by precisely a switch case function.

Then if you really want to look at it run through the lines of code put stopping points on every line of the switch function and click through it in the debugger.

Also by using different Styler settings the nested functions which make up switch case are arranged in different ways that can help you understand their hierarchies by various indentations.

Hi Tobias

Thanks for reminder, this is what exactly I am using in my MA Indicator code.

                switch(AppliedMethod) {

                        case MODE_LWMA:
                    LinearWeightedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPrice,BufferMA);

                    LinearWeightedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPriceVW,BufferPriceVWMA);
                    LinearWeightedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferVolume,BufferVolumeMA);
                                break;

                        case MODE_EMA:
                    ExponentialMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPrice,BufferMA);

                    ExponentialMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPriceVW,BufferPriceVWMA);
                    ExponentialMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferVolume,BufferVolumeMA);
                                break;

                        case MODE_SMMA:
                    SmoothedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPrice,BufferMA);

                    SmoothedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPriceVW,BufferPriceVWMA);
                    SmoothedMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferVolume,BufferVolumeMA);
                                break;

                        default:        // SIMPLE MOVING AVERAGE
                    SimpleMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPrice,BufferMA);

                    SimpleMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferPriceVW,BufferPriceVWMA);
                    SimpleMAOnBuffer(rates_total,prev_calculated,vBegin,MAPeriod,BufferVolume,BufferVolumeMA);
                                break;

I feel that the problem is mTFM15 (not an ENUM VALUE) as ENUM_TIMEFRAMES variable passed into switch(pTimeFrame) and I am using in case as PERIOD_M15, they do not match and hence loops every case statement.

In the above example Applied Method equals one of ENUM VALUES and then case MODE EMA or so compares the same with passed in Applied Method, they match and returns the correct case value.

Well thanks for your support and learning I got from these feed backs.