Русский 中文 Español Deutsch 日本語 Português
preview
From Basic to Intermediate: SWITCH Statement

From Basic to Intermediate: SWITCH Statement

MetaTrader 5Examples | 16 April 2025, 14:27
2 417 0
CODE X
CODE X

Introduction

The content presented here is intended solely for educational purposes. Under no circumstances should the application be viewed for any purpose other than to learn and master the concepts presented.

In the previous article "From Basic to Intermediate: The Include Directive", we covered the basics of using the #include compilation directive. That article served as a brief pause, allowing you to properly absorb the information and take the time to study how to work with control flow statements. This is because it is indeed essential that you study and thoroughly understand how to use them. However, we are not quite finished yet. There are still two additional statements in MQL5 that we need to cover. They are somewhat more complex, mainly in terms of the attention required when using them.

For that reason, I will aim to approach both with greater care. This is important because even the slightest mistake you, as a programmer, may make when using these two final operators will almost certainly result in a significant waste of time as you try to identify the flaw in your code.

If you found the previous commands challenging and complex, brace yourself - these final two require even more attention. However, by the end of these articles, you will at least understand how each one functions. Therefore, the first prerequisite to following along with this article is being comfortable working with variables and constants, as well as understanding how to use the IF statement. If you're confident in those areas, you'll be ready to proceed and understand the content presented here.

As usual, let's begin a new topic. We will start discussing the second-to-last statement to be explained.


The SWITCH Statement

This statement - literally meaning "switch" - can serve as a possible alternative to the IF statement. However, there is an important nuance to understand before you can effectively use the SWITCH statement in place of IF.

To understand when and how this substitution is possible, it's important, dear reader, that you first understand a key concept. In programming, it's not uncommon to encounter situations where we test the same variable multiple times in search of a very specific value. This phrase "very specific" is the core idea here. The value cannot be greater, smaller, or even similar; it must be exactly the value we're looking for. No more, no less: EXACTLY.

In such scenarios, we can avoid using multiple IF statements and instead use a single SWITCH statement. However - and this is crucial - you need to be aware that the bit-width and the format of the variable used in a SWITCH statement play a significant role in whether or not it can be used effectively.

To summarize: you can only use SWITCH as a substitute for multiple IF statements if and only if the same variable is being checked across those IF conditions. Furthermore, you can only check whether the variable equals a certain value. It is not possible to check if it is greater than or less than that value. Also, the variable's bit-width can affect the evaluation result. This is, in very simple terms, what defines how the SWITCH statement works.

At first glance, this might seem overly complicated or at the very least impractical. However, quite the opposite is true. The SWITCH statement is widely used across many different scenarios. Even though it may initially appear limited or cumbersome, it is very useful in many real-world applications.

What truly makes the SWITCH statement somewhat confusing or daunting, particularly for beginner programmers, is how it behaves differently across various programming languages and contexts. That said, in this article, we'll focus specifically on how the SWITCH statement is used within MQL5. In this context, its behavior closely resembles that of the SWITCH statement in C/C++. You may even refer to C/C++ documentation as a supplementary resource to deepen your understanding of this construct. That's because what we'll cover here is just the foundation, an introductory look at how the statement works and a few precautions to keep in mind. There is a lot more to explore if you look into how SWITCH is implemented in C/C++.

Alright, I believe that gives you a good sense of what lies ahead and where you can dig deeper if you choose to. So now it's time to dive right in and begin exploring the SWITCH statement and its potential uses. To begin, we'll start with a very simple example that doesn't yet use the statement itself. Let's take a look at the code below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 5;
07. 
08.     if (counter == 5) Print("The counter value is five."); else
09.     if (counter == 3) Print("The counter value is three."); else
10.     if (counter == 1) Print("The counter value is one."); else
11.         Print("The counter value is unknown.");
12. }
13. //+------------------------------------------------------------------+

Code 01

I know many readers will look at this and say: "Man, what a silly piece of code." And yes, I know, it is. But we truly need to start with something very simple. Otherwise, you may end up completely lost trying to make sense of what's happening later on.

Just by looking at this code, you can clearly understand what will be displayed in the MetaTrader 5 terminal. Therefore, I believe it's entirely unnecessary to show the output message. Now, if you can't figure it out just by reading the code, dear reader, then I strongly and without the slightest hesitation recommend that you stop right here, rewind, and begin again from the very first article: From Basic to Intermediate: Variables (I). Don't think you'll learn how to program by skipping steps. You won't. Start by understanding the foundational concepts and commands before attempting to take bigger leaps into unfamiliar territory.

