Everything in the library are functions independent of each other; no global var for sharing across functions
Not so. Any Library can contain global vars AND they can be shared across all functions.
To DevMan, and anyone else that wants to create libraries, here is some info to help you.
You can use mq4 files like a library, but as you see you can not use the "#property library" preprocessor directive for that.
The #include directive is for including only text files like mq4 or mqh (Function library header file). Also depending how you reference your file, the preprocessor will look
for the file either in the default location - the \experts\include folder or in the \experts folder. (Look in help on "#include" for more info)
For example:
#include <myFile.mqh> Only the \experts\include folder (default location) is searched.
#include "myFile.mqh" Only the current directory is searched, where the source ex4 file is. For experts, it would of course be the experts folder.
As for your libraries, the standard and recomended way to store and use them is this:
1) Create your library as a normal mq4 file with the "#property library" directive at the top. Then compile and place both mq4 and ex4 files in the \experts\libraries folder.
For example lets say 2 of your functions look like this: (This will be useful for seeing how the header file you will create relates to your library functions)
// MyLibrary.mq4
#property library
bool Timer_CheckIfWaiting(int waitType)
{
return(arrTimer[waitType][BOOL_WAITING]);
}
int Timer_GetTimer(int waitType)
{
return(arrTimer[waitType][INT_TIME_TO_WAIT]);
}
// more functions...
// end of file
2) Then you need to create .mqh header file that lists the full description of each function, as the help file states: For compiler to be able to form the imported function call and pass parameters in a proper way, the full description of functions is needed. This description is simply the full definition of each function ending in a semicolin like this:
bool Timer_CheckIfWaiting(int waitType);
int Timer_GetTimer(int waitType);
string Timer_GetCountDownString(int waitType);
etc....
3) To finish your header file you need to put an #import directive at the top of your file followed by the name of your compiled ex4 file in quotes like this:
#import "Timers.ex4"
You also need to put an 'emtpy' #import statement at the bottom of your file. So you header file should now look like this:
#import "Timers.ex4"
bool Timer_CheckIfWaiting(int waitType);
string Timer_GetCountDownString(int waitType);
int Timer_GetTimer(int waitType);
// more function definitions...
#import
Your header file is done, but it must be copied to the \experts\include folder.
To use your Library, all you need to do is use an #include directive near the top of your EA to include your library header file- like this:
#include <MyLibrary.mqh>
Now when you complile your EA the content of the header file will be included in your ex4 file, but it will not include the library itself.
Your compiled "MyLibrary.ex4" file must remain in the library folder as your EA looks for this file at runtime.
So if you wanted to share your new EA with someone you would give them both the EA .ex4 file and the library .ex4 file.
Just be sure that they put the library file in the libraries folder or your EA won't work. By the way, you don't need to give them the header file for the reason I gave above.
But as you add functions to your library, just remember to also add the new function definitions to your header file.
Hope this helps...
Not so. Any Library can contain global vars AND they can be shared across all functions.
To DevMan, and anyone else that wants to create libraries, here is some info to help you.
You can use mq4 files like a library, but as you see you can not use the "#property library" preprocessor directive for that.
The #include directive is for including only text files like mq4 or mqh (Function library header file). Also depending how you reference your file, the preprocessor will look
for the file either in the default location - the \experts\include folder or in the \experts folder. (Look in help on "#include" for more info)
For example:
#include <myFile.mqh> Only the \experts\include folder (default location) is searched.
#include "myFile.mqh" Only the current directory is searched, where the source ex4 file is. For experts, it would of course be the experts folder.
As for your libraries, the standard and recomended way to store and use them is this:
1) Create your library as a normal mq4 file with the "#property library" directive at the top. Then compile and place both mq4 and ex4 files in the \experts\libraries folder.
For example lets say 2 of your functions look like this: (This will be useful for seeing how the header file you will create relates to your library functions)
// MyLibrary.mq4
#property library
bool Timer_CheckIfWaiting(int waitType)
{
return(arrTimer[waitType][BOOL_WAITING]);
}
int Timer_GetTimer(int waitType)
{
return(arrTimer[waitType][INT_TIME_TO_WAIT]);
}
// more functions...
// end of file
2) Then you need to create .mqh header file that lists the full description of each function, as the help file states: For compiler to be able to form the imported function call and pass parameters in a proper way, the full description of functions is needed. This description is simply the full definition of each function ending in a semicolin like this:
bool Timer_CheckIfWaiting(int waitType);
int Timer_GetTimer(int waitType);
string Timer_GetCountDownString(int waitType);
etc....
3) To finish your header file you need to put an #import directive at the top of your file followed by the name of your compiled ex4 file in quotes like this:
#import "Timers.ex4"
You also need to put an 'emtpy' #import statement at the bottom of your file. So you header file should now look like this:
#import "Timers.ex4"
bool Timer_CheckIfWaiting(int waitType);
string Timer_GetCountDownString(int waitType);
int Timer_GetTimer(int waitType);
// more function definitions...
#import
Your header file is done, but it must be copied to the \experts\include folder.
To use your Library, all you need to do is use an #include directive near the top of your EA to include your library header file- like this:
#include <MyLibrary.mqh>
Now when you complile your EA the content of the header file will be included in your ex4 file, but it will not include the library itself.
Your compiled "MyLibrary.ex4" file must remain in the library folder as your EA looks for this file at runtime.
So if you wanted to share your new EA with someone you would give them both the EA .ex4 file and the library .ex4 file.
Just be sure that they put the library file in the libraries folder or your EA won't work. By the way, you don't need to give them the header file for the reason I gave above.
But as you add functions to your library, just remember to also add the new function definitions to your header file.
Hope this helps...
Vangosh. thks for the insight; i have done up the libraries exactly as u have mentioned but minus global vars (except #define);
i am about to need a global var to handle fractional pips in all the lib ftns, so how do u do that? eg
#property library
int Pip;
//how do I change the value of Pip according to a bool switch that I will use eg if (UseFractionalPips) Pip=10; else Pip=1
bool Timer_CheckIfWaiting(int waitType)
{
//eg let's say we need to use global var Pip here
return(arrTimer[waitType][BOOL_WAITING]);
}
int Timer_GetTimer(int waitType)
{
//eg let's say we need to use global var Pip here
return(arrTimer[waitType][INT_TIME_TO_WAIT]);
}
Vangosh. thks for the insight; i have done up the libraries exactly as u have mentioned but minus global vars (except #define);
i am about to need a global var to handle fractional pips in all the lib ftns, so how do u do that? eg
#property library
int Pip;
//how do I change the value of Pip according to a bool switch that I will use eg if (UseFractionalPips) Pip=10; else Pip=1
bool Timer_CheckIfWaiting(int waitType)
{
//eg let's say we need to use global var Pip here
return(arrTimer[waitType][BOOL_WAITING]);
}
int Timer_GetTimer(int waitType)
{
//eg let's say we need to use global var Pip here
return(arrTimer[waitType][INT_TIME_TO_WAIT]);
}
You use the globar var just like any other. It doesn't matter if it's in your library or in your main EA. Any var outside of function scope is global no matter where you declare it. Here is some of my code so you can see:
#property library // Array Rows shown just for reference. #defines are really put in main EA. //#define WAIT_TYPE_ORDER1 0 //#define WAIT_TYPE_ORDER2 1 //#define WAIT_TYPE_FILTER 2 //#define WAIT_TYPE_ANOTHER 3 // add as many wait types (timers) as you want. // Array Colums #define BOOL_WAITING 0 #define INT_TIME_TO_WAIT 1 int arrTimer[25][2]; //Global array var that is used in the functions below. The amount of timers is hardcoded to 25 for now. void Timer_Init() { ArrayInitialize(arrTimer,-1); } bool Timer_CheckIfWaiting(int waitType) { return(arrTimer[waitType][BOOL_WAITING]); } string Timer_GetCountDownString(int waitType) { int secondsMod; int waitCountSec; int waitCountMin; string leadingZero; string trailingZero; string countDown; waitCountSec = TimeLocal() - Timer_GetTimer(waitType); waitCountSec = -waitCountSec; if (waitCountSec <= 0) return("0:00"); waitCountMin = waitCountSec/60; // Modulo formula: a - n * floor(a / n): waitCountSec - 60 * MathFloor(waitCountSec / 60); secondsMod = waitCountSec % 60; if (secondsMod == 0) trailingZero = "0"; else trailingZero = ""; if (secondsMod > 0 && secondsMod < 10) leadingZero = "0"; else leadingZero = ""; countDown = StringConcatenate(waitCountMin, ":", leadingZero, secondsMod, trailingZero); return(countDown); } int Timer_GetTimer(int waitType) { return(arrTimer[waitType][INT_TIME_TO_WAIT]); } void Timer_StartWaiting(int minutes, int waitType) { minutes*=60; arrTimer[waitType][BOOL_WAITING] = true; arrTimer[waitType][INT_TIME_TO_WAIT] = TimeLocal() + minutes; }
Here is some of the main EA code that uses my Timers library. I included the list of externs just so you can get an idea of what is availible to do in my EA.
// Main EA #include <Timers.mqh> // Timer Wait Types. Can have up to 25 types. #define TIMER_ORDER1 0 #define TIMER_ORDER2 1 #define TIMER_FILTER 2 // External vars extern string UserNotes; extern bool EnableTrading = false; extern int MaxOrders = 3; extern int OrderWaitTime = 2; //Used with Timers extern double Lots = 0.01; extern int TakeProfit = 20; extern int StopLoss = 70; extern int TrailingStop = 0; extern bool AutoLotIncrease = true; extern double LotIncreaseStepSize = 0.01; extern bool ResetLots = false; extern int MoneyManagement = true; extern double MM_MarginLevel = 2000; extern string TimePeriod_Note = "Use only: 5=M5, 15=M15, 30=M30, 60=H1"; extern int TimePeriod = 15; extern int NumBars = 10; extern int FilterPeriod = 60; extern int FilterWaitTime = 10; //Used with Timers extern int FilterStochastic = false; extern int StochSlowing = 3; extern int FilterCCI = false; extern int PeriodCCI = 14; extern int FilterRSI = false; extern int PeriodRSI = 9; extern int HighRSI = 70; extern int LowRSI = 27; extern int FilterWPR = false; extern int PeriodWPR = 14; extern int HighWPR = -20; extern int LowWPR = -80; extern int FilterMomentum = true; extern int PeriodMomentum = 4; extern int FilterMA = true; extern int PeriodMASlow = 12; extern int PeriodMAFast = 3; extern int PPM_1 = 3; extern int PPM_5 = 5; extern int PPM_15 = 15; extern int PPM_X = 60; extern int MagicNumber = 5252; extern bool GV_DeleteAll = false;
Main EA continued:
// Some notable global vars bool orderWaiting = false; bool filterWaiting = false; string trendInfo; string comment1; string comment2; string comment3; string statusMode; // MT Client Global Variable names string GV_OrderTicket; string GV_OrderOpen; string GV_LotSize; void CheckWaiting() // Checks for running timers and will help with displaying timer info on screen { if (Timer_GetCountDownString(TIMER_ORDER1) != "0:00") comment2 = "\n>> Order Pause: " + Timer_GetCountDownString(TIMER_ORDER1) + " minutes..."; if (Timer_GetCountDownString(TIMER_ORDER1) == "0:00") { orderWaiting = false; comment2 = ""; } if (Timer_GetCountDownString(TIMER_FILTER) != "0:00") comment3 = "\n>> Order Pause: " + Timer_GetCountDownString(TIMER_FILTER) + " minutes..."; if (Timer_GetCountDownString(TIMER_FILTER) == "0:00") { filterWaiting = false; comment3 = ""; } } // Example of how I do my filters (indicators) bool RSIFilter(string orderType) { if (FilterRSI == false) return(true); double rsiValue = iRSI(NULL,FilterPeriod,PeriodRSI,PRICE_CLOSE,0); //Print(">> rsiValue: ", rsiValue); if (orderType == "Buy") { if (rsiValue > HighRSI) return(false); else return(true); } if (orderType == "Sell") { if (rsiValue < LowRSI) return(false); else return(true); } }
// Main function void Main() { // Lots of code removed to show trend info and to handle displaying of Comments Comment(trendInfo, comment1, comment2, comment3); if (EnableTrading == false) return; if (GetOpenOrders() == MaxOrders) return; //Print(">> No more orders allowed"); if (orderWaiting == true || filterWaiting == true) return; GoForTrade(); } // end of Main // GoForTrade() function void GoForTrade() { // custom entry logic removed // then I add my filter checks as needed if (MAFilter("Buy") == false) { comment1 = "\n>> Buy Order prevented by MA Filter at " + timeDate + " " + timeMinutes; Print(comment1); Timer_StartWaiting(FilterWaitTime,TIMER_FILTER); filterWaiting = true; return; } if (MomentumFilter("Buy") == false) { comment1 = "\n>> Buy Order prevented by Momentum Filter at " + timeDate + " " + timeMinutes; Print(comment1); Timer_StartWaiting(FilterWaitTime,TIMER_FILTER); filterWaiting = true; return; } // several more filter checks... // if everything checks out, it will open an order. BuyOrder(TakeProfit, StopLoss); // Same code for selling here... }
Main EA Continued...
// Buy order with much code removed... void BuyOrder(int takeProfitPips, int stopLossPips) { double dblStopLoss; double objStopLoss; double dblTakeProfit; string strStopLoss; string name; string description; string order_Comment; int order_Ticket; MoneyManagementCheck(); if (IsTradeAllowed()) order_Ticket = OrderSend(); else return; // if order success.. Print(">> Buy Order # ", order_Ticket, " Sent at ", timeMinutes," ", order_Comment); comment1 = "\n>> Buy Order # " + order_Ticket + " Sent at " + timeMinutes + "\n>> " + order_Comment; SaveOrderTicket(order_Ticket); MoneyManagementCheck(); Lots = GlobalVariableGet(Symbol() + "_LotSize"); Timer_StartWaiting(OrderWaitTime,TIMER_ORDER1); // Call to Timer library orderWaiting = true; // Used for Timers } } //Not related to timers but I manage multible orders by saving info from each order to Client GlobalVariables void SaveOrderTicket(int order_Ticket) { string leadingZero; for (int i=1; i<MaxOrders+1; i++) { if (i > 0 && i < 10) leadingZero = "0"; else leadingZero = ""; if (GlobalVariableGet(Symbol() + "_OrderOpen_" + leadingZero + i) == 0) { GlobalVariableSet(Symbol() + "_OrderOpen_" + leadingZero + i, 1); GlobalVariableSet(Symbol() + "_OrderTicket_" + leadingZero + i, order_Ticket); break; } } } // Then you can work with your open orders like this void CheckIfOpenOrder_Closed() { int order_Ticket; datetime closeTime; string leadingZero; double stopLoss = 0; double takeProfit = 0; double pips; double profit; string order_Type; int i; for (i=1; i<MaxOrders+1; i++) { if (i > 0 && i < 10) leadingZero = "0"; else leadingZero = ""; if (GlobalVariableGet(Symbol() + "_OrderOpen_" + leadingZero + i) == 1) { order_Ticket = GlobalVariableGet(Symbol() + "_OrderTicket_" + leadingZero + i); if (OrderSelect(order_Ticket, SELECT_BY_TICKET) == true) if (OrderCloseTime() > 0) break; } } // now that you have the ticket of the latest order closed you can do whatever you want here... // display some info about closed order Print(">> ", order_Type, " Order # ", order_Ticket, " is closed at ", TimeToStr(closeTime,TIME_MINUTES)); Print(">> Margin Level = ", GetMarginLevel(), "%, MM_MarginLevel = ", MM_MarginLevel, "%"); comment1 = StringConcatenate("\n>> ", order_Type, " Order # ", order_Ticket, " is closed at ", TimeToStr(closeTime,TIME_MINUTES), "\n>> Profit = " + DoubleToStr(profit,2), " - Pips = " + DoubleToStr(pips,0)); // make this order slot available for new orders GlobalVariableSet(Symbol() + "_OrderOpen_" + leadingZero + i, 0); // now no open order in this slot GlobalVariableSet(Symbol() + "_OrderTicket_" + leadingZero + i, -1); // order ticket for this slot is -1... no ticket... MoneyManagementCheck(); }
Last bit of EA code relating to Timer library...
void init() { Timer_Init(); // this is a good place to do this... // Create GlobalVariable Names here // Lots of other init stuff } // if you don't do this your backtesting will be messed up (if you use GV's) void deinit() { if (IsTesting()) { // Delete all GlobalVariables and start fresh for next pass GlobalVariablesDeleteAll(); } } // This is all of my start function void start() { if (validTimePeriod == false) return; if (validFilterPeriod == false) return; if (validTrailingStop == false) return; //---- Start Main program ---- Main(); if (TrailingStop > 0) CheckTrailingStop(GetOpenOrderTickets, TrailingStop); CheckWaiting(); GetOpenTradeLots(); CheckIfOpenOrder_Closed(); }
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
OK,
Library development - its simple right ?...
I have a library file in my "include" folder, its not a header with function prototypes, its a proper in-line #include of a source file. Its a self-contained set of code. It goes like this...
The compiler likes it, includes it in my EA no problem, and we're good to go.
However...
In my EA I now add some parameters using the "extern" declaration like this...
My EA compiles & I can drag it onto a chart; BUT; there are no parameters available - all of those "extern" items are missing...
After much head scratching I comment out the include and find the parameters returned. So again after trial & error I discover that if I have ANY variables declared in my include then I lose all of my "extern" parameters to the EA. I can include the file so long as it doesn't have any variables declare within it.
The following causes it to work properly...
How on earth do I get around this ?... I want to include a nice library of self-contained functions & variables that I can still access and use in my EA, but it seems this is not possible...
I've even placed the #include line AFTER my "extern" variables but still no joy.
SURELY this is not correct. If an "#include" directive replaces the line of code with the contents of the included file, then this should be simple. If I add variables to my EA this doesn't lose all of the extern items. I don't want to add the variables of my "libraray" file into my main EA - surely that's the whole purpose of an "included" file..
SO... Why am I losing my parameters when I include a file with modular scope variables ? (even if I declare them extern in the included file I still lose my parameters)
This is madness... HELP !...