Welcome to the second part of creating Your First Expert Advisor lesson.
In the previous part we have taken the code generated by the new program wizard and
added our own code which we are going to crack it today line by line.
Did you wear your coding gloves? Let’s crack.
Note: I have to repeat that our expert advisor is for educational purpose only and will
not (or aimed to) make profits.
The code we have:
//+------------------------------------------------------------------+
//| My_First_EA.mq4 |
//| Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Coders Guru"
#property link "http://www.forex-tsd.com"
//---- input parameters
extern double TakeProfit=250.0;
extern double Lots=0.1;
extern double TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
int Crossed (double line1 , double line2)
{
static int last_direction = 0;
static int current_direction = 0;
if(line1>line2)current_direction = 1; //up
if(line1<line2)current_direction = 2; //down
if(current_direction != last_direction) //changed
{
last_direction = current_direction;
return (last_direction);
}
else
{
return (0);
}
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
int cnt, ticket, total;
double shortEma, longEma;
if(Bars<100)
{
Print("bars less than 100");
return(0);
}
if(TakeProfit<10)
{
Print("TakeProfit less than 10");
return(0); // check TakeProfit
}
shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
int isCrossed = Crossed (shortEma,longEma);
total = OrdersTotal();
if(total < 1)
{
if(isCrossed == 1)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,
"My EA",12345,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY order opened : ",OrderOpenPrice());
}
else Print("Error opening BUY order : ",GetLastError());
return(0);
}
if(isCrossed == 2)
{
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
Bid-TakeProfit*Point,"My EA",12345,0,Red);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("SELL order opened : ",OrderOpenPrice());
}
else Print("Error opening SELL order : ",GetLastError());
return(0);
}
return(0);
}
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
{
if(OrderType()==OP_BUY) // long position is opened
{
// should it be closed?
if(isCrossed == 2)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet);
// close position
return(0); // exit
}
// check for trailing stop
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>Point*TrailingStop)
{
if(OrderStopLoss()<Bid-Point*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-
Point*TrailingStop,OrderTakeProfit(),0,Green);
return(0);
}
}
}
}
else // go to short position
{
// should it be closed?
if(isCrossed == 1)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet);
// close position
return(0); // exit
}
// check for trailing stop
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
{
if((OrderStopLoss()>(Ask+Point*TrailingStop)) ||
(OrderStopLoss()==0))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,
OrderTakeProfit(),0,Red);
return(0);
}
}
}
}
}
}
return(0);
}
//+------------------------------------------------------------------+
The idea behind our expert advisor.
Before digging into cracking our code we have to explain the idea behind our expert
advisor. Any expert advisor has to decide when to enter the market and when to exit.
And the idea behind any expert advisor is what the entering and exiting conditions are?
Our expert advisor is a simple one and the idea behind it is a simple too, let’s see it.
We use two EMA indicators, the first one is the EMA of 8 days (sort EMA) and the
second one is the EMA of 13 days (long EMA).
Note: using those EMAs or any thought in this lesson is not a recommendation of mine,
they are for educational purpose only.
Entering (Open):
Our expert advisor will enter the market when the short EMA line crosses the long
EMA line, the direction of each lines will determine the order type:
If the short EMA is above the long EMA will buy (long).
If the short EMA is below the long EMA we will sell (short).
We will open only one order at the same time.
Exiting (Close):
Our expert advisor will close the buy order when the short EMA crosses the long EMA
and the short EMA is below the long EMA.
And will close the sell order when the short EMA crosses the long EMA and the short
EMA is above the long EMA.
Our order (buy or sell) will automatically be closed too when the Take profit or the Stop
loss points are reached.
Modifying:
Beside entering (opening) and exiting (closing) the market (positions) our expert advisor
has the ability to modify existing positions based on the idea of Trailing stop point.
We will know how we implemented the idea of Trialing stop later in this lesson.
Now let’s resume our code cracking.
//---- input parameters
extern double TakeProfit=250.0;
extern double Lots=0.1;
extern double TrailingStop=35.0;
In the above lines we have asked the wizard to declare three external variables (which
the user can set them from the properties window of our expert advisor).
The three variables are double data type. We have initialized them to default values (the
user can change these values from the properties window, but it recommended to leave
the defaults).
I have to pause again to tell you a little story about those variables.
Stop loss:
It’s a limit point you set to your order when reached the order will be closed, this is
useful to minimize your lose when the market going against you.
Stop losses points are always set below the current asking price on a buy or above the
current bid price on a sell.
Trailing Stop
It’s a kind of stop loss order that is set at a percentage level below (for a long position) or
above (for a short position) the market price. The price is adjusted as the price fluctuates.
We will talk about this very important concept later in this lesson.
Take profit:
It’s similar to stop lose in that it’s a limit point you set to your order when reached the
order will be closed
There are, however, two differences:
_ There is no “trailing” point.
_ The exit point must be set above the current market price, instead of below.
Figure 1 – Setting Stop loss and Take profit points
int Crossed (double line1 , double line2)
{
static int last_direction = 0;
static int current_direction = 0;
if(line1>line2)current_direction = 1; //up
if(line1<line2)current_direction = 2; //down
if(current_direction != last_direction) //changed
{
last_direction = current_direction;
return (last_direction);
}
else
{
return (0);
}
}
As I told you before, the idea behind our expert advisor is monitor the crossing of the
short EMA and the long EMA lines. And getting the direction of the crossing (which line
is above and which line is below) which will determine the type of the order (buy, sell,
buy-close and sell-close).
For this goal we have created the Crossed function.
The Crossed function takes two double values as parameters and returns an integer.
The first parameter is the value of the first line we want to monitor (the short EMA in our
case) and the second parameter is the value of the second we want to (the long EMA).
The function will monitor the two lines every time we call it by saving the direction of
the two lines in static variables to remember their state between the repeated calls.
_ It will return 0 if there’s no change happened in the last directions saved.
_ It will return 1 if the direction has changed (the lines crossed each others) and the
first line is above the second line.
_ It will return 2 if the direction has changed (the lines crossed each others) and the
first line is below the second line.
Note: You can use this function in your coming expert advisor to monitor any two lines
and get the crossing direction.
Let’s see how did we write it?
int Crossed (double line1 , double line2)
The above line is the function declaration, it means we want to create Crossed function
which takes two double data type parameters and returns an integer.
When you call this function you have to pass to it two double parameters and it will
return an integer to you.
You have to declare the function before using (calling) it. The place of the function
doesn't matter, I placed it above start() function, but you can place it anywhere else.
static int last_direction = 0;
static int current_direction = 0;
Here we declared two static integers to hold the current and the last direction of the two
lines. We are going to use these variables (they are static variables which means they
save their value between the repeated calls) to check if there’s a change in the direction of
the lines or not.
we have initialized them to 0 because we don’t want them to work in the first call to the
function (if they worked in the first call the expert advisor will open an order as soon as
we load it in the terminal).
if(current_direction != last_direction) //changed
In this line we compare the two static variables to check for changes between the last call
of our function and the current call.
If last_direction not equal current_direction that’s mean there’s a change happened in the
direction.
last_direction = current_direction;
return (last_direction);
In this case (last_direction not equal current_direction) we have to reset our
last_direction by assigning to it the value of the current_direction.
And we will return the value of the last_direction. This value will be 1 if the first line is
above the second line and 2 if the first line is below the second line.
else
{
return (0);
}
Else (last_direction is equal current_direction) there’s no change in the lines direction
and we have to return 0.
Our program will call this function in its start() function body and use the returned value
to determine the appropriate action.
In the coming part of this lesson we will know how did we call the function, and we will
know a lot about the very important trading functions.
To that day I hope you the best luck.
I welcome very much the questions and the suggestions._
See you
Coders’ Guru
Hi folks,
Regardless the type of your account, demo account or a real one; it's very important to have a set of functions to access this account information, for example the current account balance, the current account margin value and the current account total profit.
The account information functions are very useful for applying Money Management techniques by calculating the state of your account balance and margin etc.
Let's study these functions in details.
Syntax:
| double AccountBalance() |
Description:
The AccountBalance function returns the balance amount (how much money) of the current account. The calculation of the balance amount is the calculation of the starting capital + profit or - loss (of closed trades). The profit are loss are calculated only for the closed trades, so the floating profit/loss is not calculated within the balance!
Note: All of the Account Information function don't take parameters, see the examples!
Example:
| Print("Account balance = ", AccountBalance()); |
Syntax:
| double AccountCredit() |
Description:
The AccountCredit function returns the credit value of the current account
Example:
| Print("Account number ", AccountCredit()); |
Syntax:
| string AccountCompany() |
Description:
The AccountCompany function returns the brokerage company name you opened your current account with, the same as the name you find in the About dialog which you can open from Help menu.
Example:
| Print("Account company name ", AccountCompany()); |
Syntax:
| string AccountCurrency() |
Description:
The AccountCurrency function returns the name of the currency you used to open your account with the brokerage company, for example USD if you paid your account in US dollars.
Example:
| Print("account currency is ", AccountCurrency()); |
Syntax:
| double AccountEquity() |
Description:
The AccountEquity function returns the equity amount of the current account. The calculation of the balance equity is the calculation of the starting capital + profit or - losses (of all trades). The profit are loss are calculated for the opened and the closed trades.
Example:
| Print("Account equity = ",AccountEquity()); |
Hi folks,
Did you hear the "Brain Damage" album of Pink Floyd, No need to hear! But the Alert Once is a very hard challenge for any MQL4 programmer's brain!
When the Fast Moving Average crosses from downside to upside the Slow Moving Average in 1 Hour time frame make an Alert to buy! Great! Easy? Yes but:
When the above condition met I've got an Alert and all the time the Fast Moving Average is still above the Slow moving Average I'm getting ALERTS.
I want it to alert me once per par when the condition met! That's why I'm writing this article Alert Once (per bar).
In the code there are two methods to tell it's a new bar; The first method is a function I've created before called NewBar() which return true in the case of new bar and false otherwise:
bool NewBar()
{
static datetime lastbar;
datetime curbar = Time[0];
if(lastbar!=curbar)
{
lastbar=curbar;
return (true);
}
else
{
return(false);
}
}
The function above compare the time of opening bar for the last save bar with the time of opening bar of the current bar. If they not equals (which means it's a new bar) it returns true and if they are equals it means theres's no new bar has been developed and returns false.
This function is great if you want to track one only alert. But I want to track more than one Alert. For example I want to show alerts when:
1- When the FMA (Fast Moving Average) crosses up the SMA (Slow Moving Average) Alert me to Buy!
2- When FMA crosses down the SMA Alert me to Sell!
3- When the 2 bars ago FMA crosses up the previous bar SMA Alert me Buy confirmed by another bar!
4- When the 2 bars ago FMA crosses down the previous bar SMA Alert me Sell confirmed by another bar!
I want 4 Alert and you have to keep track of each of them and Alert Only Once Per Bar! This is the Brain Damage or programming :)!
Let's see the second type that telling it's a new bar:
static int LastAlert = 0;
if( LastAlert == 0 || LastAlert_1 < Bars )
{
Alert(alert_msg);
LastAlert = Bars;
}
In this code we compare between the last save number of bars and the current bars count, if this count increased it means it's a new bar. I prefer this code because I'll use it to track more than Alert.
One Image = 10000 words (I don't remember the count of words). Please give this image a look to know the logic behind Alert Once function.

As you can see in the above image the logic is very easy one:
1 -When the Alert Once function is called we check first if it's the first call of the function and in this case we Alert the message.
2- If it wasn't the first call we check "Was the last alert bar occurred in the same bar" which means is it a same bar for the new alert? If No we Alert the message.
Before we convert the above image to code I want to add a new concept, the reference of the Alert.
I want to track 4 Alert so I want to make the function accept a reference for each alert and track each alert alone. I hope it's clear and the code below will make it clearer (I hope).
bool AlertOnce(string alert_msg, int ref)
{
static int LastAlert_1 = 0;
static int LastAlert_2 = 0;
static int LastAlert_3 = 0;
static int LastAlert_4 = 0;
switch(ref)
{
case 1:
if( LastAlert_1 == 0 || LastAlert_1 < Bars )
{
Alert(alert_msg);
LastAlert_1 = Bars;
return (1);
}
break;
case 2:
if( LastAlert_2 == 0 || LastAlert_2 < Bars )
{
Alert(alert_msg);
LastAlert_2 = Bars;
return (1);
}
break;
case 3:
if( LastAlert_3 == 0 || LastAlert_3 < Bars )
{
Alert(alert_msg);
LastAlert_3 = Bars;
return (1);
}
break;
case 4:
if( LastAlert_4 == 0 || LastAlert_4 < Bars )
{
Alert(alert_msg);
LastAlert_4 = Bars;
return (1);
}
break;
}
}
First we track 4 Alert so we will use 4 static variables to hold the statue of every alert and we use switch keyword to work with every alert alone. that's better than making 4 functions one for every alert? right?
1- In the case the LastAlert_1 (or any of the four alerts) is equal to 0, it means it's the first call we Alert the alert_msg and set the LastAlert_1 to the number of bars on the chart.
2- Or if the LastAlert_1 is less the number of bars on the chart, which means it's a new bar we Alert the alert_msg.
That's all!
It's an easy task, you can use for the first alert type (Buy when FMA crosses up ) a code like that:
if (Cross(FMA ,SMA) == CROSS_UP)
AlertOnce ("We have to buy",1);
Just remember that the reference of this alert is number 1.
I hope you find a useful and brain save lesson!
Coders' Guru
Hi folks,
Today we are going to study some of important function that MetaTrader has grouped them under the topic "Checkup Functions".
The Checkup functions are a set of functions that are telling you some of useful information about the current statue of the client terminal (for example is dlls calling allowed or not and is the expert advisor allowed or not ) and the MQL4 environment (for example what's the last error has been occurred and is the trade context busy or not).
Let's go ahead and study this group of functions!
Syntax:
| int GetLastError() |
Description:
The GetLastError function returns the code last error occurred during the execution of the MQL4 program or zero if there was nor errors. After that (after calling it) the last error be set back to zero.
We are going to set aside a separated article for MQL4 error tracking!
Note: To get a text representation of the error code you can use the function ErrorDescription(), but don't to forget to include stdlib.mqh
Note: All of the Checkup functions don't take any parameters, see the examples!
Example:
| int err; |
Syntax:
| bool IsConnected() |
Description:
The IsConnected function tells you if the terminal is connected to the server (True) or not (False). You can use it before any code of your Expert Advisor that needs to be connected to the server first.
Example:
| if(!IsConnected()) |
Syntax:
| bool IsDemo() |
Description:
The IsDemo function tells you if the expert advisor runs in demo (True) or live (False) account. You can use this function for instance to protect you trial expert advisor from working in a live account and work only in a demo account.
Example:
| if(IsDemo()) Print("I work at a demo account"); |
Syntax:
| bool IsDllsAllowed() |
Description:
The IsDllsAllowed function tells you if the expert advisor is allowed to call dlls (True) or not (False). To allow dlls calling you go to Tools -> Options -> Expert Advisors then check "Allow DLL Imports" .
Example:
| #import "user32.dll" |
Hi folks,
Today we are going to talk about a very important set of MQL4 functions; the Conversion functions.
In many of situations you have a variable in a specific format and you want to use it in another format.
For example: When we use the CurTime() function which returns the current server time; it returns this time in datetime format.
It will not problem for us if we are going to use this time as a datatime format for example adding to 2 hours to it or substracting it from the local time.
But if we want to display this time to the user using the Alert() function we will face a problem. the Alert() can't convert automatically from datetime data type to string data type which we want the user to see. In this case we have to use the conversion function TimeToStr().
Beside the conversions functions we are going to study I have to mention that MQL4 will make implicit conversions from a data type to other data type when you assign a wrong value for this data type.
For example:
string var1 = 100;
Alert(var1);
In the above code you have assigned an integer to a string variable. MQL4 will convert the number 100 from integer to string.
If you don't sure of that add this line:
Alert(var1+10);
What do you think you'll get? No, not 110 but you will get 10010 (Figure 1). That's because MQL4 has converted the 100 to string and 10 to string then added them to each others as strings.
Figure 1
Let's study the conversion function available in MQL4!
Syntax:
| string CharToStr( int char_code) |
Description:
The CharToStr function converts from Char type to string type; it converts the ASCII char code passed to it to string.
Parameters:
This function takes only one parameter:
int char_code
The ASCII char code of the character you want to convert it to string.
Example:
| for (int cnt = 1 ; cnt < 255 ; cnt++) |
Syntax:
| string DoubleToStr( double value, int digits) |
Description:
The DoubleToStr function converts from double data type to string type; it converts the double value passed to the function to string with the number of digits passed to the function.
Parameters:
This function takes two parameters:
double value
The double value you want to convert it to string.
int digits
The number of digits you want the function to use in converting the double value to string. it can be ranged from 0 (no digits) to 8 (8 digits).
Example:
| string value=DoubleToStr(1.2345678, 4); |
Syntax:
| double NormalizeDouble( double value, int digits) |
Description:
The NormalizeDouble function rounds the double value passed to it to the number of digits passed. It's like DoubleToStr function but it returns double value instead of string.
Parameters:
This function takes two parameters:
double value
The double value you want to round it.
int digits
The number of digits you want the function to use in rounding the double value. it can be ranged from 0 (no digits) to 8 (8 digits).
Example:
| double value=1.2345678; |
Syntax:
| double StrToDouble( string value) |
Description:
The StrToDouble function converts from string data type to double type; it converts the string value passed to the function to a double.
Parameters:
This function takes only one parameter:
string value
The string value you want convert it to double value.
Example:
| double value=StrToDouble("1.2345678"); |
Syntax:
| int StrToInteger( string value) |
Description:
The StrToInteger function converts from string data type to integer type; it converts the string value passed to the function to an integer.
Parameters:
This function takes only one parameter:
string value
The string value you want convert it to integer value.
Example:
| double value=StrToInteger("1999"); |
Syntax:
| datetime StrToTime( string value) |
Description:
The StrToTime function converts from string data type to datetime data type; the string value passed to the function must be in the format: "yyyy.mm.dd hh:mi"
Parameters:
This function takes only one parameter:
string value
The string value you want convert it to datatime data type. This string have in one of these formats:
"yyyy.mm.dd hh:mi"
"hh:mi"
"yyyy.mm.dd"
Example:
| datetime var1; |
Syntax:
| string TimeToStr( datetime value, int mode=TIME_DATE|TIME_MINUTES) |
Description:
The TimeToStr function converts from datetime data type to string data type; the return string value will be in the format "yyyy.mm.dd hh:mi".
Parameters:
This function takes two parameters:
datetime value
The datatime value you want to convert it to string. It starts from 00:00 January 1, 1970.
int mode
Optional parameter determine the mode of conversion; what the string format the function will return.
It can be one or combination of these modes:
TIME_DATE the result will be in the format "yyyy.mm.dd",
TIME_MINUTES the result will be in the format"hh:mi",
TIME_SECONDS the result will be in the format "hh:mi:ss".
The default value is TIME_DATE|TIME_MINUTES which means the result will be in the format "yyyy.mm.dd hh:mi".
Example:
| strign var1=TimeToStr(CurTime(),TIME_DATE|TIME_SECONDS); |
Coder Guru
www.xpworx.com
Hi folks!
Today we are going to go step by step creating our first MetaTrader extension (dll) in C++, let's don't waste the time and start by defining what's the MetaTrader extension (dll)?
MQL4 language give you a limited things to do with it and there are a lot of things you can not do in MQL4. To get the full control of your Windows operating system (For example, accessing the window registry or file handling APIs) you have to choices:
1- To call/use the windows common dlls and import the functions you want, and this is an example:
#import "user32.dll"
int MessageBoxA(int hWnd, string lpText, string lpCaption, int uType);
In the line above we used the #import keyword to import one of the "user32.dll" function; MessageBoxA function. Then we can use this function in our code like any normal function.
2- The second choice is creating our own dll in c++ and use it in our code the same as the common windows dlls. And that's what are we going to learn today.
I tried Visual Basic to create the MetaTrader dll but it failed, the truth is I didn't give it a lot of time and trials because the fact that the Visual Basic is not a real dll (activex) creator.
Note: If you find here any new terms that you don't understand them (like activex), if you can't ignore them you can ask me to explain them to you. But you don't need to know these terms to understand how to create your own dll.
So, the best choice was to use Visual c++, I used Microsoft Visual c++ 6 which you can download free express version of it from here: http://msdn.microsoft.com/vstudio/express/visualc/download/
Note: The version of Visual C++ used in this tutorial is Microsoft Visual c++ 6 not the express version.
Now let's create our first dll that says "hello world!"
1- The first step you have to run Visual C++ (Figure 1).

Figure 1 - Visual C++ 6
2- Now from File menu choose New and a dialog like that (Figure 2) will appear.
Figure 2 - New project dialog
3- From this dialog choose "MFC AppWizard (dll)" and write a name for the project in the "Project Name" field (Figure 3) and click "OK".
Figure 3 - MFC dll
Note: You can choose "Win32 Dynamic-Link Library" instead of "MFC AppWizard (dll)" but this means you will not able to use "CString" string type, CString is a string type in MFC that makes the world easier.
4- Another dialog (Figure 4) will appear to you asking you for some option. leave the default options and click "Finish" button. And when the information dialog appear click "OK".
Figure 4 - Project options
5- Congratulation! You have a new project now "demo" project which you can start to write your dll in. Please open the file "demo.cpp" and give it a look.
Now, we are going to write some code in this file:
#define MT4_EXPFUNC __declspec(dllexport)
you put this line after the lines:
#include "stdafx.h"
#include "demo.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
6- Add the end of the file "demo.cpp" and after this line:
CDemoApp theApp;
We are going to write our "Hello" function like that:
MT4_EXPFUNC void __stdcall Hello(char* say)
{
MessageBox(NULL,say,"demo",NULL);
}
7- Now we have the function "Hello" which takes a string to say it and returns no thing (void).
But the world want to know our function and in c++ to make the function availabe to the world we have to add the function name in a file called the .def file.
Now open the demo.def file and add this line (the bold line) at the end of the file:
; demo.def : Declares the module parameters for the DLL.
LIBRARY "demo"
DESCRIPTION 'demo Windows Dynamic Link Library'
EXPORTS
; Explicit exports can go here
Hello
8- Compile the dll by pressing F7, if you are a lucky man like me you will not get any errors or warnings. Search for the demo.dll in Debug folder in the Demo project folder.
In the coming article we are going to test our dll and we are going to know more about the data type passed and received to and from the dll that we can use to write more advanced dlls.
Hope you find it a useful article!
Coders' Guru
Hi folks!
In the previous part of this article we created step-by-step our first MetaTrader extension (dll) in C++ and in this article we are going to give it a test.
Also we are going to study in this article and the coming article some of the advanced topics briefly (like how to use arrays and structure in your dll).
Hope you are ready for this hard journey which deserves the effort.
We are going to write some code to test our demo.dll. These are the steps we have to take before saying "Hello World!"
1- We have the demo.dll in the debug folder in your Visual C++ projects folder. Copy the demo.dll to the library folder ("MetaTrader 4\experts\libraries").
2- Open MetaEditor to create the include file which will hold the declaration of our "Hello" function. This is the code of demo.mqh
#import "demo.dll"
void Hello(string say);
#import
Note how we have imported the dll and how we have declared the "Hello" function with the same parameters (string say) and return value (void) as the function in the dll.
This file will be saved at the Include folder (MetaTrader 4\experts\include).
3- Now, let's create the script to test the demo.dll. We are going to name it "Hello.mq4" and it must be saved at the Scripts folder (MetaTrader 4\experts\scripts).
#include <demo.mqh>
int start()
{
Hello ("Hello World!");
return(0);
}
Note how we have started the code by including the demo.mqh file to make it a part of our code.
4- Compile the script (F5) and load it now (double click it in the Navigator window in the Terminal). What did you get? a nice dialog like the one showed in figure 1, if not please check everything or email me!
Note: You have to enable the option "Allow DLL imports" in MetaTrader before using any code that import external functions (from the common windows dlls or you custom dlls like our demo.dll) that's by going to Tools -> Options -> Expert Advisors tab then checking "Allow DLL imports" (Figure 2).
Our demo.dll was a simple one yet it was a completed dll. There's an advanced sample that shipped with MetaTrader program which include advanced programming topics. We are going to study it and thank MetaQuotes for its ideal sample.
You will find the sample of the dll in "MetaTrader 4\EXPERTS\SAMPLES"; the dll (ExpertSample.dll) in the folder "MetaTrader 4\EXPERTS\SAMPLES\ExpertSample", the include file (sampledll.mqh) in "MetaTrader 4\EXPERTS\SAMPLES\INCLUDE" and the script (ExportFunctions.mq4) in "MetaTrader 4\EXPERTS\SAMPLES".
You have to open the source code of the dll (To open the source code double click ExpertSample.dsw file) and give the code a look. You will find it more advanced and to some degree a complex one compared to the demo.dll, but don't be afraid we are going to know everything in the next article.
Hi folks,
Today we are going to study a very important set of function that handles our custom indicators created in MQL4; the Custom indicator functions.
The Custom indicator functions are a set of functions that we use to set low level properties of the custom indicator we want to code, and they can not be used with the code of Expert Advisors or Scripts.
Let's give these functions a deep look:
Syntax:
| void IndicatorBuffers (int count) |
Description:
The IndicatorBuffers function allocates the required memory (buffer) needed for the indicator calculation.
The IndicatorBuffers value range from 1 to 8 and it must be equal to or less than the buffers count indicated by the indicator_buffers property.
Note: The difference between the buffers allocated by the indicator_buffers property and IndicatorBuffers function is that the indicator_buffers property allocate the buffers needed to draw the indicators lines while the IndicatorBuffers allocate the extra buffers that needed for extra calculation.
Parameters:
This function takes only one parameter:
int count:
The count of the buffers, the range is 1 to 8.
Example:
| #property indicator_separate_window |
Syntax:
| int IndicatorCounted() |
Description:
The IndicatorCounted function returns the amount of the bars that the indicator has been calculated them.
In the first launch of the indicator this count will be 0 because the indicator didn’t calculate any bars yet. And after that it will be the count of total bars on the chart -1.
Parameters:
This function takes no parameters:
Example:
| int start() |
Syntax:
| void IndicatorDigits (int digits) |
Description:
The IndicatorDigits function sets the count of digits after decimal point (precision format) of the indicator, the default value is the Symbol of the used chart precision format.
Parameters:
This function takes only one parameter:
int digits:
The count of digits after decimal point.
Example:
| int init() |
Syntax:
| void IndicatorShortName (string name) |
Description:
The IndicatorShortName function sets the text that will be showed on the upper left corner of the separate chart window (Figure 2).
Parameters:
This function takes only one parameter:
string name:
The text you want to display in the indicator short name.
Example:
| int init() |
Hi folks,
Today we are going to study a very important set of function that handles our custom indicators created in MQL4; the Custom indicator functions.
The Custom indicator functions are a set of functions that we use to set low level properties of the custom indicator we want to code, and they can not be used with the code of Expert Advisors or Scripts.
Let's give these functions a deep look:
Syntax:
| void IndicatorBuffers (int count) |
Description:
The IndicatorBuffers function allocates the required memory (buffer) needed for the indicator calculation.
The IndicatorBuffers value range from 1 to 8 and it must be equal to or less than the buffers count indicated by the indicator_buffers property.
Note: The difference between the buffers allocated by the indicator_buffers property and IndicatorBuffers function is that the indicator_buffers property allocate the buffers needed to draw the indicators lines while the IndicatorBuffers allocate the extra buffers that needed for extra calculation.
Parameters:
This function takes only one parameter:
int count:
The count of the buffers, the range is 1 to 8.
Example:
| #property indicator_separate_window |
Syntax:
| int IndicatorCounted() |
Description:
The IndicatorCounted function returns the amount of the bars that the indicator has been calculated them.
In the first launch of the indicator this count will be 0 because the indicator didn’t calculate any bars yet. And after that it will be the count of total bars on the chart -1.
Parameters:
This function takes no parameters:
Example:
| int start() |
Syntax:
| void IndicatorDigits (int digits) |
Description:
The IndicatorDigits function sets the count of digits after decimal point (precision format) of the indicator, the default value is the Symbol of the used chart precision format.
Parameters:
This function takes only one parameter:
int digits:
The count of digits after decimal point.
Example:
| int init() |
Syntax:
| void IndicatorShortName (string name) |
Description:
The IndicatorShortName function sets the text that will be showed on the upper left corner of the separate chart window (Figure 2).
Parameters:
This function takes only one parameter:
string name:
The text you want to display in the indicator short name.
Example:
| int init() |
Hi folks,
We are going to study today a very important set of MQL4 functions; the Date and Time Functions, which are the functions that returns the local (your computer) and server time.
As an example to show the importance of these function you can manage the time your expert advisor will enter the market and exist from the market. Another example with the aid of these functions you can know how long a position has been opened by subtracting the order opened time (returned by the function OrderOpenTime) from the current time (returned by he function CurTime which we are going to study it later).
There are a lot of useful usages of the date and time function that can't be listed here.
Before we dig into studying the date and time function we have to review the datetime data type because it's the cornerstone of understanding how the date and time is calculating in MQL4.
datetime data type is a special MQL4 data type, which holds a date and time data. You set the datetime variable by using the keyword (D) followed by two signal quotations ('). Between the two signal quotations you write a character line consisting of 6 parts for value of year, month, date, hour, minutes, and seconds. datetime constant can vary from Jan 1, 1970 to Dec 31, 2037.
For example:
| D'2004.01.01 00:00' // New Year |
We use the keyword datetime to create a datetime variable.
For example:
| datetime dtMyBirthDay= D'1972.10.19 12:00:00'; |
Now, let's give the date and time functions a study trip:
Syntax:
| datetime CurTime( ) |
Description:
The CurTime function returns the current server time, it's not always the exact current server time but it's the last know server time that the terminal has been retrieved it from the server with the last price quotation.
The return value of the CurTime function is a datetime data type and it's the number of seconds elapsed from 00:00 January 1, 1970.
What if you used this function (and all the date & time functions) in the testing mode - Back Testing?
In the testing mode the server time will be modeled by the tester.
Parameters:
This function takes no parameters and return datetime value.
Example:
| if(CurTime()-OrderOpenTime()<360) return(0); |
Syntax:
| int Day( ) |
Description:
The Day function returns the current day of the month (1, 2, 3, 4, ..... 31) of the last known server time.
The day is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(Day()<5) return(0); |
Syntax:
| int DayOfWeek( ) |
Description:
The DayOfWeek function returns the current day of the week of the last know server time:
0 = Sunday
1 = Monday
2 = Tuesday
3 = Wednesday
4 = Thursday
5 = Friday
6 = Saturday
The day of week is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| // does not work on holidays. |
Syntax:
| int DayOfYear( ) |
Description:
The DayOfYear function returns the current day of the year (1, 2, 3, .... 365 (366) ) of the last know server time.
The day of year is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(DayOfYear()==245) return(true); |
Syntax:
| int Hour( ) |
Description:
The Hour function returns the current hour (0, 1, 2, .... 23 ) of the last know server time.
The hour is modeled in the testing mode.
Note: The hour returned by the Hour function is the hour of the moment the program start and will not change during the execution of the program.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(Hour()>=12 || Hour()<17) return(true); |
Syntax:
| datetime LocalTime( ) |
Description:
The LocalTime function returns the current local computer time. The return value of the LocalTime function is a datetime data type and it's the number of seconds elapsed from 00:00 January 1, 1970.
The local time is modeled in the testing mode as well as the server time.
Parameters:
This function takes no parameters and return datetime value.
Example:
| if(LocalTime()-OrderOpenTime()<360) return(0); |
Syntax:
| int Minute( ) |
Description:
The Minute function returns the current minute (0, 1, 2, .... 59 ) of the last know server time. Like the Hour function the minute returned by the Minute function is the minute of the moment the program start and will not change during the execution of the program.
The minute is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(Minute()<=15) return("first quarter"); |
Syntax:
| int Month( ) |
Description:
The Month function returns the current month (0, 1, 2, 3, .... 12 ) of the last know server time.
The month is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(Month()<=5) return("the first half year"); |
Syntax:
| int Seconds( ) |
Description:
The Seconds function returns the current seconds (0, 1, 2, .... 59 ) of the minute of the last know server time. Like the Hour and the Minute functions the seconds returned by the Seconds function is the second of the moment the program start and will not change during the execution of the program.
The minute is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| if(Seconds()<=15) return(0); |
Syntax:
| int Year( ) |
Description:
The Year function returns the current year of the last know server time.
The year is modeled in the testing mode.
Parameters:
This function takes no parameters and return integer value.
Example:
| // return if the date is within the range from 1 Jan. to 30 Apr., 2006. |
Syntax:
| int TimeDay(datetime date) |
Description:
The TimeDay function returns the day of the month (1, 2, 3, ... 31) of the given date. It extracts the day of the month from the given date
Parameters:
datetime date:
The date (datetime data type) you want to extract the day of the month from.
Example:
| int day=TimeDay(D'2003.12.31'); // day is 31 |
Syntax:
| int TimeDayOfWeek(datetime date) |
Description:
The TimeDayOfWeek function returns the day of the week (0,1, 2, .... 6) of the given date. It extracts the day of the week from the given date
Parameters:
datetime date:
The date you want to extract the day of the week from.
Example:
| int weekday=TimeDayOfWeek(D'2004.11.2'); // day is 2 - Tuesday |
Syntax:
| int TimeDayOfYear(datetime date) |
Description:
The TimeDayOfYear function returns the day of the year (1, 2, 3, .... 365 (366)) of the given date. It extracts the day of the year from the given date
Parameters:
datetime date:
The date you want to extract the day of the year from.
Example:
| int day=TimeDayOfYear(CurTime()); |
Syntax:
| int TimeHour(datetime date) |
Description:
The TimeHour function returns the hour of the day (0,1, 2, .... 23) of the given date. It extracts the hours of the day from the given date
Parameters:
datetime date:
The date you want to extract the hour of the day from.
Example:
| int h=TimeHour(CurTime()); |
Syntax:
| int TimeMinute(datetime date) |
Description:
The TimeMinute function returns the minute of the hour (0,1, 2, .... 59) of the given date. It extracts the minute of the hour from the given date
Parameters:
datetime date:
The date you want to extract the minute of the hour from.
Example:
| int m=TimeMinute(CurTime()); |
Syntax:
| int TimeMonth(datetime date) |
Description:
The TimeMonth function returns the month of the year (1, 2, 3, .... 12) of the given date. It extracts the month of the year from the given date
Parameters:
datetime date:
The date you want to extract the month of the year from.
Example:
| int m=TimeMonth(CurTime()); |
Syntax:
| int TimeSeconds(datetime date) |
Description:
The TimeSeconds function returns the seconds of the minute (0,1, 2, .... 59) of the given date. It extracts the seconds of the minute from the given date
Parameters:
datetime date:
The date you want to extract the seconds of the minute from.
Example:
| if(Seconds()<=15) return(0); |
Syntax:
| int TimeYear(datetime date) |
Description:
The TimeYear function returns the year of the given date. It extracts the year from the given date
Parameters:
datetime date:
The date you want to extract the year from.
Example:
| // return if the date is within the range from 1 Jan. to 30 Apr., 2006. |
Hope you enjoyed the lesson!
Coders Guru
Hi folks,
One of the most important keys (if not the most important one) of success trading is the Money Management technique you apply to your trading operations.
The Money Management is how to handle the money you put in one or more trades, where you put more money in the good trades and put less money in the bad trades. And at the same time how to handle the capital you using in your trading account where you spend more when you have more balance and spend less when you have less balance.
The most of traders think first in when to buy/sell but the successful ones think first how manage the risk before buying/selling
The Money Management briefly is the art of handling the size of the trade
Because we are in the development section we are taking another approach of talking about the Money Management, we are going to talk about a MQL4 code which enable us to apply our Money Managements and Risk controller techniques in the case of writing an expert advisor.
We have a simple here in MQL4.
//+------------------------------------------------------------------+
//| EMA_CROSS_2.mq4 |
//| Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Coders Guru"
#property link "http://www.forex-tsd.com"
#define MAGICMA 20060306
//---- Trades limits
extern double TakeProfit=180;
extern double TrailingStop=30;
extern double StopLoss=70;
extern bool UseStopLoss = false;
extern double HedgingTakeProfit=20;
extern double HedgingStopLoss=10;
extern bool UseHedging = true;
extern bool ContinuesHedging = true;
//---- EMAs paris
extern int ShortEma = 10;
extern int LongEma = 80;
//---- Crossing options
extern bool ImmediateTrade = true; //Open trades immediately or wait for cross.
extern bool CounterTrend = true; //Use the originally CounterTrend crossing method or not
//---- Money Management
extern double Lots = 1;
extern bool UseMoneyManagement = true; //Use Money Management or not
extern bool AccountIsMicro = false; //Use Micro-Account or not
extern int Risk = 10; //10%
//---- Time Management
extern bool UseHourTrade = false;
extern int FromHourTrade = 8;
extern int ToHourTrade = 18;
extern bool Show_Settings = true;
extern bool Summarized = false;
extern double slippage = 3;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
if(Show_Settings && Summarized == false) Print_Details();
else if(Show_Settings && Summarized) Print_Details_Summarized();
else Comment("");
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
bool isNewSumbol(string current_symbol)
{
//loop through all the opened order and compare the symbols
int total = OrdersTotal();
for(int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
string selected_symbol = OrderSymbol();
if (current_symbol == selected_symbol)
return (False);
}
return (True);
}
int Crossed()
{
double EmaLongPrevious = iMA(NULL,0,LongEma,0,MODE_EMA, PRICE_CLOSE, 1);
double EmaLongCurrent = iMA(NULL,0,LongEma,0,MODE_EMA, PRICE_CLOSE, 0);
double EmaShortPrevious = iMA(NULL,0,ShortEma,0,MODE_EMA, PRICE_CLOSE, 1);
double EmaShortCurrent = iMA(NULL,0,ShortEma,0,MODE_EMA, PRICE_CLOSE, 0);
if(ImmediateTrade)
{
if (EmaShortCurrent<EmaLongCurrent)return (1); //down trend
if (EmaShortCurrent>EmaLongCurrent)return (2); //up trend
}
if (EmaShortPrevious>EmaLongPrevious && EmaShortCurrent<EmaLongCurrent ) return (1); //down trend
if (EmaShortPrevious<EmaLongPrevious && EmaShortCurrent>EmaLongCurrent ) return (2); //up trend
return (0); //elsewhere
}
//--- Bassed on Alex idea! More ideas are coming
double LotSize()
{
double lotMM = MathCeil(AccountFreeMargin() * Risk / 1000) / 100;
if(AccountIsMicro==false) //normal account
{
if (lotMM < 0.1) lotMM = Lots;
if ((lotMM > 0.5) && (lotMM < 1)) lotMM=0.5; //Thanks cucurucu
if (lotMM > 1.0) lotMM = MathCeil(lotMM);
if (lotMM > 100) lotMM = 100;
}
else //micro account
{
if (lotMM < 0.01) lotMM = Lots;
if (lotMM > 1.0) lotMM = MathCeil(lotMM);
if (lotMM > 100) lotMM = 100;
}
return (lotMM);
}
string BoolToStr ( bool value)
{
if(value) return ("True");
else return ("False");
}
void Print_Details()
{
string sComment = "";
string sp = "----------------------------------------\n";
string NL = "\n";
sComment = sp;
sComment = sComment + "TakeProfit=" + DoubleToStr(TakeProfit,0) + " | ";
sComment = sComment + "TrailingStop=" + DoubleToStr(TrailingStop,0) + " | ";
sComment = sComment + "StopLoss=" + DoubleToStr(StopLoss,0) + " | ";
sComment = sComment + "UseStopLoss=" + BoolToStr(UseStopLoss) + NL;
sComment = sComment + sp;
sComment = sComment + "ImmediateTrade=" + BoolToStr(ImmediateTrade) + " | ";
sComment = sComment + "CounterTrend=" + BoolToStr(CounterTrend) + " | " ;
if(UseHourTrade)
{
sComment = sComment + "UseHourTrade=" + BoolToStr(UseHourTrade) + " | ";
sComment = sComment + "FromHourTrade=" + DoubleToStr(FromHourTrade,0) + " | ";
sComment = sComment + "ToHourTrade=" + DoubleToStr(ToHourTrade,0) + NL;
}
else
{
sComment = sComment + "UseHourTrade=" + BoolToStr(UseHourTrade) + NL;
}
sComment = sComment + sp;
sComment = sComment + "Lots=" + DoubleToStr(Lots,0) + " | ";
sComment = sComment + "UseMoneyManagement=" + BoolToStr(UseMoneyManagement) + " | ";
sComment = sComment + "AccountIsMicro=" + BoolToStr(AccountIsMicro) + " | ";
sComment = sComment + "Risk=" + DoubleToStr(Risk,0) + "%" + NL;
sComment = sComment + sp;
Comment(sComment);
}
void Print_Details_Summarized()
{
string sComment = "";
string sp = "----------------------------------------\n";
string NL = "\n";
sComment = sp;
sComment = sComment + "TF=" + DoubleToStr(TakeProfit,0) + " | ";
sComment = sComment + "TS=" + DoubleToStr(TrailingStop,0) + " | ";
sComment = sComment + "SL=" + DoubleToStr(StopLoss,0) + " | ";
sComment = sComment + "USL=" + BoolToStr(UseStopLoss) + NL;
sComment = sComment + sp;
sComment = sComment + "IT=" + BoolToStr(ImmediateTrade) + " | ";
sComment = sComment + "CT=" + BoolToStr(CounterTrend) + " | " ;
if(UseHourTrade)
{
sComment = sComment + "UHT=" + BoolToStr(UseHourTrade) + " | ";
sComment = sComment + "FHT=" + DoubleToStr(FromHourTrade,0) + " | ";
sComment = sComment + "THT=" + DoubleToStr(ToHourTrade,0) + NL;
}
else
{
sComment = sComment + "UHT=" + BoolToStr(UseHourTrade) + NL;
}
sComment = sComment + sp;
sComment = sComment + "L=" + DoubleToStr(Lots,0) + " | ";
sComment = sComment + "MM=" + BoolToStr(UseMoneyManagement) + " | ";
sComment = sComment + "AIM=" + BoolToStr(AccountIsMicro) + " | ";
sComment = sComment + "R=" + DoubleToStr(Risk,0) + "%" + NL;
sComment = sComment + sp;
Comment(sComment);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
if (UseHourTrade)
{
if (!(Hour()>=FromHourTrade && Hour()<=ToHourTrade))
{
Comment("Time for trade has not come yet!");
return(0);
}
}
int cnt, ticket, ticket2, total;
string comment = "";
if(CounterTrend==true) comment = "EMAC_Counter";
if(CounterTrend==false) comment = "EMAC_Pro";
if(ImmediateTrade==true) comment = comment + "_Immediate";
if(ImmediateTrade==false) comment = comment + "Postponed";
if(Bars<100)
{
Print("bars less than 100");
return(0);
}
if(TakeProfit<10)
{
Print("TakeProfit less than 10");
return(0); // check TakeProfit
}
int isCrossed = 0;
isCrossed = Crossed ();
if(CounterTrend==false)
{
if(isCrossed==1) isCrossed=2;
if(isCrossed==2) isCrossed=1;
}
if(UseMoneyManagement==true) Lots = LotSize(); //Adjust the lot size
total = OrdersTotal();
if(total < 1 || isNewSumbol(Symbol()))
{
if(isCrossed == 1)
{
if(UseStopLoss)
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,slippage,Ask-StopLoss*Point,Ask+TakeProfit*Point,comment,MAGICMA,0,Green);
else
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,slippage,0,Ask+TakeProfit*Point,comment,MAGICMA,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice());
}
else Print("Error opening BUY order : ",GetLastError());
if(UseHedging) Hedge(ticket,Lots);
return(0);
}
if(isCrossed == 2)
{
if(UseStopLoss)
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,slippage,Bid+StopLoss*Point,Bid-TakeProfit*Point,comment,123,0,Red);
else
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,slippage,0,Bid-TakeProfit*Point,comment,MAGICMA,0,Red);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice());
}
else Print("Error opening SELL order : ",GetLastError());
if(UseHedging) Hedge(ticket,Lots);
return(0);
}
return(0);
}
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL && OrderSymbol()==Symbol() && OrderMagicNumber() == MAGICMA)
{
if(OrderType()==OP_BUY) // long position is opened
{
// check for trailing stop
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>Point*TrailingStop)
{
if(OrderStopLoss()<Bid-Point*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
return(0);
}
}
}
}
else // go to short position
{
// check for trailing stop
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
{
if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
return(0);
}
}
}
}
}
}
if(ContinuesHedging && OrdersCount(Symbol()) < 2)
{
//Print(OrdersCount(Symbol()));
for(cnt=0;cnt<total;cnt++)
{
ticket = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderSymbol() == Symbol())
Hedge(OrderTicket(),OrderLots());
}
}
return(0);
}
//+------------------------------------------------------------------+
int OrdersCount(string symbol)
{
int total = OrdersTotal();
int count =0;
for(int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if (symbol == OrderSymbol())
count++;
}
return (count);
}
void Hedge (int order_ticket , double hlots)
{
int ticket, order_type;
double order_profit;
string hcomment = "EMAC_" + Symbol() + "_Hedging";
if(OrderSelect(order_ticket,SELECT_BY_TICKET,MODE_TRADES))
{
order_type = OrderType();
order_profit = OrderProfit();
if(order_type == OP_SELL && order_profit < 0 - slippage)
{
ticket=OrderSend(Symbol(),OP_BUY,hlots,Ask,slippage,Ask-HedgingStopLoss*Point,Ask+HedgingTakeProfit*Point,hcomment,123,0,Yellow);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Hedgin BUY order opened : ",OrderOpenPrice());
}
else Print("Error opening Hedgin BUY order : ",GetLastError());
}
if(order_type == OP_BUY && order_profit < 0 - slippage)
{
ticket=OrderSend(Symbol(),OP_SELL,hlots,Bid,slippage,Bid+HedgingStopLoss*Point,Bid-HedgingTakeProfit*Point,hcomment,MAGICMA,0,Gold);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Hedgin SELL order opened : ",OrderOpenPrice());
}
else Print("Error opening Hedgin SELL order : ",GetLastError());
}
}
}
Coder Guru
www.xpworx.com
Hi folks,
Today we are going to take an idea to create Expert Advisor (That the Expert Advisors are for).
How to protect my profits of all opening orders (if there's any) by the mean I want to take them when they reach a specific amount and close all the trades when the drop down to a specific amount.
For example: There are 4 opened positions and they make profit. They've made 200 Pip right now. suddenly the profit went to 150 then 100 then I'm losing money.
Our code today will prevent this situation, let's see the idea programicaly.
First we want a way to calculate the profit of all opened positions.
When the profit goes to specific amount we are going to close all the opened position. But, we want the program too to prevent the profit to drop again. So, we want to set another profit point that the program will prevent any drops below it.
For example: the program will take the profit when it reaches 200 Pips and prevent the profit to drop below to 100 Pips .
The programming problem now is when to start preventing the profit drop. How to tell the program that the profit went over 100 Pip and we don't want it drop back?
We need a third point when the profit reach it the program will start to monitor the profit drop.
The example right now is: the program will take the profit when it reaches 200 Pips and start to monitor the drop down of the profit when the profit reaches 150 Pips and prevent the profit to drop again to 100 Pips level.
Let's convert that to code!
Please download the code. I've added the profit protector code to a normal expert advisor of mine. We will not study the expert advisor strategy in buying/selling/closing/trailing. But we are going to study the code aimed to protect the profit.
These are the pieces of code concerning our idea:
.....//your normal code
extern double ProfitToProtect = 200;
extern double ProtectStarter = 150;
extern double LossToProtect = 100;
extern bool ProtectProfit= true;
bool ProtectLoss= false;
.....//your normal code
int start()
{
...... //your normal code
if(ProtectProfit)
ProfitProtect(ProfitToProtect);
if(ProtectLoss)
LossProtect(LossToProtect);
.......//your normal code
}
void ProfitProtect(double profit)
{
int total = OrdersTotal();
double MyCurrentProfit=0;
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
MyCurrentProfit += OrderProfit();
}
if(MyCurrentProfit>=ProtectStarter) //start protection at this level!
ProtectLoss=true;
if(MyCurrentProfit>=profit)
CloseAll();
}
void LossProtect(double profit)
{
int total = OrdersTotal();
double MyCurrentProfit=0;
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
MyCurrentProfit += OrderProfit();
}
if(MyCurrentProfit<=profit)
CloseAll();
}
void CloseAll()
{
int total = OrdersTotal();
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
if(OrderType()==OP_BUY)
OrderClose(OrderTicket(),OrderLots(),Bid,Slippage, Violet);
if(OrderType()==OP_SELL)
OrderClose(OrderTicket(),OrderLots(),Ask,Slippage, Violet);
}
}
We have defined our profit point as external variables at the top of the program:
extern double ProfitToProtect = 200;
extern double ProtectStarter = 150;
extern double LossToProtect = 100;
extern bool ProtectProfit= true;
Where the the ProfitToProtect is the amount we want the program to take the profit when it is reached. And the ProtectStarter is the amount the program start at monitoring the profit to prevent drop down again. And finally the LossToProtect is the amount of the profit the program prevent the profit to drop below it.
We have added the option to the user to use our profit protector or not with the variable ProtectProfit;
bool ProtectLoss= false;
We have declared this variable outside the start() function to make it in a global scope and we will use this variable to start the profit monitoring.
if(ProtectProfit)
ProfitProtect(ProfitToProtect);
If the user has chosen to use our protect (ProtectProfit=True) then the program will call the function ProfitProtect(). We are going to study this function soon.
if(ProtectLoss)
LossProtect(LossToProtect);
If the ProtectLoss variable is true (It will be true when the profit reaches the ProtectStarter level) then the program will call the function LossProtect() which we are going to study it soon.
void ProfitProtect(double profit)
{
int total = OrdersTotal();
double MyCurrentProfit=0;
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
MyCurrentProfit += OrderProfit();
}
if(MyCurrentProfit>=ProtectStarter) //start protection at this level!
ProtectLoss=true;
if(MyCurrentProfit>=profit)
CloseAll();
}
The ProfitProtect() function takes a double parameter (profit you want to protect).
It starts by getting the number of opened orders by calling the function OrdersTotal()
then it declares a double variable MyCurrentProfit and initialize it to 0. We will use this variable to calculate the profit of the opened positions.
Now we enter in loop from 0 to the count of the opened positions. In every loop we select the order using OrderSelect() function and examine is the MagicNumber of the order is the same as our MagicNumber variable to be sure that we are working only with the positions have been opened with our Expert Advisor. Then we get the profit of the order using OrderProfit() and add it to the MyCurrentProfit variable.
Now we have the total profit stored in the MyCurrentProfit variable, We can check it now to find did it reach the ProtectStarter value; if true we will enable ProtectLoss. And we have to check the MyCurrentProfit variable against ProfitToProtect variable to find did it reach it or not; if true we will call the CloseAll() function which will close all the opened positions.
void LossProtect(double profit)
{
int total = OrdersTotal();
double MyCurrentProfit=0;
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
MyCurrentProfit += OrderProfit();
}
if(MyCurrentProfit<=profit)
CloseAll();
}
The LossProtect() function is very like the ProfitProtect() function, the only difference is it will monitor the MyCurrentProfit value and close all the opened position if it goes below the LossToProtect vlaue.
void CloseAll()
{
int total = OrdersTotal();
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(0,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
if(OrderType()==OP_BUY)
OrderClose(OrderTicket(),OrderLots(),Bid,Slippage, Violet);
if(OrderType()==OP_SELL)
OrderClose(OrderTicket(),OrderLots(),Ask,Slippage, Violet);
}
}
The CloseAll() function goes through all the opened position and check them against our expert MagicNubmer then close every buy or sell position using OrderClose() function.
I hope everything is clear, And hope you find it a useful idea!
Coders Guru
Hi folks,
Today we are going to study a very important set of functions that enables us to work with external files from the MQL4 programs; the File functions.
One of annoying feature of MQL4 that the directories limitation; you can't work with files that outside one of these three directories:
MetaTrader thinks it's safer to limit the directories you can access from the normal MQL4 program and give you the ability to write your MQL4 extension (dll) to do what do you want.
Note: I've wrote a dll that enable you to work with files outside the limited directories of MQL4, you can know more by going there: http://www.forex-tsd.com/tools-utilities/386-mt4-files-functions-replacement.html
There are a lot of functions to study in this section, so, we are going to divide this lesson to two parts each of them study the half of File functions. Let's start this part of the lesson.
Syntax:
| int FileOpen( string filename, int mode, int delimiter=';') |
Description:
The FileOpen function opens the given file for a specific mode (purpose) and returns its handle.
You pass to the FileOpen function the file name you want to open; this file must be located in Terminal_Install_Dir/EXPERTS/FILES or Terminal_Install_Dir/TESTER/FILES and their subdirectories.
You open the file for writing, reading or both and you determine that with the mode parameter.
The returned value of the FileOpen function is the file handle if the function successes and -1 if failed. File handle is a unique number assigned for the file which you will use with the most of the File functions to work with the opened file.
Parameters:
This function takes three parameters:
string filename:
The file name you want to open.
int mode:
The purpose you want to open the file for, there are four modes which you can use and combine them:
FILE_CSV: use this mode to open the csv (Comma-separated values) file format.
FILE_BIN: use this mode to open the binary file format.
FILE_READ: use this mode to open the file for reading (getting data from the file).
FILE_WRITE: use this mode to open the file for writing (saving data to the file).
Note 1: You can not combine the FILE_CSV and FILE_BIN in mode parameter.
Note 2: If you open the file with FILE_WRITE and the file wasn't exist a new file with the filename parameter will be created.
Note 3: If you open an existing file with FILE_WRITE mode (without combining it with FILE_READ) the data in the file will be deleted and will be empty file. If you want to add (append) data to an existing file you have to open it with the combination of FILE_WRITE and FILE_READ.
Note 4: You can not use FILE_READ mode with not existing file.
Note 5: You can open more than 32 files from the same program and you can't use the file handles returned from a program with another program.
int delimiter:
In the case of opening csv the delimiter is the character that separates the data, the default value is ";" delimiter.
Example:
| int handle; |
Syntax:
| void FileClose(int handle) |
Description:
The FileClose function closes the given file; you pass to it the file handle (you've got this handle when you opened the file with FileOpen function) and it will close it.
Parameters:
This function takes only one parameter:
int handle:
The handle of the opened file you want to close.
Example:
| int handle=FileOpen("filename", FILE_CSV|FILE_READ); |
Coder Guru
www.xpworx.com
Hi folks,
Today we are going to study a set of MQL4 functions which needs to be clearer for the new comers to the language. We are going to study the Global variables and the MQL4 functions that handle them.
The global variables are places to store data between the instances of MQL4 programs and MetaTrader launches too.
In MQL4 you use the normal variables to store the data temporary and it exists only at the time that program is running and vanishes with the un-initialization of the program. But the global variables exist when you un-initialize the program and even if you shut down the terminal itself. The terminal can store the global variables for four weeks from the last store.
The main job of the global variables is enabling the inner communication between the experts advisor.
Assume that you have created two expert advisors:
The first expert advisor works on daily time frame and buys the EURUSD when the Moving Averages of the price of the last 10 days crosses upward the Moving Averages of the price of the last 80 days.
And it sells the EURUSD when the Moving Averages of the price of the last 10 days crosses downward the Moving Averages of the price of the last 80 days.
And the second expert advisor works on 1 hour time frame and buys the EURUSD when the Moving Averages of the price of the last 10 hours crosses upward the Moving Averages of the price of the last 80 hours.
And it sells the EURUSD when the Moving Averages of the price of the last 10 hours crosses downward the Moving Averages of the price of the last 80 hours.
You don't want the two expert advisors to take conflicted decisions. You don't want the first expert advisor to sell the EURUSD while the second expert advisor is buying the EURUSD.
Any of the two expert advisors doesn't know anything about the other. How can they communicate?
They can communicate with the aid of writing/reading global variables.
For instance the first expert advisor can write a global variable when it open sell/buy order while the second expert advisor can read this variable to be sure that it will not open a conflicting orders.
Of course the possibilities of using global variables are not limited. Our example today will use the global variables in a very useful way.
When you attach an expert advisor to more than one chart/pair and want to change one of the expert advisor inputs values for all the charts you have to change this input for every chart.
If your expert advisor attached to ten pairs it will be a real problem to make the change 10 times.
Our program today will use the global variables to make the changes available to all the charts hold our expert advisor.
There are 6 functions in MQL4 responsible of handling the global variables. These are the global variables functions:
Syntax:
| bool GlobalVariableCheck (string name) |
Description:
The GlobalVariableCheck function checks if there's a global variable with the name passed to, it returns true if it exists and false if not exists.
You can use GetLastError to get the error information if any error has been occurred will you calling this function.
Parameters:
This function takes only one parameter:
string name
The global variable name the function will check is it exists or not.
Example:
| if(!GlobalVariableCheck("ge_TakeProfit ")) Alert("ge_TakeProfit global variable is not exist"); |
Syntax:
| bool GlobalVariableDel (string name) |
Description:
The GlobalVariableDel function deletes the global variable you passed its name and return true in success and false if it failed to delete it.
You can use GetLastError to get the error information if any error has been occurred will you calling this function.
Note: If the global variable not found the returned value will be 0 while the error code will be 4057 which means global variables processing error.
Parameters:
This function takes only one parameter:
string name
The global variable name the function will delete.
Example:
| Alert(GlobalVariableDel("ge_TakeProfit ")); |
Syntax:
| double GlobalVariableGet (string name) |
Description:
The GlobalVariableGet function returns the value of the global variable name passed to it. This value must to be double data type.
You can use GetLastError to get the error information if any error has been occurred will you calling this function.
Note: You can store in the global variable and data type but the double data type. And if you tried to store any data type other than the double data type, MQL4 will try to convert it to double data type.
Note: If the global variable not found the returned value will be 0 while the error code will be 4058 which means global variable not found. So, you have to use GlobalVariableCheck function before using GlobalVariableGet if your variable maybe 0.
Parameters:
This function takes only one parameter:
string name
The global variable name the function will return its stored value.
Example:
| if(GlobalVariableCheck("ge_TakeProfit")) TakeProfit = GlobalVariableGet("ge_TakeProfit"); |
Syntax:
| datetime GlobalVariableSet (string name, double value) |
Description:
The GlobalVariableSet function sets the variable name passed to it with the value passed to it.
If the global variable name does not exist the function will create it and set it to the passed value. If it exists the function will change its old value to the new one.
The returned value is a datetime data type which is the time of the last access time of the global variable if the function successes and if it failed the return value will be 0.
You can use GetLastError to get the error information if any error has been occurred will you calling this function.
Parameters:
This function takes two parameters:
string name
The global variable name the function will set its value (or create it and sets its value).
double value
The value of the global variable you want to set (or create). This value must be double (numeric) data type.
Example:
| Alert(GlobalVariableDel("ge_TakeProfit ")); |
Syntax:
| bool GlobalVariableDel (string name) |
Description:
The GlobalVariableDel function deletes the global variable you passed its name and return true in success and false if it failed to delete it.
You can use GetLastError to get the error information if any error has been occurred will you calling this function.
Note: If the global variable not found the returned value will be 0 while the error code will be 4057 which means global variables processing error.
Parameters:
This function takes only one parameter:
string name
The global variable name the function will delete.
Example:
| Alert(GlobalVariableDel("ge_TakeProfit ")); |
Many people are asking me how to create a label or other object in the separate window so I will describe it now. First we will see what can be created using labels.

As we see on the example, label can be put at any place on the chart. Label can be put at any window that u want to. You can point the window on which label should be put. But let's start from the begining.
What is label?
Label is an object. It means that when u draw label (manual or by script), u can change it's properties. U can change the color, and placement, even the shape of it. The second very important property of the object is that he don't vanish when u close metatrader and open it again. Once drow it stays on the chart till u close the chart window or delete the object.
(...) to be continoued...
Hi folks,
I've got a lot messages in the forex-tsd forum asking me how to use iMaOnArray function to get the Moving Average of a specific indicator. Today I'm going to answer all of you in this article.
When you attach an indicator to the chart it uses the price to for it calculation and save (draw) them . You can calculate the moving average of this array.
I'll give you a manual example before going to create our mql4 version.
Let's say that we will attach the CCI (Commodity Channel Index) indicator to our chart (Figure 1).
Now we want to get the moving average of the CCI. We can do that by dragging the Moving Average indicator to the window holds the CCI indicator and choose the Apply to: Previous Indicator's Data (Figure 2).
And that's what you get (Figure 3)
If you are interested in getting the moving average of any indicator like the above manual setup, you can 'trigger' your MetaEditor and write this code:
//+------------------------------------------------------------------+
//| iMAOnArray.mq4 |
//| Coders Guru |
//| http://www.metatrader.info |
//+------------------------------------------------------------------+
#property copyright "Coders Guru"
#property link "http://www.metatrader.info"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 LawnGreen
#property indicator_color2 DarkBlue
double ExtMapBuffer1[];
double ExtMapBuffer2[];
int init()
{
IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexStyle(1,DRAW_LINE,STYLE_SOLID,2);
SetIndexBuffer(1,ExtMapBuffer2);
return(0);
}
int deinit()
{
return(0);
}
int start()
{
int bar, limit;
int counted_bars=IndicatorCounted();
if(counted_bars<0) return(-1);
if(counted_bars>0) counted_bars--;
limit=Bars-IndicatorCounted();
for(bar=0; bar<limit; bar++)
ExtMapBuffer1[bar] = iCCI(NULL,0,14,PRICE_TYPICAL,bar);
for(bar=0; bar<limit; bar++)
ExtMapBuffer2[bar]=iMAOnArray(ExtMapBuffer1,Bars,14,0,MODE_EMA,bar);
return(0);
}
As you can notice in the above code that we use the function iCCI and iMAOnArray to calculate the Moving average of the CCI indicator.
The iCCI function simply calculate the CCI of a giving bar and return its value. We store those values returned by iCCI function in our buffer ExtMapBuffer1.
Now we have a full of data buffer (ExtMapBuffer1), how to get the Moving Average of this buffer?
With the aid of the iMAOnArray function we can calculate the moving average of the values stored in an array(buffer).
This is the syntax of the iMAOnArray function:
The iMAOnArray - as you see in its syntax - returns double value; this is the value of the moving average - counted on the array - of the given bar. Don't worry you will understand well when you know the parameters of the iMAOnArray function.
This is the array of the values you want to calculate the moving average of it.
You have to fill this array with double data type items.
In our example we used the bufferex1 as the array[] parameter passed to iMAOnArray after filling that array with the values of the CCIs of the bars in our chart.
You use the total parameter to indicate the count of items of the data from the array you want to use to calculate the moving average.
If you want to use all the items in the array in your moving average calculation pass 0 in the total parameter.
The moving average period of the moving average you want to use.
If you are familiar to moving average you can skip this section.
when use the moving average indicator with the hourly chart and use 12 as the period of moving average calculation ; it means that you want to know the average of the price of the previous 12 hours.
when use the moving average indicator with the daily chart and use 30 as the period of moving average calculation ; it means that you want to know the average of the price of the previous 30 days.
The moving average method you want to use in your calculation.
These are the moving average methods available in MetaTrader
Hi folks,
We talked before about the iCustom function and how can we use it to embed custom indicators in our expert advisors code.
We said that we have to have the .ex4 file of the indicator installed in indicators folder to be able to use iCustom, then all what we need is to call the iCustom function passing to it the name of the .ex4 file, the parameters the indicators use and decide which indicator's line we want to retrieve its value.
The only problem of using iCustom is that you have to distribute the indicator you use with your expert advisor and the user of your expert advisor have to be sure he is using the right version of the indicator.
Today we are going to take another approach of embedding indicators in expert advisors, we are going to rewrite the code of the indicator into our expert advisor and use it as a function which we can call it within the expert advisor.
By this way (writing the code of the indicator in the expert advisor) you can freely distribute only the expert advisor without bothering yourself and your user.
Our indicator is a very simple indicator, yet it will give a good picture of how to embed an indicator in an expert advisor, This is the code of the indicator:
//+------------------------------------------------------------------+
//| SmCCI.mq4 |
//| Copyright © 2006, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- input parameters
extern int t3_period=21;
extern double b=0.7;
//---- buffers
double ExtMapBuffer1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtMapBuffer1);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
double e1, e2, e3, e4, e5, e6, c1, c2, c3, c4, n, w1, w2, b2, b3;
double dpo, t3;
b2=b*b;
b3=b2*b;
c1=-b3;
c2=(3*(b2+b3));
c3=-3*(2*b2+b+b3);
c4=(1+3*b+b3+3*b2);
n=t3_period;
if (n<1) n=1;
n = 1 + 0.5*(n-1);
w1 = 2 / (n + 1);
w2 = 1 - w1;
for(int i=Bars; i>=0; i--)
{
dpo=Close[i];
e1 = w1*dpo + w2*e1;
e2 = w1*e1 + w2*e2;
e3 = w1*e2 + w2*e3;
e4 = w1*e3 + w2*e4;
e5 = w1*e4 + w2*e5;
e6 = w1*e5 + w2*e6;
t3 = c1*e6 + c2*e5 + c3*e4 + c4*e3;
ExtMapBuffer1[i]=t3;
}
Print ("SmCCI : " , ExtMapBuffer1[0], ":", ExtMapBuffer1[1]);
return(0);
}
//+------------------------------------------------------------------+
Note: We have added the line:
Print ("SmCCI : " , ExtMapBuffer1[0], ":", ExtMapBuffer1[1]);
Because we want to compare the value returned by the indicator with the value returned by the expert advisor.
Which part of the code above we are going to add to the expert advisor and how and where, these are the questions.
There are two important pieces of codes in any indicator that we have to duplicate them in the expert advisor if we want to get the same values of the indicators:
The most of the indicators enable the user to change the parameters of the indicator by declaring this set of variables with extern keyword.
Besides the external variable the indicator may use global variables - global variables are the variables that has been declared at the top of the indicator code and outside any user custom or special function.
If we want to embed the code of indicator into an expert advisor we have to know how and what kind of global/external variables the indicator use.
The indicator land of battle is inside the start() function, and if we want to embed the indicator code into an expert advisor we have to duplicate the start() block of code into the expert advisor.
How could we use the indicator's start() block of code in our expert advisor? That's what this article for!
Our expert advisor will not do anything more than duplicating the code of the indicator and printing the values of the embedded indicator code.
We are going to convert the indicator to function that we can call it in our expert advisor, let's see how can we do it!
//+------------------------------------------------------------------+
//| Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Coders Guru"
#property link "http://www.forex-tsd.com"
//+------------------------------------------------------------------
int init()
{
return(0);
}
int deinit()
{
return(0);
}
//+------------------------------------------------------------------+
int start()
{
double trend ;
if(Bars<100) {Print("bars less than 100"); return(0);}
Print ("PipHunter :" , SmCCI(21,0.7,0) , ":" , SmCCI(21,0.7,1));
return(0);
}
//+------------------------------------------------------------------+
double SmCCI (int t3_period , double b,int bar)
{
double e1, e2, e3, e4, e5, e6, c1, c2, c3, c4, n, w1, w2, b2, b3;
double dpo, t3;
b2=b*b;
b3=b2*b;
c1=-b3;
c2=(3*(b2+b3));
c3=-3*(2*b2+b+b3);
c4=(1+3*b+b3+3*b2);
n=t3_period;
if (n<1) n=1;
n = 1 + 0.5*(n-1);
w1 = 2 / (n + 1);
w2 = 1 - w1;
for(int i=Bars; i>=bar; i--)
{
dpo=Close[i];
e1 = w1*dpo + w2*e1;
e2 = w1*e1 + w2*e2;
e3 = w1*e2 + w2*e3;
e4 = w1*e3 + w2*e4;
e5 = w1*e4 + w2*e5;
e6 = w1*e5 + w2*e6;
t3 = c1*e6 + c2*e5 + c3*e4 + c4*e3;
}
return (t3);
}
The trick behind the expert advisor code and all the work is in the SmCCI function.
In the SmCCI function we have used the indicator's external variables (t3_period and b) as parameters for the function.
The third parameter in the function is int bar which we use it as a reference to the bar we want to calculate its indicator value (current bar = 0 and the previous bar = 1 etc).
The indicator's start() block of code is duplicated with very small changes:
1- In the for loop instead looping to 0 we are looping to the bar parameter.
2- The line: ExtMapBuffer1[i]=t3; was removed from the function because we are not in an indicator so we are painting on buffer.
3- The variable t3 is holding the indicator calculation value, so we return it.
The final result of the expert advisor and when we call the SmCCI function like this:
Print ("PipHunter :" , SmCCI(21,0.7,0) , ":" , SmCCI(21,0.7,1));
We are expecting to get the same values of the indicator. And that's what we have got (Figure 1).
I hope you find it a useful lesson and see u!
Coders' Guru
Welcome to the practical world of MQL4 courses; welcome to your first indicator in MQL4.
I recommend you to read the previous nine lessons very carefully, before continuing with these series of courses, that’s because we will use them so much in our explanations and studies of the Expert Advisors and Custom Indicators which we will create in this series of lessons.
Today we are going to create a simple indictor which will not mean too much for our trade world but it means too much to our MQL4 programming understanding.
It simply will collect the subtraction of High [] of the price – Low [] of the price; don’t be in a hurry, you will know everything very soon.
Let’s swim!
This is the program which has been shipped with MT4 (MetaTrader 4) enables you to write your programs, read MQL4 help, compile your program and More.
I’ve made a shortcut for MetaEditor on my desktop for easily access to the program.
If you want to run MetaEditor you have three choices.
1- Run MT4, then click F4, choose MetaEditor from Tools menu or click its icon on the Standard toolbar (Figure 1).
2- From Start menuà Programs, find MetaTrader 4 group then click MetaEditor.
3- Find the MT4 installation path (usually C:\Program Files\MetaTrader 4), find the MetaEditor.exe and click it (I recommend to make a shortcut on you desktop).