Alright, let's move on. At this point, you can clearly see that this code demonstrates exactly what we defined at the beginning of this topic. That is, we have a single variable being evaluated through multiple IF statements. Each of then is checking for one specific value. We are not checking whether the value is greater or less than something; we are looking for exact matches. That is the key point. In other words, once we have a situation like what's shown in Code 01, we can replace it with something more elegant. That something is the SWITCH statement.

Now that this is clearly defined and well understood, let's look at another code example that will produce the exact same result when executed. It is shown below:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 5;
07. 
08.     switch (counter)
09.     {
10.         case 5:
11.             Print("The counter value is five.");
12.             break;
13.         case 3:
14.             Print("The counter value is three.");
15.             break;
16.         case 1:
17.             Print("The counter value is one.");
18.             break;
19.         default:
20.             Print("The counter value is unknown.");
21.     }
22. }
23. //+------------------------------------------------------------------+

Code 02

And there you have it, dear reader. Code 02 is similar to Code 01 and produces the exact same result, with no difference in output whatsoever. But you might be thinking: "Man, this looks way more complicated. I'd rather stick with Code 01." And I won't argue, at first glance, Code 02 does appear more complex. So why would someone choose to use Code 02 instead of Code 01 when writing their programs? Well, the answer isn't quite so simple when we're discussing the SWITCH statement in its most basic form. However, I can assure you that there are many scenarios where SWITCH holds significant advantages over IF. This is because SWITCH possesses the capability that IF does not: the ability to handle other values during execution.

Now, this type of behavior is a more advanced topic when working with the SWITCH statement. I'm only mentioning it here so you don't dismiss SWITCH outright just because it may seem confusing or complicated. In reality, it's far more useful than it might initially appear.

Let's take a closer look at Code 02. You'll notice a few interesting elements being used here. First: what is this BREAK statement doing here? Isn't BREAK typically used inside loops? That's correct, dear reader. The BREAK statement is indeed used in loops. However, it is also used at specific points within a SWITCH statement. Its purpose is to control how the SWITCH executes. More specifically, when we use the BREAK statement, we're telling the compiler to stop executing the current SWITCH routine at that point. This way, the compiler knows exactly what to do next. In a sense, this resembles how BREAK works in a loop. But here it's applied differently, based on how execution is structured. Don't worry, we'll get into that in more detail shortly. But before that, let's talk about something else you may have noticed: the use of the reserved keyword CASE. If you compare Codes 01 and 02 closely, you'll see a clear similarity here.

The SWITCH statement appears similar to an IF, and now we've entered a block. The word CASE acts much like the equality condition used in each IF expression in Code 01. Following CASE, we provide a value, which is precisely the same values you saw in each of the IF conditions. Interesting, isn't it? And no, this isn't a coincidence. That's exactly how the SWITCH statement is designed to work, and how it should be understood in practical use. That's why, on the surface, SWITCH might seem far more complicated than it actually is. But once you begin to understand how it works, it becomes quite simple and, in fact, very powerful. You'll soon find yourself thinking of new ways to apply it.

Now, in Code 01 we had line 11, which executed when none of the values matched the expected ones. The same thing happens here in SWITCH. To achieve this behavior, we use another reserved keyword: DEFAULT. Within a SWITCH routine or block, DEFAULT tells the compiler that if no case matches the value tested in the SWITCH expression, an alternative routine should be executed. Typically, this sub-statement DEFAULT is placed at the end of the SWITCH block. This preserves a logical structure. However, you can technically place it anywhere within the block. It's just that doing so would be rather unconventional and awkward.

Pretty interesting, right? There's one more detail worth highlighting, something that might make the utility of SWITCH even clearer. Here it is: an IF statement will only execute the block associated with it if and only if the expression evaluates to true. No matter what the value is, the block only runs if the condition is true. With SWITCH, things work a bit differently. The expression is evaluated in a numeric manner. What matters is whether the value matches the one we're testing. A CASE block is only executed if and only if the value exactly equals the expression in the SWITCH statement. However, that block doesn't end unless a BREAK statement is encountered or the end of the SWITCH statement is reached. So be mindful of this.

For now, always include a BREAK statement before starting a new CASE. This will help keep your code organized and prevent confusion. Later on, we'll explore scenarios where omitting BREAK can be useful. But until then, make it a habit to include a BREAK before each new CASE.

