RoboForex – Professional services on Forex market

Writing Your First Trading Robot in MQL4 and MQL5

Imagine this situation: you're sitting in front of your monitor, watching the chart, and you see the price breaking through an important level. You want to enter a trade, but you need to make a quick decision, set a stop-loss and take-profit. What if you stepped away for a cup of coffee and missed the move? What if, at night while you're sleeping, a strong movement occurs that could have brought you profit?

This is exactly what trading robots (expert advisors) are for. They tirelessly monitor the market 24/7, know no fatigue or emotions, and act strictly according to the program embedded in them. Today, we will take the first step into the world of algorithmic trading and thoroughly analyze a trading robot named VR Breakdown Level.

We won't just read the code. We will understand the logic of the strategy, see how it is implemented in the two most popular languages for the MetaTrader platform — MQL4 and MQL5 — and compare these implementations. Don't be afraid if you've never programmed before! The article is written to be understandable even for those opening a code editor for the first time. Let's go!

Part 1: Introduction to the VR Breakdown Level Strategy

Before writing code, we need to clearly understand what we want from the robot. The name of the strategy speaks for itself: VR Breakdown Level means "Breakout Levels".

The strategy is based on the classic idea of technical analysis: if the price breaks the High or Low of the previous period, it is a signal for the movement to continue. The period can be anything: 1 hour, 4 hours, 1 day. This is configurable.

How it works (logic for beginners):

  1. Start of a new period: Imagine we are trading on an hourly chart. As soon as a new hour begins (a new "candle" forms), our robot wakes up and does the most important thing — it remembers the prices.
  2. Remembering levels: It looks at the previous, just-closed hour. The robot records two numbers in its memory:
    • The maximum price of the previous period (High).
    • The minimum price of the previous period (Low).
    These prices become our key levels for the current period.
  3. Waiting for a breakout: Throughout the current hour, the robot simply monitors the price. It does nothing as long as the price remains within the range between the previous period's high and low.
  4. BUY signal: As soon as the current price rises above the high of the previous period, the robot interprets this as a sign of buyer strength. It instantly opens a BUY position.
  5. SELL signal: If the price falls below the low of the previous period, this is a sign of seller strength. The robot opens a SELL trade.
  6. Risk management: Having opened a trade, the robot doesn't abandon it to fate. Immediately, for each order, it places protective orders:
    • Stop Loss: If the market moves against us, this price will limit our loss. We tell the robot in advance: "Dear, if the price falls below this level (for a buy), close the trade so I don't lose even more."
    • Take Profit: This is our goal. The price upon reaching which the robot will automatically close the trade and lock in profit.
  7. One signal — one trade: To avoid opening an infinite number of orders if the price lingers near the level, the robot "resets" the remembered level to zero after opening a trade, so it doesn't react to it again.

That's the whole strategy! Simple as a sledgehammer, and that's its beauty. Now let's see what this sledgehammer looks like in code for two different versions of MetaTrader.

Part 2: Code Analysis in MQL4

MQL4 is the language in which thousands of expert advisors have been written over the last 15+ years. It's a bit older and simpler in some aspects. Let's break down the code piece by piece.

2.1. Interface and Settings

At the very beginning of the code, we see a "header" with information about the author and version. These are just comments for us; the program ignores them.

//+------------------------------------------------------------------+
//| VR Breakdown level.mq4 |
//| Copyright 2026, Trading-Go. |
//+------------------------------------------------------------------+
#property copyright "@ Voldemar"
#property link "https://trading-go.ru/beginner/pisham-svoego-pervogo-torgovogo-robota-na-mql4-i-mql5/"
#property version "26.020"
#property strict

The most interesting part begins with the keyword input. These are the expert advisor settings that the user will see in the properties window when starting it.