Figure 1 – MetaTrader Standard Toolbar
Any method you have chosen leads you to MetaEditor as you can see in figure 2.
As you can see in figure 2, there are three windows in MetaEditor:
1- The Editor window which you can write your program in.
2- The Toolbox window which contains three tabs:
a. Errors tab, you see here the errors (if there any) in your code.
b. Find in files tab, you see here the files which contain the keyword you are searching for using the toolbar command “Find in files” or by clicking CTRL +SHIFT+ F hotkeys.
c. Help tab, you can highlight the keyword you want to know more about it and click F1, and you will see the help topics in this tab.
3- The Navigator window which contains three tabs:
a. Files tab, for easy access to the files saved in the MT4 folder.
b. Dictionary tab enables you to access the MQL4 help system.
c. Search tab enables you to search the MQL4 dictionary.
Figure 2 – MetaEditor Windows
I recommend you to navigate around the MetaEditor Menus, Toolbar and windows to be familiar with it.
Now let’s enjoy creating our first custom indicator.
Note:Custom Indicator is a program which enables you to use the functions of the technical indicators and it cannot automate your deals.
Now you have run your MetaEditor and navigated around its Menus, Toolbar and windows, let’s USE it.
To create a custom indicator you have to start with three steps (you will learn later how to skip these boring steps (my personal opinion).
Step 1: Click File menu à New (you use CTRL+N hotkey or click the New Icon in the Standard toolbar).
You will get a wizard (Figure 3) guiding you to the next step.
Choose Custom Indicator Program option, and then click next.
Figure 3 - New project wizard
Step 2: When you clicked Next, you will get the second step wizard (Figure 4) which will enable you to edit the properties of your program. In this step you can enter these properties:
1- Name of your program, this is the name which the world will call you program with and it will be saved as the_name_you_have_chosen.mq4
2- Author name, the creator of the program name.
3- Link to your web site.
4- External variables list: I want to pause here to remember you about external variable.
External variables are the variables which will be available to the user of you indicator to set from the properties tab of your indicator in MetaTrader. For example: MA_Period in the very popular EMA indicator. And these variables will be declared with the “extern” keyword in your code (Please review Variables lesson).
So, this section of the wizard enables you to add these kinds of variables.
In our first indicator example we will not need any external variables just write the values you see in figure 4 and let’s go to step 3 by clicking Next button.

Figure 4 – Program properties wizard.
Step 3: The third wizard you will get when you clicked Next button is the Drawing properties wizard (Figure 5).
Its job is enabling you to set the dawning properties of the lines of your indicator, for example: how many lines, colors and where to draw your indicator (in the main chart or in separate windows).
This wizard contains the following options:
1- Indicator in separate window option: by clicking this option, your indicator will be drawn in separate windows and not on the main chart window. If you didn’t check the option, your indicator will be drawn in the main chart window.
2- Minimum option: it will be available (enabled) only if you have checked the Indicator in separate window option, and its job is setting the bottom border for the chart.
3- Maximum option: it will be available (enabled) only if you have checked the Indicator in separate window option, and its job is setting the top border for the chart
4- Indexes List: here you add your indicator line and set its default colors.
I want you to wait to the next lesson(s) to know more about these options and don’t be in a hurry.
For our first indicator example, choose Indicator in separate window option and click Add button, when you click add button the wizard will add a line to the indexes list like you see in figure 5.

Figure 5 - Drawing properties wizard.
When you click Finish button the Magic will start. You will see the wizard disappeared and the focus returned to the MetaEditor environment and… guess what?
You have ready to use first indicator draft code.
This is the code you will get:
//+------------------------------------------------------------------+
//| My_First_Indicator.mq4 |
//| Codersguru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Codersguru"
#property link "http://www.forex-tsd.com"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- buffers
double ExtMapBuffer1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtMapBuffer1);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars=IndicatorCounted();
//----
//----
return(0);
}
//+------------------------------------------------------------------+
As you see in the above code, the wizard has written a lot of code for you, now I have to thank the wizard and to thank you too.
In the next lesson we will discover every line of code you have seen above and add our code to make our first indicator. To this lesson I hope you be ready!
Please don’t forget to download the source code of the first indicator and warm yourself for the next lesson.
I welcome very much the questions and the suggestions.
See you
Coders’ Guru
Hi folks,
Today we are going to discuss a flustering issue for the most of new MQL4 comers; the life cycle of the MQL4 program.
What the first block of code is executed first and what the last block of code is executed, what's the phases of the MQL4 program. What's the different between the life cycle of the expert advisors and script? and a lot of questions about the MQL4 program life cycle.
Let's know first what happen when the MQL4 starts?
The first time you attach the MQL4 to chart the first thing MetaTrader will do is showing the input dialog depending on the type of the program:
In this case you'll get the expert advisor input window (Figure 1) which enable you to set the parameters of the expert advisor if there was any (i.e. take profit and stop loss levels).
Each variable you declare using "extern" keyword will appear in the expert advisor input windows with its default value.