Alright, with that said, let's take a look at how the execution flow of the SWITCH statement actually works. This is illustrated in the diagram below:

Figure 01

Here, dear reader, we're looking at something a bit different from what we've seen in the previous execution flow diagrams. That's because Figure 01 is designed to illustrate how you should understand the SWITCH statement. So if you truly want to understand how SWITCH works, especially before we dive into more advanced aspects, it's important to understand this diagram properly. Once you do, you'll be able to explore the SWITCH statement with ease, even at a level beyond what we're currently demonstrating.

Here are the explanations. As you'll notice, everything begins as with any other statement. That is, by using the reserved keyword to declare the start of the statement. From that moment on, until we reach the exit point (the small circle at the end), everything belongs exclusively to the SWITCH block. None of it is accessible from outside commands. Understanding this is crucial, especially for a concept we will explore later.

Now, the next element we encounter is the expression. This expression should be interpreted numerically, not logically. What does this mean in practice? It means that using conditions like "greater than" or "less than" inside the expression won't produce the results you might expect. So unlike an IF statement, where the key factor is whether the expression evaluates to true or false, here the expression in a SWITCH must ALWAYS be thought of as yielding a number. That number will then be used in the next step.

The next step is where the CASE statements come into play. This is where the expression is evaluated logically. I.e., it will be evaluated as true or false. But wait a minute. There seems to be some contradiction. Didn't you just say the expression isn't evaluated logically, but numerically? Now I'm saying it's logical again.Yeah, that sounds like a contradiction This is an absolutely reasonable question, as it all does seem confusing at first.

Unfortunately, there's no simpler way to explain it. The value from the expression is passed down and checked against various CASE statements. There's no strict order. The connection between the expression and the CASE values is purely numeric. However, when a CASE statement is executed, it checks the value logically, that is, as true or false. That's why, next to each case, I've included an additional label: VALUE. This illustrates the actual value being compared against the expression. If the match occurs, we then execute the corresponding ROUTINE. To make any kind of decision, a logical comparison must happen, even if it's triggered by a numeric match. This is where things tend to get a little messy. Many people wrongly assume that the evaluation happens directly in the SWITCH expression. But in reality, it takes place during the matching of a specific case.

Didn't I say the SWITCH statement could get a bit confusing if you didn't fully understand the earlier articles? And we're still working with the most basic form of it!

Anyway, once a CASE verifies that the EXPRESSION is equal to a VALUE, the corresponding ROUTINE is executed. Period. New line. Now we get to a part where everything becomes complicated. But that will be explained later. This is the mysterious red line you saw in Image 01. That line represents a deeper complexity we won't address just yet. Let's ignore it for now. Unless you're eager to explore ahead on your own and figure out what happens when the flow goes through that red line, I suggest leaving it alone for the moment. Here's what you should do instead: at the end of every ROUTINE block, insert a BREAK statement. This will ensure that execution exits the SWITCH block cleanly. This statement is fun, but it can really twist your brain in knots if you're not careful. There are ways to write logic inside a SWITCH that become incredibly hard to follow unless you deeply understand control flow.

Alright, everything sounds great so far. But there's a thought that's been bothering me. In previous articles, we learned that the BREAK statement allows us to exit a loop without having to re-evaluate the loop condition. That made perfect sense. But now, seeing BREAK used inside a SWITCH, You might be a little confused about something. What if we're inside a loop and we also use a SWITCH inside that loop, just like you’ve shown us. If we use BREAK inside the SWITCH, won't that terminate the entire loop prematurely? Now that is an excellent question, dear reader. That's the kind of question that shows you're really following along and understanding the material we've covered so far. So here's what we'll do: Since you already know how to create a loop and control its flow using BREAK, RETURN, and CONTINUE, let's work through a slightly more advanced example than the one we saw at the beginning of this article, or in the earlier ones. The goal here is to provide clarity, not to build something special or functional, but to see the concepts in a practical, demonstrative way.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " Counting...");
07.     Print(__FUNCTION__, " ", __LINE__, " Pit Stop :: ", Tic_Tac());
08.     switch (Tic_Tac())
09.     {
10.         case true:
11.             Print(__FUNCTION__, " ", __LINE__, " Return TRUE");
12.             break;
13.         case false:
14.             Print(__FUNCTION__, " ", __LINE__, " Return FALSE");
15.             break;
16.     }
17. }
18. //+------------------------------------------------------------------+
19. bool Tic_Tac(void)
20. {
21.     static uchar counter = 10;
22. 
23.     while (true)
24.     {
25.         switch (counter)
26.         {
27.             case 8:
28.                 counter = counter - 1;
29.                 return false;
30.             case 6:
31.                 Print("Press TAB to continue or ESC to abort the count.");
32.                 counter = counter - 1;
33.                 break;
34.             case 5:
35.                 if (TerminalInfoInteger(TERMINAL_KEYSTATE_TAB))
36.                 {
37.                     Print("Accelerating count.");
38.                     counter = 2;
39.                 } else if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE))
40.                 {
41.                     Print("General panic...");
42.                     return false;
43.                 }
44.                 continue;
45.             case 0:
46.                 return true;
47.             default:
48.                 counter = counter - 1;
49.         }
50.         Print(__FUNCTION__, " ", __LINE__, " :: ", counter);
51.         Sleep(300);
52.     }
53.     Print(__FUNCTION__, " ", __LINE__, "This line will never be executed.");
54. }
55. //+------------------------------------------------------------------+