//+------------------------------------------------------------------+
//| Input parameters |
//+------------------------------------------------------------------+
input double iLots = 0.01; // Trading volume in lots
input ENUM_TIMEFRAMES iTimeFrame = PERIOD_CURRENT; // Timeframe for analysis
input int iTakeProfit = 400; // Take Profit in points
input int iStopLoss = 200; // Stop Loss in points
input int iMagicNumber = 227; // Unique identifier for EA orders
input int iSlippage = 30; // Maximum slippage in points
  • iLots — this is the size of the first trade.
  • iTimeFrame — the very period we talked about. You can choose H1, H4, D1, etc.
  • iTakeProfit and iStopLoss — distances to targets in points (pips).
  • iMagicNumber — a very important thing! This is a unique ID for our robot. Imagine several advisors running on one account. To prevent them from interfering with each other's orders and closing each other's trades, each has its own magic number. The robot only touches orders where this number matches its settings.

2.2. Global Variables

Here we declare variables that will be visible in all functions of the robot.

double lt = 0; // Corrected lot volume
double level_up = 0; // Level for buying (High of the previous bar)
double level_dw = 0; // Level for selling (Low of the previous bar)
  • lt — we will store the lot volume here, adjusted to the broker's requirements (more on this later).
  • level_up and level_dw — our main characters. The breakout level prices will be stored here. They are zero until a new bar appears.

2.3. Startup Moment: The OnInit() Function

This function is executed once, when we first attach the robot to the chart.