The same as expert advisors, the first time you attach an indicator to chart you'll get the parameters window (Figure 2) which enable you to set the parameters of the indicator, the colors of the indicator lines (Figure 3) and the levels of the sub-window chart (Figure 4).
Each variable you declare using "extern" keyword will appear in the indicator parameters windows with its default value.
The colors are defined using the preprocessor keyword "#property indicator_colorN", for example:
#property indicator_color1 Silver
#property indicator_color2 Red
and the preset levels are defined using the preprocessor keywords "#property indicator_levelN", "#property indicator_levelcolor", "#property indicator_levelwidth" and "#property indicator_levelstyle".


If there were any inputs coded in the script using the extern keyword, they will appear in the script input window (Figure 5) only if you used the preprocessor keyword "#property show_inputs".
If you used "#property show_confirm" preprocessor keyword a confirmation message box will appear before the script input window.
This is the first step MetaTrader will take in the journey of the MQL4 program life. Let's see what will happen nex?
The next phase in the MQL4 program cycle is the initialization phase.
Every line of code you wrote inside the block of init() function will be executed in this phase. This phase executed if one of these triggers occurred:
1- The first time you attach the program to a new chart (After the input window appearance).
2- When you start MetaTrader and there were opened chart(s) that hosts expert advisors or indicators. The script is executed only once (to the end of its life cycle) then de-initialized so MetaTrader wouldn't host opened scripts.
3- When you change the period of the chart and the program was hosted on one or more charts (except the scripts).
4- When you change the symbol of the chart and the program was hosted on one or more charts (except the scripts).
5- When you recompile the program in MetaEditor and the program was hosted on one or more charts (except the scripts).
6- When you change one of the program inputs (hitting F7 hot key to open expert advisor input window and right click the indicator then choose indicator properties from the context menu - Figure 6).
7- When you change the account the expert advisors will be initialized.
Unlike the above case, the initialization code is executed only one time during the life cycle of the program and will not be called again till the end of the program.
After the initialization of the program it will wait for new quotation arrival from the server, every time MetaTrader receives new price quotation from the server it calls start() function and execute all the lines of the code in its block.
Note: The scripts is an exception because its start() function is executed once you attach it to the chart and immediately after the init() function then the script is detached from the chart.
The start() function have to finish its job first before receiving/reacting to new quotations, that means the code of start() function is executed line by line and only when MetaTrader find the return keyword it will be ready to call start() function again with the most new quotation.
If there were any quotations that arrived while the execution of start() function it would be ignored by the program,
Besides the new quotation arrival trigger, the start() function is executed in these cases:
1- For the indicators the start() function is recalled in the case of changing the chart symbol.
2- For the indicators the start() function is recalled in the case of changing the chart period
Note: The start() function will not be run when you open the expert advisor input window, you have to close it to enable MetaTrader to execute start() function again.
The execution phase is the longest phase in the program cycle life and in the most of programs the start() function block code is the most important code.
Every program attached has its end, when the program ends its job the block of deinit() function will be executed.
These are the triggers of the deinit() function:
1- When you shut down MetaTader and the program was hosted on one or more charts.
2- When you close the chart that hosts the program.
3- Before the changing of the period of the chart that hosts the program.
4- Before the changing of the symbol of the chart that hosts the program.
5- When you recompile the program and the program was hosted on one or more charts.
6- When you change the inputs of the program.
7- When you change the account the expert advisors will be de-initialized.
These was the life cycle of the MQL4 program and it's the time to de-initialize the lesson.
Hope you enjoyed it,
Coders Guru
Hi folks,
I've decided to set aside an article for the Magic Number mystery because of the huge quantity of questions from the novices in the forex-tsd forum.
It's an article about a daily question!
This is one of the question we have got everyday in the forum:
"Hi,
I would like to learn how to alter a basic EA (say, the Simple MACD) to allow me to place multiple, concurrent orders for a given account. For example, if I want to be able to place an order for each different currency pair and not have any conflicts in terms of the order placing or order closing process.
I believe this has something to do with the OrderSend function and the "magic" parameter, but that's as far as I've gotten.
Any help on this would be great.
Thanks,
Ian"
Well Ian, you have given a hint of the what's the Magic Number for.
The Magic Number is one of the parameters (optional parameter) of the OrderSend Function:
int OrderSend( string symbol , int cmd , double volume , double price, int slippage , double stoploss , double takeprofit , string comment=NULL , int magic=0 , datetime expiration =0 , color arrow_color=CLR_NONE)
OrderSend() is the function you use in MQL4 to open a new order (instant or pending order) and the magic parameter (the ninth parameter ) is an integer value you set as a magic number of the opened order!
So, The answer of the first question is "The Magic Number is one of the OrderSend parameters which you can set when you send your order".
What's the Magic Number for? is the one on the negotiation table right now.
The Magic Number is a unique number you assign to your order(s) as a reference enables you to distinguish between the orders that opened by your expert advisor and the orders that opened by another expert advisors or manually.
To know how much important to use the Magic Number we have a simple code:
Our sample is an Expert Advisor that opens 4 buying order ( no conditions because it's just a sample) and close them all when the total profit of them reaches 100 Pips or the total loss is -100 Pips.
With the aid of using Magic Number our Expert Advisor is smart enough to know is the order has been opened by itself or it has been opened by another expert advisor or manually.
Here's the code:
int MagicNumber = 101030;
extern double Profit = 100;
extern double Loss = -100;
//+------------------------------------------------------------------
int init()
{
return(0);
}
int deinit()
{
return(0);
}
int start()
{
int cnt, ticket, total,n;
if(Bars<100) {Print("bars less than 100"); return(0);}
total = OrdersTotal();
if(total < 1)
{
OrderSend(Symbol(),OP_BUY,1,Ask,5,0,Ask+100*Point,"MagicNumber demo",MagicNumber,0,Green);
OrderSend(Symbol(),OP_BUY,1,Ask,5,0,Ask+100*Point,"MagicNumber demo",MagicNumber,0,Green);
OrderSend(Symbol(),OP_BUY,1,Ask,5,0,Ask+100*Point,"MagicNumber demo",MagicNumber,0,Green);
OrderSend(Symbol(),OP_BUY,1,Ask,5,0,Ask+100*Point,"MagicNumber demo",MagicNumber,0,Green);
return(0);
}
ProfitLossMonitor();
return(0);
}
void ProfitLossMonitor()
{
int total = OrdersTotal();
double MyCurrentProfit=0;
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
MyCurrentProfit += OrderProfit();
}
if(MyCurrentProfit>=Profit)
CloseAll();
if(MyCurrentProfit<=Loss)
CloseAll();
}
void CloseAll()
{
int total = OrdersTotal();
for (int cnt = 0 ; cnt < total ; cnt++)
{
OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
if (OrderMagicNumber() == MagicNumber)
if(OrderType()==OP_BUY)
OrderClose(OrderTicket(),OrderLots(),Bid,5,Violet);
if(OrderType()==OP_SELL)
OrderClose(OrderTicket(),OrderLots(),Ask,5,Violet);
}
}
The expert advisor at the first place has defined (declared) the integer variable MagicNumber to use it later in the code.
int MagicNumber = 101030;
The expert advisor opens 4 buy orders and use the function ProfitLossMonitor() to monitor the sum of profit or loss. But how can the Expert advisor know that current opened order has been opened by him or by another expert advisor?
The expert advisor checks the MagicNumber of selected order returned by OrderMagicNumber() against the MagicNumber variable to know is it our order or not:
if (OrderMagicNumber() == MagicNumber)
When the total of profit is equal to 100 or the total of the loss equal to -100 the Expert advisor will call the function CloseAll() to close all the opened orders have been opened by the expert advisors. And before closing those orders the Expert Advisor checks again the MagicNumber of selected order returned by OrderMagicNumber() against the MagicNumber variable.
Without using Magic Number could you imagine the operation of these kinds of expert advisors? How could they calculate the profit and loss of their orders? How could they close only their orders?
That's why the Magic Number is essential!
Coder Guru
www.xpworx.com
Hi folks,
We are going to complete our series of lessons that answer the question: "How to deal with currency pairs which are different than the current chart currency (The chart that hosts the expert advisor)? For example, how to make an expert advisor that can open Buy position of GBPUSD or USDCHF while the expert advisor is hosted on EURUSD chart?"
In the previous lesson we studied the Timeseries Access functions that enables us to access the price date of any chart (currency and timeframe) regardless of the chart that hosts the expert advisor. But they are not enough to write our expert advisor.
What's the Bid/Ask price we are going to use with OrderSend to open the order? We can't use the function Bid() and Ask() because they are returning the current currency Bid and Ask price.
Our magic function today is MarketInfo() function:
Syntax:
| double MarketInfo( string symbol, int type) |
Description:
The MarketInfo() function is the function you need to retrieve various market data of the given currency, for example: the current Bid price of the currency, the current Ask price of the currency, the Swap value of Buy or Selling the currency and the number of digits the currency uses.
Note: A part of this data are stored in the Predefined Variables but this data is exclusive for the current chart and MarketInfo() function give us more data about the currency.
This function can return the following important data:
Hi folks!
We have studied Arrays here and here. Please give them a review!
Today we are going to study an example of 2 dimensional array and a very useful code that "Using Arrays to track info for All Open Orders" (Do you hear me deeforex ?)
The best model that the arrays are look like is the tables. You have a table that includes only your monthly profits/losses in Forex; this is one dimensional array.
For the complex data you need more columns in the table and more dimensions in the array. For example the table (array) which will hold all the opened trades information maybe looks like that:
| OrderSwap | OrderLots | OrderTakeProfit | OrderStopLoss | OrderProfit | OrderOpenPrice |
| -0.68 | 0.10 | 0.00 | 0.00 | 45.97 | 118.01 |
| 0.00 | 0.10 | 1.8763 | 1.8713 | 6.00 | 1.8758 |
| 0.00 | 0.30 | 0.7531 | 0.7478 | 15.00 | 0.7523 |
Could you guess how much dimensions the array above have? No! It's 2 dimensional array!
"Whatever the number of the fields, whatever the number of columns, the 2 dimensional arrays are for your all purposes" Saying of mine :)!
The array above has 2 dimensions; the first dimension is the fields of the array (we have three fields in the table above). The second dimension is the columns of the array (we have 6 columns in the table above). So, in code our array will be like that:
double myarray[2][5];
No! it's not a typo! In the world of MQL4 arrays (and the most of programming language arrays) the first element of the array starts from 0. so the 3 fields and 6 columns arrays will be "myarray[2][5]" (We always subtract 1 from the total elements of the array).
Note: There are 3 dimensional arrays and 4 dimensional arrays in MQL4 but they are abandoned topics. Just for your knowledge the maximum dimension of the arrays in MQL4 is 4 dimensional arrays.
Hi folks!
I'm very fanatic for sharing MQL4 codes/ideas, however I've got a lot of requests asking me about MQL4 indicator/experts protection. I think it's not evil to use your programming talent to get some money if you don't want to share (it's a choice anyway).
Without protecting your MQL4 code it will be waste of time to try to commercialize your programs, that's why I'm writing this article.
Just as a review and to emphasis that we are talking about how to protect the .ex4 files read the next section:
There are two kinds of files that you use with MetaTrader; the program files and the executable files:
The program files are normal text files but have one of these extensions: .mq4 and .mgh.
These files are the source code of the programs wrote in MQL4 programming language; source code means they could be opened for viewing or editing in MetaEditor.
The executable files are binary files (you can't open them for viewing or editing) and has the extension .ex4.
These files are the result of compiling the .mq4 files using MetaEditor, and these are the files that you can load them in MetaTrader and use them.
Compiling is an operation taken by a special program (called a compiler) to convert the program from text (readable) format to the binary format which the computer can understand (computers think in binary).
This is the general definition of compiling. Compiling in our case is converting the mq4 files to ex4 for file using MetaEditor program. We are doing this by opening the mq4 files in MetaEditor then pressing F5 hot key. MetaEditor will compile (convert) the file to ex4 format and keeping the mq4 file untouched MetaEditor will place the generated ex4 file at the same path as the mq4 file. We compile the mq4 files because the MetaTrader can't load any files except ex4 files.
The source code of MQL4 programs can't be protect because it's in text format and when you distribute it you intend to give the receiver the access to the source code of the program.
The executable version of the program is the only version that you can protect it. You protect it by write the protection code in the source code of the program then compile it to the ex4 format then distribute it to the user.
We are going to discuss some ideas of MQL4 programs protection, maybe they are not the best but they are the common ideas, we are going to write some code to apply these ideas:
This the widely used method to protect softwares in general and can be used to protect MQL4 programs.
When the user buy your program you send him the program with a password and he can use the program without the password.
This is a simple code to apply password protection method:
int start()
{
extern string Please_Enter_Password = "0";
// your code here....
int start()
{
if (password != "viva metatrader") //change to the password you give the user!
{
Alert ("Wrong password!");
return (0);
}
// your code here....
}
In the code above the password is "viva metatrader" which is hard coded in the MQL4 file. You have to compile the program after adding this piece of code and send it to the user with the password.
If you want to give the user of the program a try-before-buy program you can limit the usage of your program by limited period of time and after this period the program will not work.
Use the code below to limit your program for period of time.
int start()
{
string expire_date = "2006.31.06"; //<-- hard coded datetime
datetime e_d = StrToTime(expire_date);
if (CurTime() >= e_d)
{
Alert ("The trial version has been expired!");
return(0);
}
// your normal code!
return(0);
}
In this method of protection you will ask the user to give you his account number and you write the following code to prevent the program to work with another accounts:
int start()
{
int hard_accnt = 11111; //<-- type the user account here before compiling
int accnt = AccountNumber();
if (accnt != hard_accnt)
{
Alert ("You can not use this account (" + DoubleToStr(accnt,0) + ") with this program!");
return(0);
}
// your normal code!
return(0);
}
In this method of protection you will allow the user to use the program in demo mode only and prevent him to use the program in live trading. It's not strong protection because the user can host the program in another instance of MetaTrader that runs in demo mode and trade manually in the real account instance.
int start()
{
bool demo_account = IsDemo();
if (!demo_account)
{
Alert ("You can not use the program with a real account!");
return(0);
}
// your normal code!
return(0);
}
This is the method of choice, write your own C++ DLL and let the MQL4 program export it.
In C++ you can do anything, for instance you can make the DLL communicated to your server (if you have one) enabling the user to download a certificate or even update the MQL4 program.
I hope I can to write all purposes MQL4 protection DLL. I'll let you know when I write one.
Hope you enjoyed the article!
Hi folks,
I've received a lot of PMs asking me "How to determine a New Bar?" "How to trigger some code at the start of the New Bar?" That's why we are going to study today a very important piece of code that working with the new bar and the open time of this new bar (I'm saying it's important, I don't know what do you think?).
Let's start with a theoretical approach by defining what does 'Bar' mean?
Investopedia says: Bar is:
"A graphical representation of a stock's movement that usually contains the open, high, low and closing prices for a set period of time. For example, if a technical trader is working with daily data, one bar is the set of quotes for one day. In the case of one-minute data, it is the price data for one minute. Also, if the data is displayed using a candlestick chart, one bar equals one candlestick or in the case of bar charts, one bar is equal to one bar."
It's easy now to say that the new bar is the time that the trading platform finishes a bar (current bar) and starts to draw a new bar; this time is determined by the timeframe you use. If you use 30 minutes timeframe you have to except that the platform will draw a new bar approximately every 30 minutes (give figure 1 a look)
Let's write some code in replying of this important question:
bool NewBar()
{
static datetime lastbar = 0;
datetime curbar = Time[0];
if(lastbar!=curbar)
{
lastbar=curbar;
return (true);
}
else
{
return(false);
}
}
The above code is a straight forward and very simple one: It compares the open time of the bar which is returned from the function Time[0] into the variable curbar with the previous open time of the bar that saved in a static variable (lastbar).
When the platform starts a new bar the lastbar variable will have a different than value of the curbar variable and the function returns true (which means there's a new bar). otherwise the function returns false (which means there's no new bar).
You will find in the Forex forums a lot of pieces of code that tries to tell the start of a New Bar, however this is code is the must clean one and self-discloser one!
We have written the function which returns true in the case of a start of a New Bar, so, it's an easy task to write a block of code to do what we want to do in the case of a start of a new bar; here's an example:
int start()
{
.......
if (NewBar() == true)
{
Print("New Bar");
}
.......
}
You have not to forget the empty parenthesis after the NewBar keyword because it's a function which takes no prameters.
I hope you find it a useful lesson and wait your comments/questions!
Coders' Guru
I'm using other method to determine a new bar. I want to know at the open price, at the first second of a new bar that this is a new bar and I'm doing it in this way:
1) define variable newBars before init() function
2) check if the Bars variable (with is included in mql4 language) is bigger than my newBar
3) if it is bigger then it means that this is a new bar so I throw an alert and fill newBar with Bars variable.
The Bars variable as we know is the number of Bars in current chart, if we save the value of the previous tick of the number of the bars (in the newBar variable) and compare it with actual value of Bars we can get to know that the new bar was shown on the screen.
I'm attaching an mq4 script example :)
Kalenzo
Hi folks!
This is not a trading article (I repeat and repeating it "I'm not a good trade but a good programmer!")! this article is about a program that suggested by one of my clients to deal with News time.
In the News time we are not sure what's going on and where exactly the market will go. So, the idea behind our program today is placing two pending orders above and below the current market price and give the user the ability to set the distance between the pending order price and the market price.
Besides, we are going to create a script to delete the order that have been created by the first script, and only these orders will be deleted.
Let's start with the News script:
The News script asking the user to set the distance of the pending orders (how many pips below and above the current price) you want to place you pending BUYSTOP and SELLSTOP orders! (Figure 1). And you can set too Take Profit, Stop Loss and Lots values.
The script then will place the orders for you (Figure 2) and wait the market to go to its direction. Or you can use News_Delete script to delete these orders.
Let's give the code of News script a look
This is the code of the News script:
//+------------------------------------------------------------------+
//| Codersguru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Codersguru"
#property link "http://www.forex-tsd.com"
#property show_inputs
extern double distance = 15;
extern double stoploss = 15;
extern double takeprofit = 20;
extern double lots = 1;
int start()
{
int ticket;
string hcomment = "NewsScript";
ticket=OpenPendingOrder(OP_SELLSTOP,lots,distance,5,stoploss,takeprofit,hcomment);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Pending " + GetOrderType(OrderType()) + " order opened : ",OrderOpenPrice());
}
else Print("Error opening Pending " + GetOrderType(OrderType()) + " order : ",GetLastError());
ticket=OpenPendingOrder(OP_BUYSTOP,lots,distance,5,stoploss,takeprofit,hcomment);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Pending " + GetOrderType(OrderType()) + " order opened : ",OrderOpenPrice());
}
else Print("Error opening Pending " + GetOrderType(OrderType()) + " order : ",GetLastError());
return(0);
}
//+------------------------------------------------------------------+
int OpenPendingOrder(int pType=OP_BUYLIMIT,double pLots=1,double pLevel=5,int sp=0, double sl=0,double tp=0,string pComment="",int pMagic=123,datetime pExpiration=0,color pColor=Yellow)
{
switch (pType)
{
case OP_BUYLIMIT:
return(OrderSend(Symbol(),OP_BUYLIMIT,pLots,Ask-pLevel*Point,sp,(Ask-pLevel*Point)-sl*Point,(Ask-pLevel*Point)+tp*Point,pComment,pMagic,pExpiration,pColor));
break;
case OP_BUYSTOP:
return(OrderSend(Symbol(),OP_BUYSTOP,pLots,Ask+pLevel*Point,sp,(Ask+pLevel*Point)-sl*Point,(Ask+pLevel*Point)+tp*Point,pComment,pMagic,pExpiration,pColor));
break;
case OP_SELLLIMIT:
return(OrderSend(Symbol(),OP_SELLLIMIT,pLots,Bid+pLevel*Point,sp,(Bid+pLevel*Point)+sl*Point,(Bid+pLevel*Point)-tp*Point,pComment,pMagic,pExpiration,pColor));
break;
case OP_SELLSTOP:
return(OrderSend(Symbol(),OP_SELLSTOP,pLots,Bid-pLevel*Point,sp,(Bid-pLevel*Point)+sl*Point,(Bid-pLevel*Point)-tp*Point,pComment,pMagic,pExpiration,pColor));
break;
}
}
string GetOrderType( int type)
{
if(type == OP_BUY) return ("Buying position");
if(type == OP_SELL) return ("Selling position");
if(type == OP_BUYLIMIT) return ("Buy Limit pending position");
if(type == OP_BUYSTOP) return ("Buy Stop pending position");
if(type == OP_SELLLIMIT) return ("Sell Limit pending position");
if(type == OP_SELLSTOP) return ("Sell Stop pending position");
}
As you see above there are two function in this script:
The GetOrderType() returns the order type in text representation for easy printing.
The main function is OpenPendingOrder() which takes all the needed information of the pending order you want to open (the order type, how much lots, the distance, the stop loss value, the take profit value, the comment, the magic number, the expiration time and the color of the arrow).
The function place the order and returns the ticket number of the order in successes and 0 otherwise.
The second script will delete only the orders have been placed by our News script. The News_Delete identfy these orders by its type (they are SELLSTOP or BUYSTOP orders) and its comment "NewsScript".
This is the code of the NewsDelete script:
//+------------------------------------------------------------------+
//| Codersguru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Codersguru"
#property link "http://www.forex-tsd.com"
int start()
{
int cnt, ticket, total;
string hcomment = "NewsScript";
total = OrdersTotal();
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(0, SELECT_BY_POS, MODE_TRADES);
if((OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP) && OrderComment() == hcomment)
OrderDelete(OrderTicket());
}
return(0);
}
//+------------------------------------------------------------------+
You can download the both of scripts and enjoy your News trading!
For any comments drop me a mail.
Coders' Guru
Hi folks,
Today we are going to continue with the remaining of Object Functions and we have a simple MQL program to apply some of what we have learnt about drawing objects programicaly.
Let's see what left of the object functions:
Syntax:
| bool ObjectMove(string name, int point, datetime time1, double price1) |
Description:
The ObjectMove function changes the specified coordinate of the object to new x and y coordinate.
Any object has up to 3 coordinates and they are indexed 0, 1 and 2. You specify the coordinate you want to change with its index (point parameter) then set new x and y values for the new coordinate (time1 and time2).
The function returns true if it successfully had changed the coordinate and false otherwise.
Note: If you have a 2 or 3 coordinates object and want to change the 2 or 3 coordinates, you have to use ObjectMove function 2 or 3 times for every coordinate.
Parameters:
string name:
The string name of the object you want to change its coordinate.
int point:
Coordinate index (0, 1, 2) you want to change it.
datetime time1:
The first vertical coordinate of the object. This parameter is a datetime type (because the vertical coordinate of the chart is the time coordinate).
double price1:
The first horizontal coordinate of the object. This parameter is a double type (because the horizontal coordinate of the chart is the price coordinate).
Note: You have to note which currency pair you are going to draw on its chart because the prices ranges differs from currency to currency.
Example:
| ObjectMove("MyTrend", 1, D'2005.02.25 12:30', 1.2345); |
Syntax:
| string ObjectName(int index) |
Description:
The ObjectName function returns the object name for the given index from the object list. To check the error use GetLastError() function.
Parameters:
int index:
The index of the object you want to get its name.
Note: The index must be equal to 0 or greater, and be less than the total of the objects count returned by ObjectsTotal() function.
Example:
| int obj_total=ObjectsTotal(); |
Hi folks,
"OK, now I have a brain pain! I just spent the morning scanning thru the MQL4 and MetaTrader help file pages to try and track down if I missed anything."
Could you please answer me only one question:
When I open a Buy order using OrderSend function, Should I use the Ask or the Bid price? What about the Stop loss is it going below or above the Ask or the Bid price? What about the Take profit?
When I open a Sell order using OrderSend function, Should I use the Ask or the Bid price? What about the Stop loss is it going below or above the Ask or the Bid price? What about the Take profit?
What about BUYLIMIT, BUYSTOP, SELLLIMIT and SELLSTOP orders?
Is that the only one question? Well here’s the answer!
OP_BUY
Ask
Ask-StopLoss
Ask+TakeProfit
You Buy at the current Ask price of the currency!
You set the StopLoss Below (-) the Ask price!
You set the TakeProfit Above (+) the Ask price!
Example:
OrderSend(Symbol(),OP_BUY,Lots,Ask,slippage,
Ask-StopLoss*Point,Ask+TakeProfit*Point,”comment”,0,0,Green);
Bid
Bid+StopLoss
Bid-TakeProfit
You Sell at the current Bid price of the currency!
You set the StopLoss Above (+) the Bid price!
You set the TakeProfit Below (-) the Bid price!
Example:
OrderSend(Symbol(),OP_SELL,Lots,Bid,slippage,
Bid+StopLoss*Point,Bid-TakeProfit*Point, ”comment”,0,0,Green);
Ask-Level
Ask-Level-StopLoss
Ask-Level +TakeProfit
You Buy at future price level Below the current Ask price of the currency!
You set the StopLoss Below (-) the Ask - the level price!
You set the TakeProfit Above (+) the Ask - the level price!
Example:
OrderSend(Symbol(),OP_BUYLIMIT,Lots,Ask-Level*Point,slippage,
(Ask-Level*Point)-StopLoss*Point,
( Ask-Level*Point)+TakeProfit*Point,”comment”,0,0,Green);
Ask+Level
Ask+Level -StopLoss
Ask+Level +TakeProfit
You Buy at future price level Above the current Ask price of the currency!
You set the StopLoss Below (-) the Ask + the level price!
You set the TakeProfit Above (+) the Ask + the level price!
Example:
OrderSend(Symbol(),OP_BUYSTOP,Lots,Ask+Level*Point,slippage,
(Ask+Level*Point)-StopLoss*Point,
( Ask+Level*Point)+TakeProfit*Point,”comment”,0,0,Green);
Bid+Level
Bid +Level +StopLoss
Bid+Level –TakeProfit
You Sell at future price level Above the current Bid price of the currency!
You set the StopLoss Above (+) the Bid + the level price!
You set the TakeProfit Below (-) the Bid + the level price!
Example:
OrderSend(Symbol(),OP_SELLLIMIT,Lots,Bid+Level*Point,slippage,
(Bid+Level*Point)+StopLoss*Point,
(Bid +Level*Point)-TakeProfit*Point,”comment”,0,0,Green);
Bid-Level
Bid -Level +StopLoss
Bid-Level-TakeProfit
You Sell at future price level Below the current Bid price of the currency!
You set the StopLoss Above (+) the Bid + the level price!
You set the TakeProfit Below (-) the Bid - the level price!
Example:
OrderSend(Symbol(),OP_SELLSTOP,Lots,Bid-Level*Point,slippage,
(Bid-Level*Point)+StopLoss*Point,
(Bid -Level*Point)-TakeProfit*Point,”comment”,0,0,Green);
Hi folks,
Today we are going to talk about a very important topic, the Predefined variables.
I still considering them functions (I'm going to tell you why later) but I'll use Predefined variables as MetaQuotes has mentioned them.
The Predefined variables are set of the most important variables which MetaTrader set continuously for every loaded chart. They are price related variables that reflect the current price data the chart had got.
These is the list of the predefined variables:
Ask, Bid, Bars, Close, Open, High, Low, Time, Digits, Point and Volume
Ask, Bid, Bars, Close, Open, High, Low, Time, Digits, Point and Volume are functions Although MetaQuotes called them predefined variables.
Variable means "a space in memory and data type you specify", while function means "do something and return some value". For example Bars collects and returns the number of the bars in chart. So, is it a variable?
Another example will proof for you that they are not variables:
If you type and compile this line of code:
Bars=1;
You will get this error:
'Bars' - unexpected token
That’s because they are not variables hence you can’t assign a value to them.
Anyway, it doesn't matter what should you call them, the really matter is how to use them!
Let's study the Predefined variables set:
Syntax:
| double Ask |
Description:
The Ask function return the last known Ask price (the sell price) for the current symbol. To be sure it reflects the actual market price you have to use the RefreshRates() function.
Note: To get the Ask price for a
Parameters:
Example:
|
|
Hi folks!
I'm writing this article today because I've go a lot of requests asking me this mystery question "How do I programmatically refresh my charts?"
Every time I answer this question like that: "You can not use normal mql4 to fulfill this task, the only way is to use a keystuffer program, please give my Send Keyboard keys to MetaTrader! article a look! it's the only solution I guess!"
Today we are going to write an indicator that refreshes the chart every x seconds. Let's go!
To refresh the chart there's only one manual method! you have to go to the Charts menu (in main menu - figure 1 - or the context menu - figure 2) and click Refresh command!
We need the code to do that for us! Our code will simulate the key storks of opening the Chart menu by click CTRL+C then click R for the Refresh command. Let's see how could we convert the normal MACD indicator to every 60 second self-refreshing indicator?

Figure 1
Figure 2
//+------------------------------------------------------------------+
//| Custom MACD.mq4 |
//| Copyright © 2004, MetaQuotes Software Corp. |
//| http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2004, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net/"
#import "user32.dll"
void keybd_event(int bVk,int bScan,int dwFlags,int dwExtraInfo);
#import
#define KEYEVENTF_EXTENDEDKEY 0x0001
#define KEYEVENTF_KEYUP 0x0002
#define VK_0 48
#define VK_1 49
#define VK_2 50
#define VK_3 51
#define VK_4 52
#define VK_5 53
#define VK_6 54
#define VK_7 55
#define VK_8 56
#define VK_9 57
#define VK_A 65
#define VK_B 66
#define VK_C 67
#define VK_D 68
#define VK_E 69
#define VK_F 70
#define VK_G 71
#define VK_H 72
#define VK_I 73
#define VK_J 74
#define VK_K 75
#define VK_L 76
#define VK_M 77
#define VK_N 78
#define VK_O 79
#define VK_P 80
#define VK_Q 81
#define VK_R 82
#define VK_S 83
#define VK_T 84
#define VK_U 85
#define VK_V 86
#define VK_W 87
#define VK_X 88
#define VK_Y 89
#define VK_Z 90
#define VK_LBUTTON 1 //Left mouse button
#define VK_RBUTTON 2 //Right mouse button
#define VK_CANCEL 3 //Control-break processing
#define VK_MBUTTON 4 //Middle mouse button (three-button mouse)
#define VK_BACK 8 //BACKSPACE key
#define VK_TAB 9 //TAB key
#define VK_CLEAR 12 //CLEAR key
#define VK_RETURN 13 //ENTER key
#define VK_SHIFT 16 //SHIFT key
#define VK_CONTROL 17 //CTRL key
#define VK_MENU 18 //ALT key
#define VK_PAUSE 19 //PAUSE key
#define VK_CAPITAL 20 //CAPS LOCK key
#define VK_ESCAPE 27 //ESC key
#define VK_SPACE 32 //SPACEBAR
#define VK_PRIOR 33 //PAGE UP key
#define VK_NEXT 34 //PAGE DOWN key
#define VK_END 35 //END key
#define VK_HOME 36 //HOME key
#define VK_LEFT 37 //LEFT ARROW key
#define VK_UP 38 //UP ARROW key
#define VK_RIGHT 39 //RIGHT ARROW key
#define VK_DOWN 40 //DOWN ARROW key
#define VK_PRINT 42 //PRINT key
#define VK_SNAPSHOT 44 //PRINT SCREEN key
#define VK_INSERT 45 //INS key
#define VK_DELETE 46 //DEL key
#define VK_HELP 47 //HELP key
#define VK_LWIN 91 //Left Windows key (Microsoft® Natural® keyboard)
#define VK_RWIN 92 //Right Windows key (Natural keyboard)
#define VK_APPS 93 //Applications key (Natural keyboard)
#define VK_SLEEP 95 //Computer Sleep key
#define VK_NUMPAD0 96 //Numeric keypad 0 key
#define VK_NUMPAD1 97 //Numeric keypad 1 key
#define VK_NUMPAD2 98 //Numeric keypad 2 key
#define VK_NUMPAD3 99 //Numeric keypad 3 key
#define VK_NUMPAD4 100 //Numeric keypad 4 key
#define VK_NUMPAD5 101 //Numeric keypad 5 key
#define VK_NUMPAD6 102 //Numeric keypad 6 key
#define VK_NUMPAD7 103 //Numeric keypad 7 key
#define VK_NUMPAD8 104 //Numeric keypad 8 key
#define VK_NUMPAD9 105 //Numeric keypad 9 key
#define VK_MULTIPLY 106 //Multiply key
#define VK_ADD 107 //Add key
#define VK_SEPARATOR 108 //Separator key
#define VK_SUBTRACT 109 //Subtract key
#define VK_DECIMAL 110 //Decimal key
#define VK_DIVIDE 111 //Divide key
#define VK_F1 112 //F1 key
#define VK_F2 113 //F2 key
#define VK_F3 114 //F3 key
#define VK_F4 115 //F4 key
#define VK_F5 116 //F5 key
#define VK_F6 117 //F6 key
#define VK_F7 118 //F7 key
#define VK_F8 119 //F8 key
#define VK_F9 120 //F9 key
#define VK_F10 121 //F10 key
#define VK_F11 122 //F11 key
#define VK_F12 123 //F12 key
#define VK_F13 124 //F13 key
#define VK_NUMLOCK 144 //NUM LOCK key
#define VK_SCROLL 145 //SCROLL LOCK key
#define VK_LSHIFT 160 //Left SHIFT key
#define VK_RSHIFT 161 //Right SHIFT key
#define VK_LCONTROL 162 //Left CONTROL key
#define VK_RCONTROL 163 //Right CONTROL key
#define VK_LMENU 164 //Left MENU key
#define VK_RMENU 165 //Right MENU key
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Silver
#property indicator_color2 Red
//---- indicator parameters
extern int FastEMA=12;
extern int SlowEMA=26;
extern int SignalSMA=9;
extern int SecondsToRefresh = 60;
//---- indicator buffers
double ind_buffer1[];
double ind_buffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- drawing settings
SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,3);
SetIndexDrawBegin(1,SignalSMA);
IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS)+1);
//---- indicator buffers mapping
if(!SetIndexBuffer(0,ind_buffer1) && !SetIndexBuffer(1,ind_buffer2))
Print("cannot set indicator buffers!");
//---- name for DataWindow and indicator subwindow label
IndicatorShortName("MACD("+FastEMA+","+SlowEMA+","+SignalSMA+")");
SetIndexLabel(0,"MACD");
SetIndexLabel(1,"Signal");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
//---- check for possible errors
if(counted_bars<0) return(-1);
//---- last counted bar will be recounted
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
for(int i=0; i<limit; i++)
ind_buffer1[i]=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)-iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
for(i=0; i<limit; i++)
ind_buffer2[i]=iMAOnArray(ind_buffer1,Bars,SignalSMA,0,MODE_SMA,i);
//---- done
Refresh(SecondsToRefresh);
return(0);
}
void Refresh(int seconds = 60)
{
datetime cur = CurTime();
static datetime last = 0;
if (last == 0) {last = cur;}
if (cur > last + seconds)
{
last = cur;
SendKey (VK_MENU);
SendKey (VK_C);
ReleaseKey(VK_MENU);
ReleaseKey(VK_C);
SendKey (VK_R);
ReleaseKey(VK_R);
}
}
void SendKey(int key,bool release = false)
{
keybd_event (key, 0, 0, 0);
if(release)
keybd_event (key, 0, KEYEVENTF_KEYUP, 0);
}
void ReleaseKey(int key)
{
keybd_event (key, 0, KEYEVENTF_KEYUP, 0);
}
The first thing we have added is the code to call the keybd_event windows function by importing it from the user32.dll. Then all the #define are from the constants used with the keybd_event function.
The real works starts with the varaible SecondsToRefresh which we set it to the x seconds we want the indicator to use it to refresh the chart (i.e. refresh the chart every 60 seconds).
The function which you use to refresh the chart is Refresh() function which take x seconds to refresh the chart. This function compares the current time with the last saved time (time algorism) to work every x seconds.
Every x seconds the function will send the keys ALT+C (To open the Charts menu) then sends R key to select Refresh command from the menu!
This program will sends the keys ALT+C and R to any activated window! So, you have to be sure that the activated window is MetaTrader window and the chart you want to refresh!
I know this is odd but it's the only way to Refresh the chart programmatically!
Hope you find it a helpful article/code/crack!
How can i get the close, low, high price of current bar? When I use Close[0], iClose(Symbol(), 0, 0) to get close price of current bar, thess two values are always the same as Open[0](when running tester tool of MetaTrader, right now I'm running MIG Trade Station, demo account) ? The same for low and high prices? Please tell me how can i figure out it. Many thanks for reading!
---------- REPLY -----------------
Hi there!
Close[0] returns the close price of the current bar (The same is true for the High[0] return the high price of the current bar, Low[0] returns the low price of the current bar and Open[0] returns the open price of the current bar)
iClose function is very like Close function but it can return the close price for another symbol and timframe. If you used it like this:
iClose(NULL,0,0)
it will equal to Close[0]. (The same is true for the iHigh, iLow and iOpen functions).
Coders Guru
Hi folks!
A lot of us are small fishes (maybe tiny fishes indeed) who trying to get any pips and run!
Scalping the market with the minimum value of MetaTrader Trail Stop - 15 Pips - make it hard to get good profit and force you as scalper to keep your eyes on the screen all the times to catch the tiny pips you want.
No problem with the minimum value of MetaTrader Trail Stop any more with this EA
The EA has few parameter although it seems to have a lot of parameters:
Enabled: Set this parameter to false to turn off the EA - Default value is true.
Trail_Value: The value you want to trail your order to, it can be any value greater than 0 but if you will use values greater than 15 why do not use MetaTrader trail stop?
Trade_Identifier: To be sure that the EA working only with a specific order you have to select only this order to be trailed with the EA.
There are 4 value you can for Trade_Identifier option:
0 : Setting Trade_Identifier to 0 means you will use the Ticket Number of the order (Figure 1) - The next step is setting the value of the variable Trade_Ticket to the Ticket number of the order you want to trail.
This option is the safer one hence it's the default value of Trade_Identifier.
1 : Setting Trade_Identifier to 1 means you will use the Magic Number of the order - You have to note that only the orders that had been opened by an EA has Magic Number.
The next step is setting the value of the variable Trade_Magic to the Magic number of the order you want to trail.
2 : Setting Trade_Identifier to 2 means you will use the Comment of the order.
The next step is setting the value of the variable Trade_Comment to the Comment of the order you want to trail.
3 : Setting Trade_Identifier to 3 means you will use the Symbol (Currency name, ex: EURUSD) of the order.
The next step is setting the value of the variable Trade_Symbol to the Symbol of the order you want to trail.
Caution: This tool and everything I've wrote as code or articles is for educational purpose only and you have to use it at your own full risk!
Hi folks,
Today we are going to study in details a very important MQL4 function; the ScreenShot() function and in the coming article we are going to create a useful expert advisor that ......
Let's start from the beginning and know what screen shots means in MetaTrader?
In MetaTrader it's easy to save any chart you want with all the indicators plotted to it.
Just right-click on the chart you want to save and from the context menu (Figure 1) choose "Save As Picture" option.

This will bring Save As Picture dialog (Figure 2) to choose from it one of three options:
1- Active work space: Choosing this option will save a screen shot with all the MetaTrader program (Toolbar, Menus, Charts and windows). It's very like pressing ALT + Print Screen in Microsoft Window.
2- Active chart (as is): This option will save the chart as it appears in front of you with the same size.
3- Active chart: This option will enable you to set the width and height of the chart you want to save. If you supplied big width, MetaTrader will go through the history of the chart and save it in the picture.
When you choose the option you want and click ok you will get a dialog asking you about the name of the image, where to save it and what the type of the image you want to save (Figure 3). You cab choose one of two formats for the save image: GIF format or JPEG format.
Saving screen shots in MQL4 is a bit harder than the normal MetaTrader method but the best thing it's automated and very faster than the normal method.
To save screen shots in MQL4 you have to know the only function that enables you do that; the ScreenShot function.
Syntax:
| bool ScreenShot( string filename, int size_x, int size_y, int start_bar=-1, int chart_scale=-1, int chart_mode=-1) |
Description:
The ScreenShot function is the one responsible of saving the current chart, you pass to the filename of the saved image with the settings parameters which we will know later.
You have to know two important things about the ScreenShot function that differentiate it than the normal MetaTrader screen shot:
1- Limited saving folder:
While in the normal MetaTrader ScreenShot saving you can choose the folder you want to save the image, the ScreenShot function only uses one of two folders to save the images:
A- terminal_dir\experts\files and its sub folders in the case of forward mode.
B- terminal_dir\tester\files and its sub folders in the case of testing mode.
2- Limited image format:
The normal MetaTrader ScreenShot image can be in GIF or JPG format, while the ScreenShot function will save the image in GIF format only.
Parameters:
string filename:
The file name of the image you want to save, don't forget the .gif extension (see the example)
Note: You can create sub folder by adding this folder before the file name of the image and separating them by "/" sign (see the example).
int size_x:
The width of the image in pixels.
int size_y:
The height of the image in pixels.
int start_bar:
The first bar you want to include in your image, 0 means the first visible bar on the chart.
If this value was negative or omitted the image will start from the end of the chart.
int chart_scale:
The scale (zoom) of the chart, this value range from 0 to 5.
If this parameter omitted or was negative the function will use the current scale of the chart.
int chart_mode:
The displaying mode of the chart you want to apply to your saved image; 0 means Bars Chart, 1 means Candle Chart and 2 means Line Chart.
If this parameter omitted or was negative the function will use the current chart displaying mode.
Example:
| int lasterror=0; |
I hope you enjoyed this lesson and promise this will not be the last lesson about the ScreenShot function. In the coming lesson we are going to write a useful piece of code that puts ScreenShot function to use.
Coders Guru
Hi folks,
In a previous lesson we have studied the ScreenShot function and I promised to show a useful piece of code that puts ScreenShot function to use.
I was writing an Expert Advisor for one of my clients, the program didn't work as agreed and both of us (me and my client) couldn't catch the error.
The entry point of the Expert Advisor wasn't in accordance with the entry conditions the client demanded and we couldn't catch the error because the color changing of the used indicators and when we view the history chart we find everything is right.
I suggested to print the chart every time the Expert Advisor open a new trade but it was bad idea! then what MQL is for?
That's why I added this price of code to get a screen shot of the chart every time the Expert Advisor enter a trade and save it to a unique folder with auto increment number added to the image file name.
int start()
{
.....
TakeScreenShot("OPEN_BUY");
.....
}
void TakeScreenShot(string type)
{
int count = 1;
if(!GlobalVariableCheck("ssc"))
{
GlobalVariableSet("ssc",1);
count = 1;
}
else
{
count = GlobalVariableGet("ssc") + 1;
GlobalVariableSet("ssc",count);
}
string filename = "MyEA\\" + "MyEA_" + Symbol() + "_" + type + "_" + DoubleToStr(count,0) + ".gif";
ScreenShot(filename,640,480);
}
The piece of code above have two parts; The TakeScreenShot Function and a line to call it. Let's study the function then we are going to know how to use it!
The TakeScreenShot function simply do the following:
1- It remembers the count of previous screen shots have been taken, that's by using Global Variable! Why? to name every new image file with a new name based on the count of images.
2- It takes a screen shot of the current chart whenever you call it.
3- It saves the image file in a folder called "MyEA", the function add to the name the name of the symbol (currency pair) and the type of trade - The type of the trade is a string parameter of the function you supply it and the function will add it to image name for you to identify the image.
Calling the TakeScreenShot function is like calling any custom function you create/use. I mean by the above question when you have to call it.
It depends on the screenshot you want to take. In my above mentioned program that I created to my client I used it every time The program enter a new trade and every time the program close a trade. You can use it too every time the program modify a trade. Don't forget to set the type parameter to distinguish between the images the program take!
I hope you find it a useful article and a useful code!
Coders' Guru
Hi folks,
Our set of functions today are the String Functions. They are the MQL4 functions we need to handle the string variables!
Let's give the string data type an overview first!
The string data type is an array of characters enclosed in double quote (").
This array of characters is an array which holds one character after another, starting at index 0. After the last character of data, a NULL character is placed in the next array location. It does not matter if there are unused array locations after that.
A NULL character is a special character (represented by the ASCII code 0) used to mark the end of this type of string.
See figure 1 for a simple representation of the string constant “hello” in the characters array.
MQL4 limits the size of the string variable to 255 characters and any character above 255 characters will generate this error: (too long string (255 characters maximum)).
We use the keyword string to create a string variable.
For example:
| string str1 = "Hello world!, with you coders guru”; |
Now let's study the MQL4 functions concerned about the Strings:
Syntax:
| string StringConcatenate( ... ) |
Description:
The StringConcatenate function take the set of parameters passed to it and glue them together and returns them as a string.
Note: (...) means that you can pass to this function any kind of data type and any number of parameters separated by comma.
You can pass to this function any kind of data type except the arrays and any number of parameters separated by comma very like the Print(), Alert() and Comment() functions.
If you want to pass a double data type to this function the number of digits will be used are 4 digits if you want to change this number you have to use the function DoubleToStr().
The bool, color and datatime passed to function will be printed in their numeric presentation. , if you want to print them in string format use the string name of the bool or the color value and for the datetime use the function TimeToStr().
Note: You can use the + operator to add string to another string for example "coders" + "guru" will produce "codersguru", however MetaTrader saying that StringConcatenate() function works faster gluing strings together.
Parameters:
This function takes any number of parameters:
...
Any values, separated by commas.
Example:
| string text; |
Syntax:
| int StringFind( string text, string matched_text, int start=0) |
Description:
The StringFind function search for substring (part of the given string for example "gur" is substring from the string "codersguru") in a given string, if the function find the substring it returns its position, if the function didn't find the substring it returns -1.
Parameters:
This function takes two parameters:
string text
The string you want to search in it for the substring.
string matched_text
The substring you want to find it in the string.
int start=0
The index of the starting position for the search. the first character in the string has the index 0 then 1 then 2 etc.
The default value is 0 which means to search from the start of the string.
Example:
| string text="The quick brown dog jumps over the lazy fox"; |
Syntax:
| int StringGetChar( string text, int pos) |
Description:
The StringGetChar function returns the character in a given position from a given string. it return it as character code (the ASCII code of the character).
Parameters:
This function takes two parameters:
string text
The string you want to get the character from.
int pos
The position of the character you want to get, don't forget that the string array starts with 0.
Example:
| int char_code=StringGetChar("abcdefgh", 3); |
Syntax:
| int StringLen( string text) |
Description:
The StringLen function returns how many character (the length) of the given string.
Parameters:
This function takes only one parameter:
string text
The string you want to get its length..
Example:
| string str="some text"; |
Syntax:
| string StringSetChar( string text, int pos, int value) |
Description:
The StringSetChar function change one character of the given string in a given position to another character and returns the new string.
Parameters:
This function takes three parameters:
string text
The string you want change a character in it.
int pos
The position of the character you want to change.
int value
The new character you want to set it.
Example:
| string str="abcdefgh"; |
Syntax:
| string StringSubstr( string text, int start, int count=EMPTY) |
Description:
The StringSubstr function extracts the string from given position to a given count (ex: "codersguru" the position is 3 and the count is 2 then the extracted string is "de"). The function returns the extracted string if any or it returns EMPTY string.
Parameters:
This function takes three parameters:
string text
The string you want to extract from it.
int start
Where to start your extracting.
int count=EMPTY
The count of character you want to extract. The default value is EMPTY.
Example:
| string text="The quick brown dog jumps over the lazy fox"; |
Hi folks,
I've got a lot of messages asking me "How to deal with currency pairs which are different than the current chart currency (The chart that hosts the expert advisor)? For example, how to make an expert advisor that can open Buy position of GBPUSD or USDCHF while the expert advisor is hosted on EURUSD chart?" Good question, Huh?
To reply these related questions we have to start with studding the Timeseries Access functions.
The Timeseries Access functions are a set of functions that enables us to access the price date of any chart (currency and timeframe) regardless of the chart that hosts the expert advisor.
Let's give these functions a brief look:
Syntax:
| int iBars( string symbol, int timeframe) |
Description:
The iBars function returns the number of Bars of the specified chart, you specify the chart by the symbol name and the timeframe.
Note: If the chart of the symbol and timeframe you are trying to get its price data is not opened, MetaTrader will try to connect to the server to retrieve the request price data. In this case and with the all of the Timeseries access functions you have to check the the last was the error # 4066 - ERR_HISTORY_WILL_UPDATED (which means the requested data is under updating) to be sure that the price data is up-to-date. And retry your request for the price data.
Note: If you want to get the number of bars of the current chart (symbol and timeframe) use Bars function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
Note: You can use the integer representation of the timeframe (period in minutes) or you can use the timeframes constants:
| PERIOD_M1 | 1 | 1 minute. |
| PERIOD_M5 | 5 | 5 minutes. |
| PERIOD_M15 | 15 | 15 minutes. |
| PERIOD_M30 | 30 | 30 minutes. |
| PERIOD_H1 | 60 | 1 hour. |
| PERIOD_H4 | 240 | 4 hour. |
| PERIOD_D1 | 1440 | Daily. |
| PERIOD_W1 | 10080 | Weekly. |
| PERIOD_MN1 | 43200 | Monthly. |
| 0 (zero) | 0 | Timeframe used on the chart. |
Example:
| Print("Bar count on the 'EUROUSD' symbol with PERIOD_H1 is",iBars("EUROUSD",PERIOD_H1)); |
Syntax:
| int iBarShift( string symbol, int timeframe, datetime time, bool exact=false) |
Description:
The iBarShift function takes the open time of the bar for a specified symbol and timeframe and searches for this bar and returns it if found otherwise it returns -1.
If you want the iBarShift function to return the nearest bar to the given open time set the exact parameter to true.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
datetime time:
The open time of the bar you want to search for
bool exact:
The search mode, use exact =false (default) and and the function will return -1 if the open time not found. And use exact =true and the function will return the nearest bar to the given open time.
Example:
| datetime some_time=D'2004.03.21 12:00'; |
Syntax:
| double iClose( string symbol, int timeframe, int shift) |
Description:
The iClose function returns the Close price for the given bar (the shift parameter is the bar number) of the given symbol and timeframe. The function returns 0 if the history data not loaded.
Note: It's very important (and always error's source) to know that the current bar is 0 and the previous bar is 1 etc.
Note: If you want to get the Close price (of a bar) of the current chart (symbol and timeframe) use Close[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its Close price.
Example:
| Print("Current Close price for USDCHF H1: ",iClose("USDCHF",PERIOD_H1,i)); |
Syntax:
| double iHigh( string symbol, int timeframe, int shift) |
Description:
The iHigh function returns the High price for the given bar (the shift parameter is the bar number) of the given symbol and timeframe. The function returns 0 if the history data not loaded.
Note: If you want to get the High price (of a bar) of the current chart (symbol and timeframe) use High[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its High price.
Example:
| Print("Current High price for USDCHF H1: ",iHigh("USDCHF",PERIOD_H1,i)); |
Syntax:
| double iLow( string symbol, int timeframe, int shift) |
Description:
The iLow function returns the Low price for the given bar (the shift parameter is the bar number) of the given symbol and timeframe. The function returns 0 if the history data not loaded.
Note: If you want to get the Low price (of a bar) of the current chart (symbol and timeframe) use Low[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its Low price.
Example:
| Print("Current Low price for USDCHF H1: ",iLow("USDCHF",PERIOD_H1,i)); |
Syntax:
| double iOpen( string symbol, int timeframe, int shift) |
Description:
The iOpen function returns the Open price for the given bar (the shift parameter is the bar number) of the given symbol and timeframe. The function returns 0 if the history data not loaded.
Note: If you want to get the Open price (of a bar) of the current chart (symbol and timeframe) use Open[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its Open price.
Example:
| Print("Current Open price for USDCHF H1: ",iOpen("USDCHF",PERIOD_H1,i)); |
Syntax:
| datetime iTime( string symbol, int timeframe, int shift) |
Description:
The iTime function returns the Open Time of the given bar (the shift parameter is the bar number) of the given symbol and timeframe.
Note: If you want to get the bar Open Time (of a bar) of the current chart (symbol and timeframe) use Time[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its Open Time.
Example:
| Print("The Open Time of the current bar for USDCHF H1: ",iTime("USDCHF",PERIOD_H1,i)); |
Syntax:
| double iVolume( string symbol, int timeframe, int shift) |
Description:
The iVolume function returns the Tick Volume value of the given bar (the shift parameter is the bar number) of the given symbol and timeframe.
Note: Volume is simply the number of shares (or contracts) traded during a specified time frame (e.g., hour, day, week, month, etc).
Note: In MQL if you want to check if the tick is the first tick of the new bar you can check Volume[0] it will be 0 if it's the first tickof the new bar. Example:
| //---- go trading only for first tiks of new bar |
Note: If you want to get the Tick Volume value (of a bar) of the current chart (symbol and timeframe) use Volume[int shift] function.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int shift:
The index of the bar you want to get its Tick Volume value.
Example:
| Print("Current Tick Volume for USDCHF H1: ",iVolume("USDCHF",PERIOD_H1,i)); |
Syntax:
| int Highest( string symbol, int timeframe, int type, int count=WHOLE_ARRAY, int start=0) |
Description:
The Highest function calculate the Highest value of the specified type (Close price, Open price, High price etc) for a specified bars of the given symbol and timeframe.
You use the type parameter to determine the type of the values to be calculated and the parameters count and start determine the bars to be calculated.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int type:
The type of values (Series array) to be calculated, it can be one of these types:
| Constant Value Description |
int count:
How many bars you want to calculate its Highest value, use this parameter with start parameter to determine the range of bars to be calculated. The default value is WHOLE_ARRAY which means all the bars (values in the series array).
int start:
The bar to start the calculation from, the default value is 0 which means to start from the current bar.
Example:
| double val; |
Syntax:
| int Lowest( string symbol, int timeframe, int type, int count=WHOLE_ARRAY, int start=0) |
Description:
The Lowest function calculate the Lowest value of the specified type (Close price, Open price, High price etc) for a specified bars of the given symbol and timeframe.
You use the type parameter to determine the type of the values to be calculated and the parameters count and start determine the bars to be calculated.
Parameters:
string symbol:
The symbol (currency pair) of the chart you want to get its bars number.
Use NULL if you want to use current symbol.
int timeframe:
The timeframe (in integers, ex: 1,5,30,60 etc) of the chart you want to get its bars number.
Use 0 if you want to use current timeframe.
int type:
The type of values (Series array) to be calculated.
int count:
How many bars you want to calculate its Highest value, use this parameter with start parameter to determine the range of bars to be calculated. The default value is WHOLE_ARRAY which means all the bars (values in the series array).
int start:
The bar to start the calculation from, the default value is 0 which means to start from the current bar.
Example:
| double val=Low[Lowest(NULL,0,MODE_LOW,10,10)]; |
Now we have the tools to access the price data of the other charts, the question is: Is this enough to write our expert advisor that deals with other currency pairs? No!
In the coming lesson we are going to know the most important function needed to write this kind of expert advisors; the MarketInfo() function.
I hope you find it a useful lesson!
Hi folks,
We are going to study today a set of functions that responsible of handling the chart windows. These functions are infrequently used (expect WindowsTotal(), WindowFind() and ScreenShot functions) but as a MQL4 programmer you have to know them.
These are the Windows functions set:
Syntax:
| int BarsPerWindow( ) |
Description:
The BarsPerWindow function returns the number of bars visible for the user on the chart.
Note: Resizing the chart window or changing the chart period changes this number.
Parameters:
The function doesn't take any parameters.
Example:
| // work with visible bars. caption=FirstVisibleBar() Function returns index of the first visible bar. // work with visible bars. |
Syntax:
| double PriceOnDropped( ) |
Description:
The PriceOnDropped function returns the price of the currency of the chart from the point you dragged and release the expert advisor or the script at. When you click the expert advisor or the script in the navigator window and hold the left button mouse then drag it and release the left mouse buttons at any point on the chart; the PriceOnDropped returns the price at this point.
This function works only with the expert advisors and script and doesn't work with the custom indicators.
Parameters:
The function doesn't take any parameters.
Example:
| double drop_price=PriceOnDropped(); |
Syntax:
| datetime TimeOnDropped( ) |
Description:
The TimeOnDropped function returns the time of on the chart where you dragged and release the expert advisor or the script at. This function too works only with the expert advisors and script and doesn't work with the custom indicators.
Parameters:
The function doesn't take any parameters.
Example:
| double drop_price=PriceOnDropped(); |
Syntax:
| bool ScreenShot( string filename, int size_x, int size_y, int start_bar=-1, int chart_scale=-1, int chart_mode=-1) |
Description:
The ScreenShot function save a screen shot of the current chart. It saves the screen shot as GIF file in one of two folder:
If you used the function in the live mode it'll save the screen shot in terminal_dir\experts\files and its subdirectories. If you used the function in the testing mode it'll save the screen shot in terminal_dir\tester\files and its subdirectories.
The function returns True if it successfully saved the screen shot and false if it failed.
Parameters:
The function takes 6 parameters.
string filename:
The file name that the function will save the screen shot to. You can combine the file name with a subdirectory to tell the function where to save the file.
int size_x:
The width of the screen shot.
int size_y:
The height of the screen shot.
int start_bar=-1:
The index of the first bar you want to include in your screen shot. 0 means the first visible bar on the chart. The default vaule is -1 which means the end-of-chart screen shot will be taken.
int chart_scale=-1:
The scale (Zoom In and Zoom Out) of the chart screen shot that will be taken. It ranges from 0 to 5. The default value is -1 which means the function will use the current scale of the chart.
int chart_mode=-1
The mode of the chart screen shot that will be taken. it can be one of these values:
CHART_BAR (0)
CHART_CANDLE (1)
CHART_LINE (2)
The default value is -1 which means the function will use the chart mode.
Example:
| int lasterror=0; |
Syntax:
| int WindowFind(string name) |
Description:
The WindowFind function searches the chart sub windows for the indicator short name passed to it and returns the window index if found and -1 otherwise!
Note: The indicators name can be set using the function IndicatorShortName().
Note: If the indicator search for his name in the init() function using WindowFind() function it always returns -1.
Parameters:
The function takes only one parameter.
string name:
The name of the indicator short name you want to search for and return its window index.
Example:
| int win_idx=WindowFind("MACD(12,26,9)"); |
Syntax:
| int WindowHandle(string symbol, int timeframe) |
Description:
The WindowHandle function searches all the opened chart for the symbol (currency pairs) and timeframe passed to it and returns the window handle of the chart window if found and -1 otherwise.
Parameters:
The function takes two parameters:
string symbol:
The symbol name you want to search for and return its window index.
int timeframe:
The timeframe you want to search for and return its window index.
Note: The chart window you are searching must have the symbol name and the timeframe to return the window handle. if the one of the two conditions is found and other not found the return value is -1.
Example:
| int win_handle=WindowHandle("EURUSD",PERIOD_H1); |
Syntax:
| bool WindowIsVisible(int index) |
Description:
The WindowIsVisible function returns true if the chart sub-window index passed to it is visible to the user and false otherwise.
Parameters:
The function takes only one parameter:
int index:
The index of the chart sub-window you want to check its visibility.
Example:
| int maywin=WindowFind("MyMACD"); |
Syntax:
| int WindowOnDropped() |
Description:
The WindowOnDropped function returns the index of the window you dragged and released the expert advisor, indicator or the script on.
Parameters:
The function doesn't take any parameters.
Example:
| if(WindowOnDropped()!=0) |
Syntax:
| int WindowsTotal() |
Description:
The WindowsTotal function returns the count of windows (sub-windows and main window) on the chart.
Parameters:
The function doesn't take any parameters.
Example:
| Print("Windows count = ", WindowsTotal()); |
Syntax:
| int WindowXOnDropped() |
Description:
The WindowXOnDropped function returns the x-axis coordinate in pixels of the point you dragged and released the expert advisor, indicator or the script on.
Parameters:
The function doesn't take any parameters.
Example:
| Print("Expert dropped point x=",WindowXOnDropped()," y=",WindowYOnDropped()); |
Syntax:
| int WindowYOnDropped() |
Description:
The WindowYOnDropped function returns the Y-axis coordinate in pixels of the point you dragged and released the expert advisor, indicator or the script on.
Parameters:
The function doesn't take any parameters.
Example:
| Print("Expert dropped point x=",WindowXOnDropped()," y=",WindowYOnDropped()); |
It was a long path for you to reach this lesson, Congratulations!
You learnt the basics of MQL4 language then you wrote your first indicator and your first
expert advisor.
I hope you enjoyed the journey and interested to continue the road with me.
Today we will create our first script which will simply set the stoploss and takeprofit
values for all the already opened orders on the chart.
It’s useful if you are lazy to set manually your stoploss and takeprofit values from the
Modify or Delete Orders window for every order.
What are we waiting for? Let’s script!
What’s a MQL4 script?
The scrip is a program you run once to execute an action and it will be removed
immediately after the execution.
Unlike the expert advisors which will be called every time in a new tick arrival, the script
will be executed only for once.
And unlike the indicators which have the ability to draw lines on the chart, the script has
no access to indicator functions.
In short the script is an expert advisor which you can run only once.
Let's create our first script!
Wizards again!
With the help of the New Program wizard we will create the backbone of our scrip.
Bring the New Program wizard by choosing New from File menu or by clicking
CTRL+N hot keys (Figure 1).
We are going to create a script, so choose Scrip program in the wizard and click next.
That will bring the second step wizard (Figure 2).
Fill the Name, Author and Link fields with what you see in the figure 2 (or whatever you
want). Then click finish.
Figure 1 – New Program wizard
Figure 2 – Step 2
By clicking Finish button the wizard will write some code for you and left the places to
write your own code, this is the code we have got from the wizard.
//+------------------------------------------------------------------+
//| My_First_Script.mq4 |
//| Copyright Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Copyright Coders Guru"
#property link "http://www.forex-tsd.com"
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
Note: As you can easily notice from the above code that the wizard hasn’t added the init()
and deinit() functions and only added the start() function.
That’s because it’s rare to find a script needs to execute code in the program initialization
and de-initialization because the start() function itself will be executed for once.
But that’s not mean you can’t add init() and deinit() functions in a script. You can add
them if you want.
Now, we have to add our code to make our script more useful.
This is the code we have added to the above wizard’s generated code (our added code
marked by the bold font):
//+------------------------------------------------------------------+
//| My_First_Script.mq4 |
//| Copyright Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Copyright Coders Guru"
#property link "http://www.forex-tsd.com"
#property show_inputs
#include <stdlib.mqh>
extern double TakeProfit=250;
extern double StopLoss=35;
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
//----
int total,cnt,err;
total = OrdersTotal();
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()==OP_BUY) // long position is opened
{
OrderModify(OrderTicket(),OrderOpenPrice(),
Bid-Point*StopLoss,Bid+Point*TakeProfit,0,Green);
err=GetLastError();
Print("error(",err,"): ",ErrorDescription(err));
Sleep(1000);
}
if(OrderType()==OP_SELL) // short position is opened
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*StopLoss,
Ask-Point*TakeProfit,0,Red);
err=GetLastError();
Print("error(",err,"): ",ErrorDescription(err));
Sleep(1000);
}
}
//----
return(0);
}
//+------------------------------------------------------------------+
Let’s crack the code line by line as we used to do.
//+------------------------------------------------------------------+
//| My_First_Script.mq4 |
//| Copyright Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Copyright Coders Guru"
#property link "http://www.forex-tsd.com"
Here the wizard has written the comment block which contains the script name we have
been chosen, the copyright and link we have been typed.
Then two directive properties have been added according to the date we have entered,
these are the copyright and link properties.
#property show_inputs
We have added the show_inputs directive property to our script.
Without this property the script will not accept inputs from the user therefore will not
prompt an input window to the user as the one showed in figure 3.
In our script the user can set the TakeProfit and StopLoss values from the inputs window
or he can leave the default values we have set in our code.
Note: If you intend to write a script which doesn’t need inputs from the user, it’s
preferred to remove show_inputs directive property.
Figure 3 – Script Input window
#include <stdlib.mqh>
Later in our code we are going to use the function ErrorDescription which returns a
string description of the passed error number. This function is included in the file
“stdlib.mqh”, so we have included this file to our program using the include directive.
That means the content of the “stdlib.mqh” is a part of our code now and we can freely
use the ErrorDescription function.
extern double TakeProfit=250;
extern double StopLoss=35;
Here we have declared two extern variables which the user can set them from the script
inputs window (Figure 2) or he can leave the default values.
We will use these variables in our start() function to set the takeprofit and stoploss values
of all the already opened order.
int start()
{
//----
int total,cnt,err;
total = OrdersTotal();
....
}
We are inside the start() function which will be called only one time when you attach the
script to you chart.
We have declared three integer variables using a single line declaration method.
Then we assigned the return value of the OrdersTotal function to the total variable.
As you remember OrdersTotal function returns the number of opened and pending
orders.
for(cnt=0;cnt<total;cnt++)
{
....
}
Here we enter a for loop starts from 0 and ends to the total of already opened and pending
orders. We will use the loop variable cnt with the OrderSelect function to select every
opened order by its index. In every cycle of the loop we increase the cnt variable by 1.
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
We have selected the order by its index using the function OrderSelect and the loop
variable cnt.
We have to use the OrderSelect function before calling OrderType in the coming line.
(Please review Appendix 2 – Trading functions).
if(OrderType()==OP_BUY) // long position is opened
{
....
}
The OrderType function returns the type of selected order that will be one of:
OP_BUY, OP_SELL, OP_BUYLIMIT, OP_BUYSTOP, OP_SELLLIMIT or
OP_SELLSTOP.
In the above if block we have checked the type of order to find is it a Buy order or not.
If it's a Buy order, the code inside the block will be executed.
OrderModify(OrderTicket(),OrderOpenPrice(),
Bid-Point*StopLoss,Bid+Point*TakeProfit,0,Green);
It's a Buy order type, so we want to modify the values of stoploss and takeprofit to the
values of StopLoss and TakeProfit variables the user has been set.
We use the OrderModify function which modifies the properties of a specific opened
order or pending order with the new values you pass to the function.
We used these parameters:
ticket: We've got the current selected order ticket with OrderTicket function.
price: We've got the open price of the current selected order with OrderOpenPrice
function.
stoploss: Here we have set the stoploss value of the current selected order to the value of
the subtraction of the current bid price and the StopLoss value the user has been set.
takeprofit: Here we have set the takeprofit value of the current selected order to the
value of the addition of the current bid price and the TakeProfit value the user has been
set.
expiration: We haven't set an expiration date to our order, so we used 0.
arrow_color: We have set the color of the arrow to Green.
err=GetLastError();
Print("error(",err,"): ",ErrorDescription(err));
Sleep(1000);
We have assigned the returned value of the GetLastError function to the err variable.
The GetLastError returns the number of the last error occurred after an operation
(OrderModify in our case).
But we want to print not only the error number but the description of the error, so we
have used the ErrorDescription function to get the string description of the error number
and we have used the print function to output this message to the expert log.
Then we have used the Sleep function to give the terminal and our script the time to take
their breath for one second (1000 milliseconds).
Note: Sleep function suspends the execution of the program for a specified interval, this
interval passed to the function in milliseconds.
if(OrderType()==OP_SELL) // short position is opened
{
....
}
In the above if block we have checked the type of order to find is it a Sell order or not.
If it's a Sell order, the code inside the block will be executed.
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*StopLoss,
Ask-Point*TakeProfit,0,Red);
It's a Sell order type, so we want to modify the values of stoploss and takeprofit to the
values of StopLoss and TakeProfit variables the user has been set.
We use the OrderModify function again with these parameters:
ticket: We've got the current selected order ticket with OrderTicket function.
price: We've got the open price of the current selected order with OrderOpenPrice
function.
stoploss: Here we have set the stoploss value of the current selected order to the value of
the addition of the current ask price and the StopLoss value the user has been set.
takeprofit: Here we have set the takeprofit value of the current selected order to the
value of the subtraction of the current ask price and the TakeProfit value the user has
been set.
expiration: We haven't set an expiration date to our order, so we used 0.
arrow_color: We have set the color of the arrow to Red.
err=GetLastError();
Print("error(",err,"): ",ErrorDescription(err));
Sleep(1000);
The same as above explained lines.
return(0);
It's the time to terminate our script by using return function.
Let's compile our script by pressing F5 hot key, as soon as you compile the script it will
appear in the navigator window in the script category (Figure 4)
Note: The wizard has created the file "My_First_Script.mq4" and has placed it in the
"experts\scripts" folder for us.
You have to put all of you scripts in this folder and compile them before using them in
the terminal.
Figure 4 – Execute your script
To execute the script simply point it with your mouse and double click it, or click the left
mouse button and a menu as showed in figure 4 will appear then choose Execute On
Chart.
The inputs window (Figure 3) will appear and you can set new values for StopLoss and
TakeProfit or leave the default values.
I hope you enjoyed the lesson and found the first script we have created a useful one.
I welcome very much your questions and suggestions.
Coders’ Guru
We have created our first indicator, expert advisor and script in the previous lessons.
Every time we decide to create our program whatever the kind of the program (indicator,
expert or script) we have to write it from scratch.
This is a useful thing for MQL4 beginners, but it’s time consuming for advanced
programmers.
That’s why MQL4 has the feature of creating templates based programs.
Today we will create an indicator based on MACD template shipped with MetaTrader.
So, let’s template!
What are the MQL4 templates?
The MQL4 templates are text files contain instructions (commands) for MetaEditor to
generate a new program based on these instructions. MetaEditor will read these
instructions and use them to generate the appropriated lines of code.
We use the templates to duplicate the frequently used codes and save our coding time.
By using the templates you can create indicators, experts and scripts based on your
favorite indicators, experts and scripts and save the time of writing the code from scratch.
Today we are going to duplicate the MACD indicator and we will not add to it anything
that’s because we are not in the indicator creating lesson but we are in the template
lessons.
Inside look:
We are going to give the template file a look before digging into our creation of our first
template based indicator.
Note: The template files are stored in the experts\templates path.
And have the ".mqt" file extension.
Here’s the content of the “MACD.mqt” template which we will use it today creating our
template based indicator:
Note: We have indented some of content and colored them to make it clearer but you can
give the original file an inside look.
<expert>
type=INDICATOR_ADVISOR
separate_window=1
used_buffers=2
<param>
type=int
name=FastEMA
value=12
</param>
<param>
type=int
name=SlowEMA
value=26
</param>
<param>
type=int
name=SignalSMA
value=9
</param>
<ind>
color=Silver
type=DRAW_HISTOGRAM
</ind>
<ind>
color=Red
</ind>
</expert>
#header#
#property copyright "#copyright#"
#property link "#link#"
#indicator_properties#
#extern_variables#
#mapping_buffers#
//---- indicator buffers
double ExtSilverBuffer[];
double ExtRedBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
#buffers_used#;
//---- drawing settings
#indicators_init#
//----
SetIndexDrawBegin(1,SignalSMA);
IndicatorDigits(5);
//---- indicator buffers mapping
SetIndexBuffer(0, ExtSilverBuffer);
SetIndexBuffer(1, ExtRedBuffer);
//---- name for DataWindow and indicator subwindow label
IndicatorShortName("MACD("+FastEMA+","+SlowEMA+","+SignalSMA+")");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
//---- check for possible errors
if(counted_bars<0) return(-1);
//---- last counted bar will be recounted
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
for(int i=0; i<limit; i++)
ExtSilverBuffer[i]=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)-
iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
for(i=0; i<limit; i++)
ExtRedBuffer[i]=iMAOnArray(ExtSilverBuffer,Bars,SignalSMA,0,MODE_SMA,i)
;
//---- done
return(0);
}
//+------------------------------------------------------------------+
If you give the above code a look you can notice that the most of the code is a normal
MQL4 code with two new kinds of different code.
The first kind of code (Ex: <expert> and <param>) looks like the HTML tags; these are
the template tags.
And the second kind of code (Ex: #header# and #link#) looks like the MQL4 directives;
these are the template commands:
MQL4 template tags:
The template file starts with tags very like the Html and XML tags.
There is a start tag and a closing tag. The closing tag uses a slash after the opening
bracket. For example <expert> is the start tag and </expert> is the closing tag.
The text between the brackets is called an element. For example:
type=int
name=FastEMA
value=12
There are three tags in MQL4 template:
expert tag:
This is main tag and the other two tags are belonging to it.
In this tag we write the type of program, the indicator chart window, the number of buffer
used, the bottom border for the chart and the top border for the chart of the indicator.
These are the elements used in the expert tag:
type: The type of program. Possible values are EXPERT_ADVISOR,
INDICATOR_ADVISOR, SCRIPT_ADVISOR.
separate_window: The chart window type.
used_buffers: The number of used buffers.
ind_minimum: The fixed bottom border of indicator window.
ind_maximum: The fixed top border of indicator window.
param tag:
We use this tag to create external variables. For every variable we use a param tag.
These are the elements used in the param tag:
type: The data type of the variable.
name: The variable name.
value: The default value of the variable.
ind tag:
We use this tag to set the parameters of every indicator (drawing line) we use in our
program.
These are the elements used in the ind tag:
type: The indicator drawing shape style. Possible values are DRAW_LINE,
DRAW_HISTOGRAM, DRAW_SECTION, DRAW_ARROW.
color: The indicator color.
arrow: The character for displaying the DRAW_ARROW indicator. "Wingdings" font is
used for displaying the characters.
MQL4 template commands:
They are lines of code starts and ends with # symbol. And these lines of code will be
replaced with the corresponded lines with code in the generation process.
Note: MetaEditor reads these lines and replace them in the place they found and generate
the MQ4 file.
These are the template commands:
#header#: This line will be replaced with the program header block (comments with file
name, author name and the company name).
#copyright#: This line will be replaced with your company name.
#link#: This line will be replaced with your website link.
#indicator_properties#: This line will be replaced with the properties of the indicator.
#extern_variables#: This line will be replaced with external variables used in your
program with their types and default values.
#buffers_used#: This line will be replaced with the number of buffer used if any.
#indicators_init#: This line will be replaced with the initialization of the indicators
(using the function SetIndexStyle).
Creating our MACD template based indicator.
Now, let’s create our template based indicator by hitting our File menu and choose New
or clicking CTRL+N. That will bring the New Program wizard (Figure 1).
This time we will choose “Create from template” option and from the drop list we will
choose “Indicator – MACD”.
Figure 1 – New program wizard
Then we will hit Next button which brings the second step wizard (Figure 2).
MetaEditor has filled the fields with Author name and the Link (reading them from the
windows registry) and left the Name field blank which we typed in it
"MACD_From_Template"
In the Parameters list the MetaEditor has red our template file and filled the list with the
external variables and its default values.
Figure 2 – Second step wizard
Hitting Next button will bring the third step wizard (figure 3) which contains the indicator
parameters.
As you guessed MetaEditor has red our template file and generated the values of the
indicator properties.
Now click the finish button and you will see the magic of the templates.
Figure 3 – Third step wizard
What have we got?
The wizards have generated a new indicator for us based on MACD template.
Code ready to compile, ready to run:
//+------------------------------------------------------------------+
//| MACD_From_Template.mq4 |
//| Copyright Coders Guru |
//| http://www.forex-tsd.com |
//+------------------------------------------------------------------+
#property copyright "Copyright Coders Guru"
#property link "http://www.forex-tsd.com"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Silver
#property indicator_color2 Red
//---- input parameters
extern int FastEMA=12;
extern int SlowEMA=26;
extern int SignalSMA=9;
//---- buffers
//---- indicator buffers
double ExtSilverBuffer[];
double ExtRedBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- drawing settings
SetIndexStyle(0,DRAW_HISTOGRAM);
SetIndexStyle(1,DRAW_LINE);
//----
SetIndexDrawBegin(1,SignalSMA);
IndicatorDigits(5);
//---- indicator buffers mapping
SetIndexBuffer(0, ExtSilverBuffer);
SetIndexBuffer(1, ExtRedBuffer);
//---- name for DataWindow and indicator subwindow label
IndicatorShortName("MACD("+FastEMA+","+SlowEMA+","+SignalSMA+")");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
//---- check for possible errors
if(counted_bars<0) return(-1);
//---- last counted bar will be recounted
if(counted_bars>0) counted_bars--;
limit=Bars-counted_bars;
//---- macd counted in the 1-st buffer
for(int i=0; i<limit; i++)
ExtSilverBuffer[i]=iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)-
iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i);
//---- signal line counted in the 2-nd buffer
for(i=0; i<limit; i++)
ExtRedBuffer[i]=iMAOnArray(ExtSilverBuffer,Bars,SignalSMA,0,MODE_SMA,i)
;
//---- done
return(0);
}
//+------------------------------------------------------------------+
Compile the code and enjoy your new MACD indicator.
I welcome very much your questions and suggestions.
Coders’ Guru