Code 03

This Code 03 introduces some very interesting elements of code construction and implementation. That's because, here, we are using nearly everything we've covered up to this point. However, before diving into the details of Code 03, let's take a look at what happens when it is executed in the MetaTrader 5 terminal. In fact, there are two possible outcomes, each demonstrated in the animations below.

Animation 01

In this first animation, you can observe what happens when the ESC key is pressed. Now, when we press the TAB key, something slightly different happens, as shown in the next animation.

Animation 02

Notice that there’s a subtle difference between the two animations. But what really matters here is understanding how this information reaches the terminal—and how flow control statements determine when each piece of information appears.

Now, dear reader, I won't go into full detail on certain parts here. That's because I want to encourage you to revisit the previous articles to truly understand how each flow control statement works. However, I will still provide an overview of how things unfold in Code 03.

Let's begin with the code's entry point, which is OnStart. Line 6 shows where we are in the execution process. This line prints as soon as it's executed. However, line 7 won't be processed immediately. Because it includes a call to the Tic_Tac function. As a result, the full execution of line 7 is postponed until Tic_Tac completes its tasks.

Once inside the Tic_Tac function (line 19), we enter an infinite loop at line 23. But don't worry, dear reader, this loop is infinite in form, but we have specific points where it can be exited. Pay close attention here to understand what's happening. At line 25, we enter a flow control statement SWITCH. For each relevant counter value, we perform a specific action. Keep in mind that the counter variable is declared as static. It is very important. When the counter reaches the value eight, we return to the caller, returning a value of false. At this point, line 7 is fully executed. This explains the message printed in the terminal. After that, we move to line 8 and call the Tic_Tac function again. But this time, we use its return value as the expression in another SWITCH statement. Again, the execution waits until Tic_Tac completes. So, we return to line 19 and continue from there.

Wait. Didn't we exit at line 29? You might be wondering: if we exited at line 29, wouldn't that reset everything and make the loop at line 23 end again at line 29? It would, dear reader. But because line 28 executed before returning to the caller, we're now pointing to the value seven. And since there's no matching case for the value seven in the SWITCH at line 25, execution jumps to line 47. Line 47 contains a routine that only executes line 48, which decreases the counter by one. Now, the counter is pointing to value six.

Either way, after completing the SWITCH block, we proceed to lines 50 and 51. That's why certain values, like seven, don't appear in the terminal. Once value six is printed, the loop restarts, and the SWITCH statement runs again. Now the expression is holding the value six. Now pay attention. At line 31, we print another message to the terminal. Then, at line 32, we set the counter to five. But what happens at line 33, where a BREAK statement is used? This is where many beginners get confused. From earlier articles, we know that BREAK ends the loop it's within. That's true, and it was clearly demonstrated. However, in this specific case, the break doesn't terminate the outer loop. That’s because here, it is part of the SWITCH statement. In these situations, BREAK applies to the SWITCH, not to the surrounding loop, whether it be WHILE, DO WHILE, or FOR.

This may seem confusing, but to prove this behavior, I placed a message at line 53 - a message that will NEVER be printed in this Code 03. Even though the only BREAK in the entire code appears at line 33.

I think this should be clear. This code is attached to the article, so that you can study it in peace until this little quirk in using the BREAK operator becomes clear.

Once the BREAK at line 33 is executed, we go straight to line 50. Remember, the counter was decreased in line 32. So now it holds the value five.