int OnInit()
{
double stepvol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(stepvol > 0)
lt = stepvol * (int)(iLots / stepvol);
if(lt < SymbolInfoDouble> lt = 0.0;
return(INIT_SUCCEEDED);
}

What's happening here? We are checking if we can trade with the volume entered by the user. Brokers often only allow trading in specific lot fractions (e.g., step 0.01). If the user entered 0.05, but the step is 0.03, we need to round to 0.03 or 0.06? The code adjusts the volume to the correct value. If, after rounding, the volume is less than the minimum allowed, we set lt to zero to prevent the robot from opening trades with an error.

2.4. The Heart of the Robot: The OnTick() Function

This is the main function. It is called on every new tick (every slightest price change).

Step 1: Checking for a new bar

if(NewBar())
{
level_up = iHigh(_Symbol, PERIOD_CURRENT, 1);
level_dw = iLow(_Symbol, PERIOD_CURRENT, 1);
}

We call our own function NewBar(), which is written below. If it returns true (a new bar has appeared), we update our levels. iHigh(..., 1) is a standard MQL4 function that takes the High price of the bar with index 1, i.e., the previous (just closed) bar.

Step 2: Getting current prices

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  • ASK — the price at which we can buy (it's always slightly above the market price).
  • BID — the price at which we can sell (it's always slightly below the market price).

Step 3: Checking conditions and opening trades

  • BUY:
    if(ask > 0 && level_up > 0 && ask >= level_up)

    If the current ask price is greater than or equal to our upper level, and the level itself is not zero (we just updated it), then...

    int ticket = OrderSend(_Symbol, OP_BUY, lt, ask, iSlippage, 0, 0, NULL, iMagicNumber, 0, clrNONE);

    ...we send a market order to buy! The OrderSend function is the "grandmother" of all trading functions in MQL4.

    level_up = 0;

    — immediately after opening, we reset the level to prevent further entries.

  • SELL:

    The logic is mirrored. If bid <= level_dw, we send an OP_SELL order.

Step 4: Managing stops for open positions

The most complex part of the MQL4 code. Here we loop through all open orders (for loop), look for "ours" (by symbol and magic number), and if necessary, modify their stop losses and take profits.

for(int i = 0; i < total> {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == _Symbol && OrderMagicNumber() == iMagicNumber)
{
// ... calculation of new SL and TP based on the opening price (op) ...
if(new_sl != sl && new_tp != tp)
if(CheckSL_TP(OrderType(), new_sl, new_tp))
bool res = OrderModify(OrderTicket(), op, new_sl, new_tp, 0, clrNONE);
}
}
}
  • OrderSelect — a function that selects an order to work with.
  • OrderModify — a function for changing order parameters (stop and take profit).

2.5. Helper Functions

The NewBar() Function

A simple yet ingenious function for detecting a new bar. It remembers the opening time of the current bar in the variable old_time. On the next tick, it compares the new time with the old one. If they differ, a new bar has appeared!

bool NewBar(void)
{
datetime new_time = iTime(_Symbol, PERIOD_CURRENT, 0);
static datetime old_time = new_time;
if(new_time != old_time)
if((old_time = new_time) != NULL)
return(true);
return(false);
}

The CheckSL_TP Function

This function is a "checker". Brokers do not allow setting a stop-loss too close to the current price (there is usually a minimum distance, e.g., 20 points). This function checks if our new stop violates the broker's rules.

Part 3: Code Analysis in MQL5

MQL5 is an evolution of the language. It's more powerful, stricter, but also a bit more complex for a beginner. The main difference is the shift from the concept of orders to the concept of positions. In MQL4, you could have pending orders and market orders "hanging" in the list. In MQL5, a market trade is a position that occupies a separate place in the positions list.

Because of this, special libraries (classes) appeared to simplify the programmer's life. Let's look at them.

3.1. Including Libraries

At the very beginning, we see #include lines. This is like asking for help from senior comrades.

#include CTrade trade;
#include CPositionInfo posit;
  • CTrade trade; — we create an object trade, which is an expert in executing trades. Instead of the long OrderSend() function, we simply say trade.Buy().
  • CPositionInfo posit; — we create an object posit, which is an expert in getting information about open positions.

3.2. Settings and Initialization

The settings (input) look exactly the same as in MQL4. However, in OnInit(), we configure our new assistant trade.

int OnInit()
{
trade.SetExpertMagicNumber(iMagicNumber);
trade.SetDeviationInPoints(iSlippage);
// ... other settings ...
return(INIT_SUCCEEDED);
}

We tell the trade object: "Remember our magic number" and "Here is the allowed slippage". This is very convenient: set it once and forget it.

3.3. The OnTick() Function in MQL5

The overall structure is the same, but the details have changed dramatically.

Step 1: Checking for a new bar and updating levels

Here, almost everything is the same, except the iHigh and iLow functions now require two colons :: before them. This means we are calling the "global" function of the language, not some other one.

if(NewBar())
{
level_up = ::iHigh(_Symbol, PERIOD_CURRENT, 1);
level_dw = ::iLow(_Symbol, PERIOD_CURRENT, 1);
}

Step 2: Opening trades

Now, this is the most beautiful difference!

  • BUY:
    if(trade.Buy(lt))

    We simply call the Buy method of our trade object and pass only the volume. That's it! The trade object knows the Ask price itself, remembers the magic number, and knows the slippage. This is incredibly elegant and concise.

    if((level_up = 0) == 0) return;

    — and we reset the level.

  • SELL:
    if(trade.Sell(lt))

    — analogously.

Step 3: Managing stops for open positions

Instead of looping through orders, we loop through positions (::PositionsTotal()). And we use our posit object to get information about each position.

for(int i = 0; i < total> if(posit.SelectByIndex(i))
if(posit.Symbol() == _Symbol && posit.Magic() == iMagicNumber)
{
// posit.PriceOpen() - get opening price
// posit.TakeProfit() - get current TP
// posit.PositionType() - get type (BUY or SELL)
// ... calculation of new SL and TP ...
if(CheckSL_TP(posit.PositionType(), new_sl, new_tp))
trade.PositionModify(posit.Ticket(), new_sl, new_tp);
}

Notice: for modification, we again use the trade object, calling its PositionModify method. It's all logical: posit for information, trade for actions.

Part 4: Comparing MQL4 and MQL5 Code — What Should a Beginner Choose?

We've analyzed two pieces of code that do the same thing. But how do they differ? Let's create a comparison table to clearly see the difference.

CriterionMQL4MQL5
Main Approach Procedural. All operations are done through functions (OrderSend, OrderSelect). Object-oriented. Helper classes are used (CTrade, CPositionInfo).
Opening a Trade Long OrderSend function with many parameters. trade.Buy(volume). Concise and clear.
Trade Management You constantly need to select an order (OrderSelect) before working with it. The position is selected once (posit.SelectByIndex), and we can directly query the posit object for its properties.
Code Readability The code seems more "linear", but due to the abundance of functions, it can be confusing for a beginner. For example, to change a stop, you need to call OrderModify. The code is cleaner and more logical. posit handles data, trade handles actions. Easier to read and understand the programmer's intent.
Risk of Errors Higher. Easy to mix up parameters in OrderSend or forget to call OrderSelect. Lower. Objects themselves monitor the correctness of calls. For example, trade.Buy() will automatically use the correct Ask price.
Relevance Outdated. New platform features (e.g., order types) often appear only in MQL5. Modern. This is the language of the future for MetaTrader 5.
Ease of Starting Easier for a complete "zero" in programming, as it doesn't require understanding classes and objects. Requires understanding the concept of objects (classes), but in the long run, it teaches you to write correct and beautiful code.

Part 5: The Main Nuance of the Strategy — Pending Orders vs Market Orders

The strategy description mentions an interesting point: "A similar way to implement the strategy is using pending orders BUY STOP and SELL STOP... The presence of pending orders shows the broker the prices at which we intend to enter the market. Using 'internal' levels hides this information from the broker."

What does this mean?

  1. The method with pending orders (Transparent to the broker): As soon as a new period begins, we can immediately place two pending orders: BUY STOP at the level_up and SELL STOP at the level_dw. If the price reaches the level, the order triggers. The downside is that the broker (or other market participants with access to the order book) can see these orders. Large players sometimes hunt for such clusters of stop orders, provoking false breakouts.
  2. The method with market orders (Hidden), which we have implemented: We don't place anything in advance. We simply sit and wait in the code. As soon as the price touches the level, we send a market order at that very moment. To an external observer, this looks like a regular market trade, not a cluster of stop orders triggering.

Our code uses the second, more discreet approach. It's more complex to implement as it requires constant price monitoring in the OnTick() function, but it keeps our intentions hidden.

Part 6: Conclusion

So, we've come a long way. We've analyzed a simple yet effective trading strategy based on level breakouts. We've seen how the same logic can be implemented in two different languages — MQL4 and modern MQL5.

What have we learned?

  • Programming trading robots is not magic, but simply a clear recording of trading rules in a language the computer understands.
  • MQL4 is easier for understanding basic concepts, but its code is often cumbersome.
  • MQL5 is more complex at the start due to the object-oriented approach, but it offers a much cleaner, safer, and more professional toolkit. If you plan to seriously engage in development, choose MQL4 to start with; later, MQL5 will become easier and clearer for you.

Why should you give it a try?

Writing your own robot is an incredibly exciting process. You're not just a trader; you become a creator. You can program any idea you have, any trading pattern you see on the chart. You can test your strategies on historical data (this is called backtesting) and instantly see if they are profitable or loss-making, without risking real money.

Start small. Copy the VR Breakdown Level code into MetaEditor (the built-in development environment in the MetaTrader terminal), compile it (press F7), and attach it to a chart on a demo account. Observe its work.

Change the settings: set the timeframe to H4, increase the stop-loss. See how the behavior changes. Then try changing something in the code. For example, add a condition so that the robot only opens a trade after two consecutive breakouts. Or make it close a trade not by take-profit, but by a reverse breakout.

Don't be afraid of errors! Error messages are not a punishment, but hints from the compiler that help you write correct code.

Programming trading robots is a blend of a trader's analytical thinking and a programmer's creativity. It's a fascinating journey that can not only automate your trading but also give you immense pleasure from the process of creating something of your own. Open the code editor and take the first step today! Your first trading robot is waiting for you.

Source codes of the trading strategy:


MetaTrader 4 : https://www.mql5.com/en/code/69562
MetaTrader 5 : https://www.mql5.com/en/code/69545

Comments

To write a comment, log in Enter
Registration

Login

Password recovery Registration
Login

Password recovery Registration
Password request

If you forgot your password, enter your e-mail. The control line for changing the password will be sent to you by e-mail.

A link has been sent to your email address to confirm the E-mail address. To complete the registration, follow this link.

If you have not received an email to your email, check the Spam folder. If there is no letter there either, then contact us.

Registration completed successfully!

You have successfully logged in to the site!

We use both our own cookies and third-party cookies for the purpose of analysis, as well as to display ads based on your preferences, in accordance with your browsing habits and your profile. For more information, please see our Privacy Policy.
Telegram community
Discussions, settings, results,
communication with the author
GO