The loop runs again, and the SWITCH is checked again. This time the expression evaluates to five. Since we have a CASE for that value, it is executed. And this is where things get interesting. Once again, pay close attention. At this point, the program waits for the user to press one of the keys mentioned in the message displayed when the counter was six. But 9 (and this is the key point) if the user does not press any key, line 44 executes a CONTINUE statement. Now the question arises. Since CONTINUE always refers to the enclosing loop, the execution jumps back to line 23. Thus it skip lines 50 and 51 entirely. This continues as long as the expression evaluates to five. Once the user presses a key, the flow changes again. Depending on the key pressed, we either go to line 38, setting the counter to two, or to line 42. Either way, at some point, either in line 42 or 46, the loop will end. However, even then, line 53 will never be executed. We then return to line 8. At this point, the new expression is evaluated. But now you might be asking: "Wait. Wasn't switch supposed to evaluate expressions numerically? Why are the case values booleans? That makes no sense to me." And that, dear reader, is precisely the point. Back when we discussed the IF statement, I explained what makes a value true or false. The concept of false remains unchanged. However, when it comes to true, things shift a little. In this case, the TRUE value on line 10 is actually the numeric value 1. So, if the Tic_Tac function returns either 0 or 1, the SWITCH on line 8 will recognize it and a corresponding message will be displayed. But if you change the return value of Tic_Tac to something other than 0 or 1, the SWITCH on line 8 won't find a matching case. And no message will be displayed.

It's worth noting one thing. If you were to use an IF statement instead of the SWITCH at line 8, a message might be displayed. This depends on how you implement IF. And that's the goal here: to get you thinking like a programmer. I'm not going to tell you exactly what to do. Instead, I want you to think like a programmer, to try to understand how each statement works, including its capabilities and limitations.


Final considerations

In this article, we’ve explored how the SWITCH statement works. I understand that, at first glance, it might seem to cause more confusion than it solves. But I assure you that after you practice it will become very useful to you. I'll emphasize this once more: study each control structure slowly. Try replicating the same behavior in slightly different ways. This will help you build a clearer understanding of how everything fits together.

Start small, don't rush into creating an indicator or Expert Advisor right away. Build a solid foundation of knowledge first. That way, your development efforts will be more efficient and your hard work better rewarded. So take your time, review the code attached, and I'll see you in the next article.

Translated from Portuguese by MetaQuotes Ltd.
Original article: https://www.mql5.com/pt/articles/15391

Attached files |
Anexo.zip (1.43 KB)
From Novice to Expert: Programming Candlesticks From Novice to Expert: Programming Candlesticks
In this article, we take the first step in MQL5 programming, even for complete beginners. We'll show you how to transform familiar candlestick patterns into a fully functional custom indicator. Candlestick patterns are valuable as they reflect real price action and signal market shifts. Instead of manually scanning charts—an approach prone to errors and inefficiencies—we'll discuss how to automate the process with an indicator that identifies and labels patterns for you. Along the way, we’ll explore key concepts like indexing, time series, Average True Range (for accuracy in varying market volatility), and the development of a custom reusable Candlestick Pattern library for use in future projects.
Integrating AI model into already existing MQL5 trading strategy Integrating AI model into already existing MQL5 trading strategy
This topic focuses on incorporating a trained AI model (such as a reinforcement learning model like LSTM or a machine learning-based predictive model) into an existing MQL5 trading strategy.
Trading with the MQL5 Economic Calendar (Part 7): Preparing for Strategy Testing with Resource-Based News Event Analysis Trading with the MQL5 Economic Calendar (Part 7): Preparing for Strategy Testing with Resource-Based News Event Analysis
In this article, we prepare our MQL5 trading system for strategy testing by embedding economic calendar data as a resource for non-live analysis. We implement event loading and filtering for time, currency, and impact, then validate it in the Strategy Tester. This enables effective backtesting of news-driven strategies.
Price Action Analysis Toolkit Development (Part 20): External Flow (IV) — Correlation Pathfinder Price Action Analysis Toolkit Development (Part 20): External Flow (IV) — Correlation Pathfinder
Correlation Pathfinder offers a fresh approach to understanding currency pair dynamics as part of the Price Action Analysis Toolkit Development Series. This tool automates data collection and analysis, providing insight into how pairs like EUR/USD and GBP/USD interact. Enhance your trading strategy with practical, real-time information that helps you manage risk and spot opportunities more effectively.