Changes: - Add FAL_KEY and GEMINI_API_KEY to .env.example - Update picture-it to use ~/.config/opencode/.env (unified creds) - Remove shodh-memory skill (no longer used) - Remove alphaear-* skills (deprecated) - Remove thai-frontend-dev skill (replaced by website-creator) - Remove theme-factory skill - Add mql-developer skill (MQL5 trading) - Add ecommerce-astro skill (Astro e-commerce) - Add website-creator skill (Next.js + Payload CMS) - Update install script for new skills
2052 lines
63 KiB
Markdown
2052 lines
63 KiB
Markdown
# MQL4 Language Reference
|
|
|
|
Complete reference for MetaQuotes Language 4 (MQL4), used to develop Expert Advisors, custom indicators, scripts, and libraries for the MetaTrader 4 trading platform.
|
|
|
|
## Table of Contents
|
|
|
|
- [Data Types](#data-types)
|
|
- [Variables](#variables)
|
|
- [Operators](#operators)
|
|
- [Arrays](#arrays)
|
|
- [Strings](#strings)
|
|
- [Program Types](#program-types)
|
|
- [Predefined Variables](#predefined-variables)
|
|
- [Technical Indicator Functions](#technical-indicator-functions)
|
|
- [Order Management](#order-management)
|
|
- [Market Information](#market-information)
|
|
- [Account Functions](#account-functions)
|
|
- [Preprocessor Directives](#preprocessor-directives)
|
|
- [Error Handling](#error-handling)
|
|
- [Common Gotchas](#common-gotchas)
|
|
- [File Operations](#file-operations)
|
|
- [WebRequest](#webrequest)
|
|
- [Utility Functions](#utility-functions)
|
|
- [Global Terminal Variables](#global-terminal-variables)
|
|
|
|
---
|
|
|
|
## Data Types
|
|
|
|
### Integer Types
|
|
|
|
| Type | Size | Range |
|
|
|------|------|-------|
|
|
| `char` | 1 byte | -128 to 127 |
|
|
| `uchar` | 1 byte | 0 to 255 |
|
|
| `short` | 2 bytes | -32,768 to 32,767 |
|
|
| `ushort` | 2 bytes | 0 to 65,535 |
|
|
| `int` | 4 bytes | -2,147,483,648 to 2,147,483,647 |
|
|
| `uint` | 4 bytes | 0 to 4,294,967,295 |
|
|
| `long` | 8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
|
|
| `ulong` | 8 bytes | 0 to 18,446,744,073,709,551,615 |
|
|
|
|
### Floating-Point Types
|
|
|
|
| Type | Size | Significant Digits | Range |
|
|
|------|------|---------------------|-------|
|
|
| `float` | 4 bytes | 7 | 1.175e-38 to 3.402e+38 |
|
|
| `double` | 8 bytes | 15-16 | 2.225e-308 to 1.797e+308 |
|
|
|
|
### Other Types
|
|
|
|
| Type | Description | Example |
|
|
|------|-------------|---------|
|
|
| `bool` | Boolean | `true`, `false` |
|
|
| `string` | Character string | `"Hello World"` |
|
|
| `datetime` | Date and time (seconds since 1970.01.01) | `D'2024.01.15'`, `D'2024.01.15 10:30:00'` |
|
|
| `color` | RGB color | `clrRed`, `clrBlue`, `C'128,128,128'`, `0x00FF00` |
|
|
|
|
```mql4
|
|
// Type examples
|
|
int count = 10;
|
|
double price = 1.23456;
|
|
bool isActive = true;
|
|
string name = "EURUSD";
|
|
datetime startTime = D'2024.01.15 08:00:00';
|
|
color arrowColor = clrRed;
|
|
color custom = C'128,128,128';
|
|
```
|
|
|
|
### Enumerations
|
|
|
|
```mql4
|
|
enum ENUM_SIGNAL
|
|
{
|
|
SIGNAL_NONE = 0, // No signal
|
|
SIGNAL_BUY = 1, // Buy signal
|
|
SIGNAL_SELL = -1 // Sell signal
|
|
};
|
|
|
|
ENUM_SIGNAL signal = SIGNAL_BUY;
|
|
```
|
|
|
|
### Structures
|
|
|
|
```mql4
|
|
struct TradeSetup
|
|
{
|
|
string symbol;
|
|
int direction;
|
|
double entryPrice;
|
|
double stopLoss;
|
|
double takeProfit;
|
|
double lotSize;
|
|
};
|
|
|
|
TradeSetup setup;
|
|
setup.symbol = "EURUSD";
|
|
setup.direction = OP_BUY;
|
|
setup.entryPrice = Ask;
|
|
setup.stopLoss = Ask - 50 * Point;
|
|
setup.takeProfit = Ask + 100 * Point;
|
|
setup.lotSize = 0.1;
|
|
```
|
|
|
|
### Type Casting
|
|
|
|
```mql4
|
|
double price = 1.23456;
|
|
int pips = (int)(price * 10000); // Explicit cast
|
|
string text = DoubleToString(price, 5); // Function conversion
|
|
```
|
|
|
|
---
|
|
|
|
## Variables
|
|
|
|
### Local Variables
|
|
|
|
Declared inside a function. Exist only during function execution.
|
|
|
|
```mql4
|
|
void CalculateSignal()
|
|
{
|
|
int period = 14; // Local variable
|
|
double value = iRSI(NULL, 0, period, PRICE_CLOSE, 0);
|
|
}
|
|
```
|
|
|
|
### Global Variables
|
|
|
|
Declared outside any function. Accessible from all functions in the file. Initialized once when the program loads.
|
|
|
|
```mql4
|
|
double g_lotSize = 0.1; // Global variable (file scope)
|
|
int g_magicNumber = 12345;
|
|
|
|
int OnInit()
|
|
{
|
|
g_lotSize = 0.2; // Accessible here
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
double lots = g_lotSize; // Accessible here too
|
|
}
|
|
```
|
|
|
|
### Static Variables
|
|
|
|
Retain their value between function calls. Initialized only once.
|
|
|
|
```mql4
|
|
void OnTick()
|
|
{
|
|
static int tickCount = 0; // Initialized once
|
|
static datetime lastBarTime = 0;
|
|
|
|
tickCount++;
|
|
|
|
if(Time[0] != lastBarTime)
|
|
{
|
|
lastBarTime = Time[0];
|
|
// New bar logic here
|
|
}
|
|
}
|
|
```
|
|
|
|
### Input Variables
|
|
|
|
User-configurable parameters. Appear in the EA/indicator properties dialog. Read-only at runtime.
|
|
|
|
```mql4
|
|
input int InpMAPeriod = 14; // MA Period
|
|
input double InpLotSize = 0.1; // Lot Size
|
|
input string InpComment = "MyEA"; // Order Comment
|
|
input bool InpUseFilter = true; // Use Trend Filter
|
|
input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // MA Method
|
|
```
|
|
|
|
### Extern Variables
|
|
|
|
Similar to `input` but can be modified at runtime. Legacy; prefer `input`.
|
|
|
|
```mql4
|
|
extern int ExtPeriod = 20; // Period
|
|
extern double ExtFactor = 1.5; // Factor
|
|
|
|
void OnTick()
|
|
{
|
|
ExtPeriod = 30; // Allowed (unlike input variables)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Operators
|
|
|
|
### Arithmetic Operators
|
|
|
|
| Operator | Description | Example |
|
|
|----------|-------------|---------|
|
|
| `+` | Addition | `a + b` |
|
|
| `-` | Subtraction | `a - b` |
|
|
| `*` | Multiplication | `a * b` |
|
|
| `/` | Division | `a / b` |
|
|
| `%` | Modulo | `a % b` |
|
|
| `++` | Increment | `a++` or `++a` |
|
|
| `--` | Decrement | `a--` or `--a` |
|
|
|
|
### Assignment Operators
|
|
|
|
| Operator | Description | Equivalent |
|
|
|----------|-------------|------------|
|
|
| `=` | Assign | `a = b` |
|
|
| `+=` | Add and assign | `a = a + b` |
|
|
| `-=` | Subtract and assign | `a = a - b` |
|
|
| `*=` | Multiply and assign | `a = a * b` |
|
|
| `/=` | Divide and assign | `a = a / b` |
|
|
| `%=` | Modulo and assign | `a = a % b` |
|
|
|
|
### Comparison Operators
|
|
|
|
| Operator | Description |
|
|
|----------|-------------|
|
|
| `==` | Equal to |
|
|
| `!=` | Not equal to |
|
|
| `<` | Less than |
|
|
| `>` | Greater than |
|
|
| `<=` | Less than or equal to |
|
|
| `>=` | Greater than or equal to |
|
|
|
|
### Logical Operators
|
|
|
|
| Operator | Description | Example |
|
|
|----------|-------------|---------|
|
|
| `&&` | Logical AND | `a > 0 && b > 0` |
|
|
| `\|\|` | Logical OR | `a > 0 \|\| b > 0` |
|
|
| `!` | Logical NOT | `!isActive` |
|
|
|
|
### Bitwise Operators
|
|
|
|
| Operator | Description |
|
|
|----------|-------------|
|
|
| `&` | Bitwise AND |
|
|
| `\|` | Bitwise OR |
|
|
| `^` | Bitwise XOR |
|
|
| `~` | Bitwise NOT |
|
|
| `<<` | Left shift |
|
|
| `>>` | Right shift |
|
|
|
|
### Ternary Operator
|
|
|
|
```mql4
|
|
double lots = (AccountBalance() > 10000) ? 0.2 : 0.1;
|
|
string direction = (signal == SIGNAL_BUY) ? "BUY" : "SELL";
|
|
```
|
|
|
|
---
|
|
|
|
## Arrays
|
|
|
|
### Static Arrays
|
|
|
|
Fixed size, determined at compile time.
|
|
|
|
```mql4
|
|
double prices[100];
|
|
int values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
string symbols[3] = {"EURUSD", "GBPUSD", "USDJPY"};
|
|
```
|
|
|
|
### Dynamic Arrays
|
|
|
|
Size determined at runtime. Must be resized with `ArrayResize()`.
|
|
|
|
```mql4
|
|
double buffer[];
|
|
ArrayResize(buffer, 100);
|
|
buffer[0] = 1.23456;
|
|
```
|
|
|
|
### Multi-Dimensional Arrays
|
|
|
|
```mql4
|
|
double matrix[3][4]; // Static 3x4 matrix
|
|
double grid[][5]; // Dynamic first dimension, fixed second
|
|
ArrayResize(grid, 10); // Now 10x5
|
|
```
|
|
|
|
### Array Functions
|
|
|
|
```mql4
|
|
// int ArrayResize(array&, int new_size, int reserve_size=0)
|
|
// Resizes a dynamic array. Returns new size or -1 on failure.
|
|
double data[];
|
|
int newSize = ArrayResize(data, 200);
|
|
|
|
// int ArraySize(const array&)
|
|
// Returns the total number of elements.
|
|
int count = ArraySize(data); // 200
|
|
|
|
// int ArrayCopy(dst&, const src, int dst_start=0, int src_start=0, int count=WHOLE_ARRAY)
|
|
// Copies elements from one array to another.
|
|
double source[5] = {1.0, 2.0, 3.0, 4.0, 5.0};
|
|
double dest[];
|
|
ArrayResize(dest, 5);
|
|
ArrayCopy(dest, source);
|
|
|
|
// bool ArraySort(array&, int count=WHOLE_ARRAY, int start=0, int direction=MODE_ASCEND)
|
|
// Sorts a numeric array. direction: MODE_ASCEND or MODE_DESCEND.
|
|
double values[5] = {3.0, 1.0, 4.0, 1.5, 2.0};
|
|
ArraySort(values); // {1.0, 1.5, 2.0, 3.0, 4.0}
|
|
|
|
// void ArrayInitialize(array&, double value)
|
|
// Fills all elements with the given value.
|
|
double arr[100];
|
|
ArrayInitialize(arr, 0.0);
|
|
|
|
// int ArrayMaximum(const array&, int count=WHOLE_ARRAY, int start=0)
|
|
// Returns the index of the maximum value.
|
|
int maxIdx = ArrayMaximum(values);
|
|
|
|
// int ArrayMinimum(const array&, int count=WHOLE_ARRAY, int start=0)
|
|
// Returns the index of the minimum value.
|
|
int minIdx = ArrayMinimum(values);
|
|
|
|
// void ArrayFree(array&)
|
|
// Frees memory of a dynamic array and sets size to 0.
|
|
ArrayFree(data);
|
|
|
|
// bool ArraySetAsSeries(array&, bool flag)
|
|
// Sets reverse indexing (index 0 = last element). Used for indicator buffers.
|
|
double buffer[];
|
|
ArraySetAsSeries(buffer, true); // Now buffer[0] is the newest element
|
|
```
|
|
|
|
---
|
|
|
|
## Strings
|
|
|
|
### String Functions
|
|
|
|
```mql4
|
|
// int StringLen(string value)
|
|
int len = StringLen("Hello"); // 5
|
|
|
|
// string StringSubstr(string value, int start, int length=-1)
|
|
string sub = StringSubstr("EURUSD", 0, 3); // "EUR"
|
|
|
|
// int StringFind(string value, string match, int start=0)
|
|
// Returns position or -1 if not found.
|
|
int pos = StringFind("EURUSD", "USD"); // 3
|
|
|
|
// int StringReplace(string& str, string find, string replacement)
|
|
// Returns number of replacements made.
|
|
string text = "Hello World";
|
|
int count = StringReplace(text, "World", "MQL4"); // text = "Hello MQL4"
|
|
|
|
// string StringConcatenate(...)
|
|
// Concatenates multiple values. Faster than + operator for many strings.
|
|
string result = StringConcatenate("Price: ", DoubleToString(Ask, 5), " Time: ", TimeToString(TimeCurrent()));
|
|
|
|
// string StringToUpper(string value)
|
|
string upper = "eurusd";
|
|
StringToUpper(upper); // upper = "EURUSD"
|
|
// Note: StringToLower() also available
|
|
|
|
// int StringToInteger(string value)
|
|
int num = StringToInteger("42"); // 42
|
|
|
|
// double StringToDouble(string value)
|
|
double val = StringToDouble("1.23456"); // 1.23456
|
|
|
|
// string IntegerToString(long value, int str_len=0, ushort fill=' ')
|
|
string s1 = IntegerToString(42); // "42"
|
|
string s2 = IntegerToString(5, 3, '0'); // "005"
|
|
|
|
// string DoubleToString(double value, int digits=8)
|
|
string s3 = DoubleToString(1.23456, 5); // "1.23456"
|
|
string s4 = DoubleToString(1.23456, 2); // "1.23"
|
|
|
|
// Additional useful conversions
|
|
// string TimeToString(datetime value, int mode=TIME_DATE|TIME_MINUTES)
|
|
// datetime StringToTime(string value)
|
|
// string EnumToString(enum_value)
|
|
```
|
|
|
|
### String Formatting with StringFormat
|
|
|
|
```mql4
|
|
// Works like C printf
|
|
string msg = StringFormat("Symbol: %s | Price: %.5f | Spread: %d",
|
|
_Symbol, Ask, (int)MarketInfo(_Symbol, MODE_SPREAD));
|
|
// "Symbol: EURUSD | Price: 1.23456 | Spread: 12"
|
|
```
|
|
|
|
---
|
|
|
|
## Program Types
|
|
|
|
### Expert Advisors (EAs)
|
|
|
|
Automated trading programs that run on charts and can place/modify/close orders.
|
|
|
|
```mql4
|
|
//+------------------------------------------------------------------+
|
|
//| MyExpert.mq4 |
|
|
//| Copyright 2024, Author |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Author"
|
|
#property link "https://www.example.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//--- Input parameters
|
|
input int InpMAPeriod = 14; // MA Period
|
|
input double InpLotSize = 0.1; // Lot Size
|
|
input int InpStopLoss = 50; // Stop Loss (points)
|
|
input int InpTakeProfit = 100; // Take Profit (points)
|
|
input int InpMagicNumber = 12345; // Magic Number
|
|
input int InpSlippage = 3; // Slippage (points)
|
|
|
|
//--- Global variables
|
|
double g_pipSize;
|
|
int g_pipDigits;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//| Called once when the EA is loaded onto a chart. |
|
|
//| Return: INIT_SUCCEEDED, INIT_FAILED, |
|
|
//| INIT_PARAMETERS_INCORRECT, INIT_AGENT_NOT_SUITABLE |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Detect broker digit mode
|
|
if(Digits == 5 || Digits == 3)
|
|
{
|
|
g_pipSize = Point * 10;
|
|
g_pipDigits = 1;
|
|
}
|
|
else
|
|
{
|
|
g_pipSize = Point;
|
|
g_pipDigits = 0;
|
|
}
|
|
|
|
// Set up timer (optional)
|
|
EventSetTimer(60); // Fire OnTimer() every 60 seconds
|
|
|
|
Print("EA initialized on ", _Symbol, " | PipSize=", g_pipSize);
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//| Called when the EA is removed or the terminal is closed. |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
EventKillTimer();
|
|
|
|
string reasonText;
|
|
switch(reason)
|
|
{
|
|
case REASON_REMOVE: reasonText = "Removed from chart"; break;
|
|
case REASON_RECOMPILE: reasonText = "Recompiled"; break;
|
|
case REASON_CHARTCHANGE: reasonText = "Symbol or period changed"; break;
|
|
case REASON_CHARTCLOSE: reasonText = "Chart closed"; break;
|
|
case REASON_PARAMETERS: reasonText = "Inputs changed"; break;
|
|
case REASON_ACCOUNT: reasonText = "Account changed"; break;
|
|
case REASON_TEMPLATE: reasonText = "Template applied"; break;
|
|
case REASON_INITFAILED: reasonText = "OnInit failed"; break;
|
|
case REASON_CLOSE: reasonText = "Terminal closed"; break;
|
|
default: reasonText = "Unknown"; break;
|
|
}
|
|
Print("EA deinitialized. Reason: ", reasonText);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//| Called on every new tick (price change) for the chart symbol. |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Check if trading is allowed
|
|
if(!IsTradeAllowed()) return;
|
|
if(!IsConnected()) return;
|
|
|
|
// New bar detection
|
|
static datetime lastBarTime = 0;
|
|
if(Time[0] == lastBarTime) return;
|
|
lastBarTime = Time[0];
|
|
|
|
// Trading logic here
|
|
double maValue = iMA(NULL, 0, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
|
|
|
|
if(Close[1] > maValue && CountOrders(OP_BUY) == 0)
|
|
{
|
|
OpenOrder(OP_BUY);
|
|
}
|
|
else if(Close[1] < maValue && CountOrders(OP_SELL) == 0)
|
|
{
|
|
OpenOrder(OP_SELL);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Timer function |
|
|
//| Called at the interval set by EventSetTimer(). |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
// Periodic tasks: cleanup, status updates, etc.
|
|
Print("Timer event at ", TimeToString(TimeCurrent()));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ChartEvent function |
|
|
//| Called when chart events occur (clicks, key presses, objects). |
|
|
//+------------------------------------------------------------------+
|
|
void OnChartEvent(const int id,
|
|
const long &lparam,
|
|
const double &dparam,
|
|
const string &sparam)
|
|
{
|
|
if(id == CHARTEVENT_CLICK)
|
|
{
|
|
Print("Chart clicked at x=", lparam, " y=", dparam);
|
|
}
|
|
else if(id == CHARTEVENT_KEYDOWN)
|
|
{
|
|
Print("Key pressed: ", lparam);
|
|
}
|
|
else if(id == CHARTEVENT_OBJECT_CLICK)
|
|
{
|
|
Print("Object clicked: ", sparam);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Count open orders by type for this EA |
|
|
//+------------------------------------------------------------------+
|
|
int CountOrders(int orderType)
|
|
{
|
|
int count = 0;
|
|
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderSymbol() != _Symbol) continue;
|
|
if(OrderMagicNumber() != InpMagicNumber) continue;
|
|
if(OrderType() == orderType) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open a market order |
|
|
//+------------------------------------------------------------------+
|
|
bool OpenOrder(int orderType)
|
|
{
|
|
double price, sl, tp;
|
|
|
|
RefreshRates();
|
|
|
|
if(orderType == OP_BUY)
|
|
{
|
|
price = Ask;
|
|
sl = (InpStopLoss > 0) ? NormalizeDouble(Ask - InpStopLoss * Point, Digits) : 0;
|
|
tp = (InpTakeProfit > 0) ? NormalizeDouble(Ask + InpTakeProfit * Point, Digits) : 0;
|
|
}
|
|
else
|
|
{
|
|
price = Bid;
|
|
sl = (InpStopLoss > 0) ? NormalizeDouble(Bid + InpStopLoss * Point, Digits) : 0;
|
|
tp = (InpTakeProfit > 0) ? NormalizeDouble(Bid - InpTakeProfit * Point, Digits) : 0;
|
|
}
|
|
|
|
int ticket = OrderSend(_Symbol, orderType, InpLotSize, price, InpSlippage,
|
|
sl, tp, "MyEA", InpMagicNumber, 0, clrGreen);
|
|
|
|
if(ticket < 0)
|
|
{
|
|
Print("OrderSend failed. Error: ", GetLastError());
|
|
return false;
|
|
}
|
|
|
|
Print("Order opened. Ticket: ", ticket);
|
|
return true;
|
|
}
|
|
```
|
|
|
|
#### Deinit Reason Constants
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `REASON_PROGRAM` | 0 | EA called `ExpertRemove()` |
|
|
| `REASON_REMOVE` | 1 | Removed from chart |
|
|
| `REASON_RECOMPILE` | 2 | Recompiled |
|
|
| `REASON_CHARTCHANGE` | 3 | Symbol or period changed |
|
|
| `REASON_CHARTCLOSE` | 4 | Chart closed |
|
|
| `REASON_PARAMETERS` | 5 | Input parameters changed |
|
|
| `REASON_ACCOUNT` | 6 | Account changed |
|
|
| `REASON_TEMPLATE` | 7 | New template applied |
|
|
| `REASON_INITFAILED` | 8 | `OnInit()` returned non-zero |
|
|
| `REASON_CLOSE` | 9 | Terminal closed |
|
|
|
|
---
|
|
|
|
### Custom Indicators
|
|
|
|
Calculate and display values on charts. Cannot trade. Run in the interface thread (must be fast).
|
|
|
|
#### Property Directives for Indicators
|
|
|
|
```mql4
|
|
#property indicator_chart_window // Draw on main chart
|
|
// OR
|
|
#property indicator_separate_window // Draw in separate sub-window
|
|
|
|
#property indicator_buffers 2 // Number of visible plot buffers
|
|
#property indicator_color1 clrDodgerBlue // Color for buffer 0
|
|
#property indicator_color2 clrRed // Color for buffer 1
|
|
#property indicator_width1 2 // Line width for buffer 0
|
|
#property indicator_width2 1 // Line width for buffer 1
|
|
#property indicator_style1 STYLE_SOLID // Line style for buffer 0
|
|
#property indicator_style2 STYLE_DOT // Line style for buffer 1
|
|
|
|
// For separate window indicators
|
|
#property indicator_minimum 0 // Minimum scale
|
|
#property indicator_maximum 100 // Maximum scale
|
|
#property indicator_level1 30 // Horizontal level line
|
|
#property indicator_level2 70 // Another level line
|
|
#property indicator_levelcolor clrGray // Level line color
|
|
#property indicator_levelstyle STYLE_DOT // Level line style
|
|
```
|
|
|
|
**Important:** `#property indicator_buffers N` sets the number of **plotted** (visible) buffers. If you need additional calculation buffers that are not drawn, use `IndicatorBuffers(total)` in `OnInit()` to set the **total** number of buffers (plotted + calculation). The total must be >= the `#property indicator_buffers` value.
|
|
|
|
```mql4
|
|
#property indicator_buffers 2 // 2 visible plots
|
|
|
|
double PlotBuffer1[]; // Visible buffer 0
|
|
double PlotBuffer2[]; // Visible buffer 1
|
|
double CalcBuffer[]; // Hidden calculation buffer
|
|
|
|
int OnInit()
|
|
{
|
|
IndicatorBuffers(3); // Total = 2 visible + 1 calculation
|
|
|
|
SetIndexBuffer(0, PlotBuffer1);
|
|
SetIndexBuffer(1, PlotBuffer2);
|
|
SetIndexBuffer(2, CalcBuffer); // Not plotted (index >= indicator_buffers)
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
```
|
|
|
|
#### Draw Styles
|
|
|
|
| Constant | Description |
|
|
|----------|-------------|
|
|
| `DRAW_LINE` | Simple line connecting buffer values |
|
|
| `DRAW_HISTOGRAM` | Vertical bars from zero line to buffer value |
|
|
| `DRAW_ARROW` | Symbols/arrows at buffer values |
|
|
| `DRAW_NONE` | Not drawn (for calculation buffers or when using `IndicatorBuffers`) |
|
|
| `DRAW_SECTION` | Line segments between non-empty values |
|
|
| `DRAW_ZIGZAG` | Zigzag line (requires two buffers) |
|
|
|
|
#### Full Indicator Template
|
|
|
|
```mql4
|
|
//+------------------------------------------------------------------+
|
|
//| MyIndicator.mq4 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Author"
|
|
#property link "https://www.example.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#property indicator_separate_window
|
|
#property indicator_buffers 2
|
|
#property indicator_color1 clrDodgerBlue
|
|
#property indicator_color2 clrRed
|
|
#property indicator_width1 2
|
|
#property indicator_width2 1
|
|
#property indicator_level1 30
|
|
#property indicator_level2 70
|
|
#property indicator_minimum 0
|
|
#property indicator_maximum 100
|
|
|
|
//--- Input parameters
|
|
input int InpPeriod = 14; // Period
|
|
|
|
//--- Indicator buffers
|
|
double MainBuffer[];
|
|
double SignalBuffer[];
|
|
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Bind arrays to indicator buffers
|
|
SetIndexBuffer(0, MainBuffer);
|
|
SetIndexBuffer(1, SignalBuffer);
|
|
|
|
// Set drawing styles
|
|
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2);
|
|
SetIndexStyle(1, DRAW_LINE, STYLE_DOT, 1);
|
|
|
|
// Set labels (shown in Data Window)
|
|
SetIndexLabel(0, "Main");
|
|
SetIndexLabel(1, "Signal");
|
|
|
|
// Set indicator name in sub-window
|
|
IndicatorShortName("MyIndicator(" + IntegerToString(InpPeriod) + ")");
|
|
|
|
// Set how many initial bars to skip
|
|
SetIndexDrawBegin(0, InpPeriod);
|
|
SetIndexDrawBegin(1, InpPeriod);
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OnCalculate - called on every tick and on history load |
|
|
//| |
|
|
//| rates_total - total number of bars available |
|
|
//| prev_calculated - bars calculated on previous call (0 on first) |
|
|
//| time[] - bar open times |
|
|
//| open[] - bar open prices |
|
|
//| high[] - bar high prices |
|
|
//| low[] - bar low prices |
|
|
//| close[] - bar close prices |
|
|
//| tick_volume[] - tick volumes |
|
|
//| volume[] - real volumes |
|
|
//| spread[] - spreads |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
// Insufficient bars
|
|
if(rates_total < InpPeriod) return 0;
|
|
|
|
// Determine starting index
|
|
int start;
|
|
if(prev_calculated == 0)
|
|
start = InpPeriod; // First calculation
|
|
else
|
|
start = prev_calculated - 1; // Recalculate only new bars
|
|
|
|
// Main calculation loop (oldest to newest)
|
|
for(int i = start; i < rates_total; i++)
|
|
{
|
|
// Example: simple calculation
|
|
double sum = 0;
|
|
for(int j = 0; j < InpPeriod; j++)
|
|
sum += close[i - j];
|
|
|
|
MainBuffer[i] = sum / InpPeriod;
|
|
SignalBuffer[i] = MainBuffer[i] * 0.95;
|
|
}
|
|
|
|
return rates_total; // Return for next prev_calculated
|
|
}
|
|
```
|
|
|
|
#### SetIndexBuffer / SetIndexStyle / SetIndexLabel
|
|
|
|
```mql4
|
|
// bool SetIndexBuffer(int index, double array[])
|
|
// Binds an array to an indicator buffer at the given index.
|
|
SetIndexBuffer(0, MainBuffer);
|
|
|
|
// void SetIndexStyle(int index, int type, int style=EMPTY, int width=EMPTY, color clr=CLR_NONE)
|
|
// type: DRAW_LINE, DRAW_HISTOGRAM, DRAW_ARROW, DRAW_NONE, etc.
|
|
// style: STYLE_SOLID, STYLE_DASH, STYLE_DOT, STYLE_DASHDOT, STYLE_DASHDOTDOT
|
|
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, clrBlue);
|
|
|
|
// void SetIndexLabel(int index, string text)
|
|
// Sets the label shown in the Data Window. Use NULL to hide.
|
|
SetIndexLabel(0, "Fast MA");
|
|
SetIndexLabel(1, NULL); // Hidden from Data Window
|
|
|
|
// void SetIndexArrow(int index, int code)
|
|
// Sets the Wingdings symbol code for DRAW_ARROW style.
|
|
SetIndexStyle(2, DRAW_ARROW);
|
|
SetIndexArrow(2, 233); // Up arrow
|
|
SetIndexArrow(3, 234); // Down arrow
|
|
|
|
// void SetIndexDrawBegin(int index, int begin)
|
|
// Sets the bar number from which drawing starts.
|
|
SetIndexDrawBegin(0, InpPeriod);
|
|
|
|
// void SetIndexEmptyValue(int index, double value)
|
|
// Sets the value considered "empty" (not drawn). Default is EMPTY_VALUE.
|
|
SetIndexEmptyValue(0, 0.0);
|
|
```
|
|
|
|
---
|
|
|
|
### Scripts
|
|
|
|
Execute once and terminate. Can trade. Useful for one-time operations.
|
|
|
|
```mql4
|
|
//+------------------------------------------------------------------+
|
|
//| CloseAll.mq4 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Author"
|
|
#property link "https://www.example.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
#property show_inputs // Show input dialog before running
|
|
|
|
input int InpMagicNumber = 0; // Magic Number (0 = all)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script start function - called once when script is launched |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
int closed = 0;
|
|
|
|
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderSymbol() != _Symbol) continue;
|
|
if(InpMagicNumber != 0 && OrderMagicNumber() != InpMagicNumber) continue;
|
|
|
|
bool result = false;
|
|
RefreshRates();
|
|
|
|
if(OrderType() == OP_BUY)
|
|
result = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed);
|
|
else if(OrderType() == OP_SELL)
|
|
result = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrRed);
|
|
else
|
|
result = OrderDelete(OrderTicket());
|
|
|
|
if(result) closed++;
|
|
else Print("Failed to close order #", OrderTicket(), " Error: ", GetLastError());
|
|
}
|
|
|
|
Print("Closed ", closed, " orders");
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Libraries
|
|
|
|
Reusable function collections. Cannot run independently.
|
|
|
|
```mql4
|
|
//+------------------------------------------------------------------+
|
|
//| TradeLib.mq4 |
|
|
//+------------------------------------------------------------------+
|
|
#property library
|
|
#property copyright "Copyright 2024, Author"
|
|
#property strict
|
|
|
|
//--- Exported function (callable from other programs)
|
|
double CalculateLotSize(double riskPercent, double stopLossPips) export
|
|
{
|
|
double accountRisk = AccountBalance() * riskPercent / 100.0;
|
|
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
|
|
double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
|
|
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
|
|
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
|
|
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
|
|
|
|
if(tickValue == 0 || stopLossPips == 0) return minLot;
|
|
|
|
double lots = accountRisk / (stopLossPips * (tickValue / tickSize));
|
|
lots = MathFloor(lots / lotStep) * lotStep;
|
|
lots = MathMax(minLot, MathMin(maxLot, lots));
|
|
|
|
return NormalizeDouble(lots, 2);
|
|
}
|
|
```
|
|
|
|
#### Importing a Library
|
|
|
|
```mql4
|
|
// Import from compiled .ex4 library
|
|
#import "TradeLib.ex4"
|
|
double CalculateLotSize(double riskPercent, double stopLossPips);
|
|
#import
|
|
|
|
// Import from Windows DLL
|
|
#import "user32.dll"
|
|
int MessageBoxW(int hWnd, string text, string caption, int type);
|
|
#import
|
|
|
|
// Usage
|
|
void OnTick()
|
|
{
|
|
double lots = CalculateLotSize(2.0, 50);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Predefined Variables
|
|
|
|
These are built-in variables updated by the terminal. Available in all program types.
|
|
|
|
| Variable | Type | Description |
|
|
|----------|------|-------------|
|
|
| `Ask` | `double` | Current ask price (buy price) |
|
|
| `Bid` | `double` | Current bid price (sell price) |
|
|
| `Bars` | `int` | Number of bars on the current chart |
|
|
| `Point` | `double` | Point size (0.00001 for 5-digit, 0.0001 for 4-digit) |
|
|
| `Digits` | `int` | Number of decimal places (5 or 3 for 5-digit brokers) |
|
|
| `_Symbol` | `string` | Current chart symbol (same as `Symbol()`) |
|
|
| `_Period` | `int` | Current chart timeframe in minutes (same as `Period()`) |
|
|
| `Open[]` | `double` | Array of bar open prices |
|
|
| `High[]` | `double` | Array of bar high prices |
|
|
| `Low[]` | `double` | Array of bar low prices |
|
|
| `Close[]` | `double` | Array of bar close prices |
|
|
| `Time[]` | `datetime` | Array of bar open times |
|
|
| `Volume[]` | `long` | Array of bar tick volumes |
|
|
|
|
**Important:** The series arrays (`Open[]`, `High[]`, `Low[]`, `Close[]`, `Time[]`, `Volume[]`) use reverse indexing: **index 0 = the newest (current) bar**. Index 1 = previous bar, etc.
|
|
|
|
```mql4
|
|
double currentClose = Close[0]; // Current bar's close
|
|
double previousHigh = High[1]; // Previous bar's high
|
|
datetime barTime = Time[0]; // Current bar's open time
|
|
double currentSpread = Ask - Bid; // Current spread
|
|
|
|
// IMPORTANT: Call RefreshRates() before using Ask/Bid in order functions
|
|
// to ensure you have the latest prices.
|
|
RefreshRates();
|
|
double freshAsk = Ask;
|
|
double freshBid = Bid;
|
|
```
|
|
|
|
---
|
|
|
|
## Technical Indicator Functions
|
|
|
|
All built-in indicator functions follow the pattern:
|
|
`iFunction(symbol, timeframe, ...parameters, shift)`
|
|
|
|
- `symbol`: Use `NULL` or `_Symbol` for the current chart symbol.
|
|
- `timeframe`: Use `0` or `PERIOD_CURRENT` for the current chart timeframe.
|
|
- `shift`: Bar index (0 = current bar, 1 = previous bar, etc.).
|
|
|
|
### Moving Average - iMA
|
|
|
|
```mql4
|
|
double iMA(
|
|
string symbol, // Symbol name
|
|
int timeframe, // Timeframe (PERIOD_*)
|
|
int period, // Averaging period
|
|
int ma_shift, // Horizontal shift (bars)
|
|
int ma_method, // MA method (MODE_SMA, etc.)
|
|
int applied_price, // Applied price (PRICE_CLOSE, etc.)
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double sma20 = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
|
|
double ema50 = iMA(NULL, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE, 1);
|
|
```
|
|
|
|
### Relative Strength Index - iRSI
|
|
|
|
```mql4
|
|
double iRSI(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
int period, // Averaging period
|
|
int applied_price, // Applied price
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 0);
|
|
if(rsi < 30) Print("Oversold");
|
|
if(rsi > 70) Print("Overbought");
|
|
```
|
|
|
|
### MACD - iMACD
|
|
|
|
```mql4
|
|
double iMACD(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
int fast_ema_period, // Fast EMA period (typically 12)
|
|
int slow_ema_period, // Slow EMA period (typically 26)
|
|
int signal_period, // Signal line period (typically 9)
|
|
int applied_price, // Applied price
|
|
int mode, // Line index: MODE_MAIN or MODE_SIGNAL
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double macdMain = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 0);
|
|
double macdSignal = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, 0);
|
|
|
|
if(macdMain > macdSignal) Print("Bullish crossover");
|
|
```
|
|
|
|
### Stochastic Oscillator - iStochastic
|
|
|
|
```mql4
|
|
double iStochastic(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
int Kperiod, // %K period
|
|
int Dperiod, // %D period (signal)
|
|
int slowing, // Slowing
|
|
int method, // MA method for smoothing
|
|
int price_field, // Price field: 0 = Low/High, 1 = Close/Close
|
|
int mode, // MODE_MAIN (%K) or MODE_SIGNAL (%D)
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double stochK = iStochastic(NULL, 0, 5, 3, 3, MODE_SMA, 0, MODE_MAIN, 0);
|
|
double stochD = iStochastic(NULL, 0, 5, 3, 3, MODE_SMA, 0, MODE_SIGNAL, 0);
|
|
```
|
|
|
|
### Bollinger Bands - iBands
|
|
|
|
```mql4
|
|
double iBands(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
int period, // Averaging period
|
|
double deviation, // Standard deviation multiplier
|
|
int bands_shift, // Horizontal shift (bars)
|
|
int applied_price, // Applied price
|
|
int mode, // MODE_MAIN (middle), MODE_UPPER, MODE_LOWER
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double upper = iBands(NULL, 0, 20, 2.0, 0, PRICE_CLOSE, MODE_UPPER, 0);
|
|
double middle = iBands(NULL, 0, 20, 2.0, 0, PRICE_CLOSE, MODE_MAIN, 0);
|
|
double lower = iBands(NULL, 0, 20, 2.0, 0, PRICE_CLOSE, MODE_LOWER, 0);
|
|
```
|
|
|
|
### Average True Range - iATR
|
|
|
|
```mql4
|
|
double iATR(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
int period, // Averaging period
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example
|
|
double atr = iATR(NULL, 0, 14, 0);
|
|
double dynamicSL = NormalizeDouble(Ask - atr * 1.5, Digits);
|
|
```
|
|
|
|
### Custom Indicator - iCustom
|
|
|
|
```mql4
|
|
double iCustom(
|
|
string symbol, // Symbol
|
|
int timeframe, // Timeframe
|
|
string name, // Custom indicator file name (without .ex4)
|
|
... // Indicator input parameters (in order)
|
|
int mode, // Buffer index (0-based)
|
|
int shift // Bar index
|
|
);
|
|
|
|
// Example: Call a custom indicator "SuperTrend" with inputs (10, 3.0)
|
|
double superTrend = iCustom(NULL, 0, "SuperTrend", 10, 3.0, 0, 0);
|
|
|
|
// The parameter order must match the indicator's input parameters exactly.
|
|
// mode corresponds to the SetIndexBuffer() index in the indicator.
|
|
```
|
|
|
|
### MA Method Constants
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `MODE_SMA` | 0 | Simple Moving Average |
|
|
| `MODE_EMA` | 1 | Exponential Moving Average |
|
|
| `MODE_SMMA` | 2 | Smoothed Moving Average |
|
|
| `MODE_LWMA` | 3 | Linear Weighted Moving Average |
|
|
|
|
### Applied Price Constants
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `PRICE_CLOSE` | 0 | Close price |
|
|
| `PRICE_OPEN` | 1 | Open price |
|
|
| `PRICE_HIGH` | 2 | High price |
|
|
| `PRICE_LOW` | 3 | Low price |
|
|
| `PRICE_MEDIAN` | 4 | (High + Low) / 2 |
|
|
| `PRICE_TYPICAL` | 5 | (High + Low + Close) / 3 |
|
|
| `PRICE_WEIGHTED` | 6 | (High + Low + Close + Close) / 4 |
|
|
|
|
### Timeframe Constants
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `PERIOD_CURRENT` | 0 | Current chart timeframe |
|
|
| `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 hours |
|
|
| `PERIOD_D1` | 1440 | Daily |
|
|
| `PERIOD_W1` | 10080 | Weekly |
|
|
| `PERIOD_MN1` | 43200 | Monthly |
|
|
|
|
---
|
|
|
|
## Order Management
|
|
|
|
### Order Types
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `OP_BUY` | 0 | Market buy order |
|
|
| `OP_SELL` | 1 | Market sell order |
|
|
| `OP_BUYLIMIT` | 2 | Buy limit pending order (below market) |
|
|
| `OP_SELLLIMIT` | 3 | Sell limit pending order (above market) |
|
|
| `OP_BUYSTOP` | 4 | Buy stop pending order (above market) |
|
|
| `OP_SELLSTOP` | 5 | Sell stop pending order (below market) |
|
|
|
|
### Trading Functions
|
|
|
|
```mql4
|
|
// OrderSend - Returns ticket on success, -1 on failure
|
|
int OrderSend(string symbol, int cmd, double volume, double price,
|
|
int slippage, double stoploss, double takeprofit,
|
|
string comment, int magic, datetime expiration, color arrow_color);
|
|
|
|
// OrderModify - Returns true on success
|
|
bool OrderModify(int ticket, double price, double stoploss,
|
|
double takeprofit, datetime expiration, color arrow_color);
|
|
|
|
// OrderClose - Close market order (can be partial)
|
|
bool OrderClose(int ticket, double lots, double price, int slippage, color Color);
|
|
|
|
// OrderDelete - Delete pending order only
|
|
bool OrderDelete(int ticket, color Color);
|
|
|
|
// OrderSelect - Must call before reading order properties
|
|
bool OrderSelect(int index, int select, int pool);
|
|
// select: SELECT_BY_POS or SELECT_BY_TICKET
|
|
// pool: MODE_TRADES or MODE_HISTORY
|
|
|
|
int OrdersTotal(); // Open + pending count
|
|
int OrdersHistoryTotal(); // Closed + deleted count
|
|
```
|
|
|
|
### Order Information Functions
|
|
|
|
After `OrderSelect()`, these return info about the selected order:
|
|
|
|
| Function | Return | Description |
|
|
|----------|--------|-------------|
|
|
| `OrderTicket()` | `int` | Ticket number |
|
|
| `OrderType()` | `int` | Order type (OP_BUY, etc.) |
|
|
| `OrderLots()` | `double` | Volume |
|
|
| `OrderOpenPrice()` | `double` | Open price |
|
|
| `OrderClosePrice()` | `double` | Close price (0 if open) |
|
|
| `OrderOpenTime()` | `datetime` | Open time |
|
|
| `OrderCloseTime()` | `datetime` | Close time (0 if open) |
|
|
| `OrderStopLoss()` | `double` | Stop loss |
|
|
| `OrderTakeProfit()` | `double` | Take profit |
|
|
| `OrderMagicNumber()` | `int` | Magic number |
|
|
| `OrderComment()` | `string` | Comment |
|
|
| `OrderSymbol()` | `string` | Symbol |
|
|
| `OrderProfit()` | `double` | Net profit |
|
|
| `OrderCommission()` | `double` | Commission |
|
|
| `OrderSwap()` | `double` | Swap |
|
|
| `OrderExpiration()` | `datetime` | Expiration |
|
|
|
|
> **Production patterns** (retry logic, order loops, close all, error handling): See [trading-operations.md](trading-operations.md)
|
|
|
|
---
|
|
|
|
## Market Information
|
|
|
|
### MarketInfo
|
|
|
|
```mql4
|
|
double MarketInfo(string symbol, int type);
|
|
```
|
|
|
|
| Constant | Description |
|
|
|----------|-------------|
|
|
| `MODE_SPREAD` | Spread in points |
|
|
| `MODE_STOPLEVEL` | Minimum stop level in points |
|
|
| `MODE_LOTSIZE` | Contract size (e.g., 100000 for forex) |
|
|
| `MODE_TICKVALUE` | Tick value in account currency |
|
|
| `MODE_TICKSIZE` | Tick size (minimum price change) |
|
|
| `MODE_SWAPLONG` | Swap for long positions |
|
|
| `MODE_SWAPSHORT` | Swap for short positions |
|
|
| `MODE_MINLOT` | Minimum lot size |
|
|
| `MODE_LOTSTEP` | Lot size step |
|
|
| `MODE_MAXLOT` | Maximum lot size |
|
|
| `MODE_MARGINREQUIRED` | Margin required for 1 lot |
|
|
| `MODE_DIGITS` | Number of decimal digits |
|
|
| `MODE_POINT` | Point size |
|
|
| `MODE_FREEZELEVEL` | Freeze distance in points (cannot modify orders within this distance) |
|
|
|
|
```mql4
|
|
double spread = MarketInfo(_Symbol, MODE_SPREAD);
|
|
double stopLevel = MarketInfo(_Symbol, MODE_STOPLEVEL);
|
|
double minLot = MarketInfo(_Symbol, MODE_MINLOT);
|
|
double lotStep = MarketInfo(_Symbol, MODE_LOTSTEP);
|
|
double maxLot = MarketInfo(_Symbol, MODE_MAXLOT);
|
|
double tickVal = MarketInfo(_Symbol, MODE_TICKVALUE);
|
|
double tickSize = MarketInfo(_Symbol, MODE_TICKSIZE);
|
|
double margin1 = MarketInfo(_Symbol, MODE_MARGINREQUIRED);
|
|
int digits = (int)MarketInfo(_Symbol, MODE_DIGITS);
|
|
double point = MarketInfo(_Symbol, MODE_POINT);
|
|
```
|
|
|
|
### SymbolInfoDouble (Modern Replacement)
|
|
|
|
```mql4
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
|
|
long digits = SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
|
|
long stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
|
|
```
|
|
|
|
---
|
|
|
|
## Account Functions
|
|
|
|
| Function | Return Type | Description |
|
|
|----------|-------------|-------------|
|
|
| `AccountBalance()` | `double` | Account balance |
|
|
| `AccountEquity()` | `double` | Account equity (balance + floating P/L) |
|
|
| `AccountFreeMargin()` | `double` | Free margin available |
|
|
| `AccountMargin()` | `double` | Margin currently used |
|
|
| `AccountProfit()` | `double` | Total floating profit/loss |
|
|
| `AccountCurrency()` | `string` | Account currency (e.g., "USD") |
|
|
| `AccountNumber()` | `int` | Account number |
|
|
| `AccountCompany()` | `string` | Broker company name |
|
|
| `AccountLeverage()` | `int` | Account leverage (e.g., 100) |
|
|
| `AccountName()` | `string` | Account holder name |
|
|
| `AccountServer()` | `string` | Trade server name |
|
|
| `AccountStopoutLevel()` | `int` | Stop-out level (margin %) |
|
|
| `AccountStopoutMode()` | `int` | Stop-out mode (0=percent, 1=money) |
|
|
| `AccountInfoDouble(prop)` | `double` | Modern replacement |
|
|
| `AccountInfoInteger(prop)` | `long` | Modern replacement |
|
|
| `AccountInfoString(prop)` | `string` | Modern replacement |
|
|
|
|
```mql4
|
|
// Risk calculation example
|
|
double riskPercent = 2.0;
|
|
double balance = AccountBalance();
|
|
double riskAmount = balance * riskPercent / 100.0;
|
|
|
|
Print("Account: ", AccountNumber(), " at ", AccountCompany());
|
|
Print("Balance: ", balance, " ", AccountCurrency());
|
|
Print("Equity: ", AccountEquity());
|
|
Print("Margin: ", AccountMargin());
|
|
Print("Free: ", AccountFreeMargin());
|
|
Print("Leverage: 1:", AccountLeverage());
|
|
```
|
|
|
|
---
|
|
|
|
## Preprocessor Directives
|
|
|
|
### #property
|
|
|
|
```mql4
|
|
// Common EA/indicator/script properties
|
|
#property copyright "Copyright 2024, Author"
|
|
#property link "https://www.example.com"
|
|
#property version "1.00"
|
|
#property description "My Expert Advisor"
|
|
#property strict // Enable strict compilation mode (recommended)
|
|
|
|
// Indicator-specific
|
|
#property indicator_chart_window
|
|
#property indicator_separate_window
|
|
#property indicator_buffers 3
|
|
#property indicator_color1 clrBlue
|
|
#property indicator_color2 clrRed
|
|
#property indicator_color3 clrGreen
|
|
#property indicator_width1 2
|
|
#property indicator_style1 STYLE_SOLID
|
|
#property indicator_minimum 0
|
|
#property indicator_maximum 100
|
|
#property indicator_level1 20
|
|
#property indicator_level2 80
|
|
#property indicator_levelcolor clrSilver
|
|
|
|
// Script-specific
|
|
#property show_inputs // Show inputs dialog
|
|
#property show_confirm // Show confirmation dialog
|
|
|
|
// Library-specific
|
|
#property library // Mark as library
|
|
```
|
|
|
|
### #include
|
|
|
|
```mql4
|
|
// Include from MQL4/Include/ directory
|
|
#include <stdlib.mqh> // Standard library (ErrorDescription, etc.)
|
|
#include <stderror.mqh> // Error code constants
|
|
|
|
// Include from same directory as the source file
|
|
#include "MyHelpers.mqh"
|
|
|
|
// Include guards (manual, MQL4 has no #pragma once)
|
|
#ifndef MY_HELPERS_MQH
|
|
#define MY_HELPERS_MQH
|
|
// ... header content ...
|
|
#endif
|
|
```
|
|
|
|
### #define
|
|
|
|
```mql4
|
|
// Simple constants
|
|
#define EA_NAME "SuperScalper"
|
|
#define EA_VERSION "2.1"
|
|
#define MAGIC 20240115
|
|
|
|
// Macros with parameters
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
#define ABS(x) ((x) >= 0 ? (x) : -(x))
|
|
#define PIP(x) ((x) * g_pipSize)
|
|
|
|
// Multi-line macro (use backslash)
|
|
#define LOG(msg) \
|
|
Print(__FILE__, " Line ", __LINE__, ": ", msg)
|
|
|
|
// Predefined macros
|
|
// __FILE__ - Current file name
|
|
// __LINE__ - Current line number
|
|
// __FUNCTION__ - Current function name
|
|
// __DATETIME__ - Compilation date/time
|
|
// __MQLBUILD__ - MQL compiler build number
|
|
```
|
|
|
|
### #import
|
|
|
|
```mql4
|
|
// Import from compiled MQL4 library (.ex4)
|
|
#import "MyLibrary.ex4"
|
|
double CalculateRisk(double percent, int stopPoints);
|
|
int CountSignals(string symbol, int timeframe);
|
|
#import
|
|
|
|
// Import from Windows DLL
|
|
#import "kernel32.dll"
|
|
int GetTickCount();
|
|
void Sleep(int milliseconds);
|
|
#import
|
|
|
|
#import "user32.dll"
|
|
int MessageBoxW(int hWnd, string text, string caption, int type);
|
|
#import
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Error Functions
|
|
|
|
```mql4
|
|
// int GetLastError()
|
|
// Returns the last error code and resets the internal error variable.
|
|
int err = GetLastError();
|
|
|
|
// void ResetLastError()
|
|
// Resets the error variable to ERR_NO_ERROR (0).
|
|
ResetLastError();
|
|
|
|
// int _LastError
|
|
// Predefined variable holding the last error code (NOT reset by reading).
|
|
|
|
// string ErrorDescription(int error_code)
|
|
// Requires: #include <stdlib.mqh>
|
|
#include <stdlib.mqh>
|
|
string desc = ErrorDescription(GetLastError());
|
|
```
|
|
|
|
### Trade Error Codes
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `ERR_NO_ERROR` | 0 | No error |
|
|
| `ERR_NO_RESULT` | 1 | No error but result unknown |
|
|
| `ERR_COMMON_ERROR` | 2 | Common error |
|
|
| `ERR_INVALID_TRADE_PARAMETERS` | 3 | Invalid trade parameters |
|
|
| `ERR_SERVER_BUSY` | 4 | Trade server is busy |
|
|
| `ERR_OLD_VERSION` | 5 | Old client terminal version |
|
|
| `ERR_NO_CONNECTION` | 6 | No connection to server |
|
|
| `ERR_NOT_ENOUGH_RIGHTS` | 7 | Insufficient rights |
|
|
| `ERR_TOO_FREQUENT_REQUESTS` | 8 | Too frequent requests |
|
|
| `ERR_MALFUNCTIONAL_TRADE` | 9 | Malfunctional trade operation |
|
|
| `ERR_ACCOUNT_DISABLED` | 64 | Account disabled |
|
|
| `ERR_INVALID_ACCOUNT` | 65 | Invalid account |
|
|
| `ERR_TRADE_TIMEOUT` | 128 | Trade timeout |
|
|
| `ERR_INVALID_PRICE` | 129 | Invalid price |
|
|
| `ERR_INVALID_STOPS` | 130 | Invalid stops |
|
|
| `ERR_INVALID_TRADE_VOLUME` | 131 | Invalid lot size |
|
|
| `ERR_MARKET_CLOSED` | 132 | Market closed |
|
|
| `ERR_TRADE_DISABLED` | 133 | Trading disabled |
|
|
| `ERR_NOT_ENOUGH_MONEY` | 134 | Not enough money |
|
|
| `ERR_PRICE_CHANGED` | 135 | Price changed (requote) |
|
|
| `ERR_OFF_QUOTES` | 136 | Off quotes |
|
|
| `ERR_BROKER_BUSY` | 137 | Broker busy |
|
|
| `ERR_REQUOTE` | 138 | Requote |
|
|
| `ERR_ORDER_LOCKED` | 139 | Order locked |
|
|
| `ERR_LONG_POSITIONS_ONLY_ALLOWED` | 140 | Long positions only |
|
|
| `ERR_TOO_MANY_REQUESTS` | 141 | Too many requests |
|
|
| `ERR_TRADE_MODIFY_DENIED` | 145 | Modification denied (too close to market) |
|
|
| `ERR_TRADE_CONTEXT_BUSY` | 146 | Trade context busy |
|
|
| `ERR_TRADE_EXPIRATION_DENIED` | 147 | Expiration denied by broker |
|
|
| `ERR_TRADE_TOO_MANY_ORDERS` | 148 | Too many open orders |
|
|
| `ERR_TRADE_HEDGE_PROHIBITED` | 149 | Hedging prohibited |
|
|
| `ERR_TRADE_PROHIBITED_BY_FIFO` | 150 | FIFO rule violation |
|
|
|
|
### Runtime Error Codes
|
|
|
|
| Constant | Value | Description |
|
|
|----------|-------|-------------|
|
|
| `ERR_NO_MQLERROR` | 4000 | No MQL error |
|
|
| `ERR_WRONG_FUNCTION_POINTER` | 4001 | Wrong function pointer |
|
|
| `ERR_ARRAY_INDEX_OUT_OF_RANGE` | 4002 | Array index out of range |
|
|
| `ERR_NO_MEMORY_FOR_CALL_STACK` | 4003 | No memory for function call stack |
|
|
| `ERR_RECURSIVE_STACK_OVERFLOW` | 4004 | Recursive stack overflow |
|
|
| `ERR_NOT_ENOUGH_STACK_FOR_PARAM` | 4005 | Not enough stack for parameter |
|
|
| `ERR_NO_MEMORY_FOR_PARAM_STRING` | 4006 | No memory for parameter string |
|
|
| `ERR_NO_MEMORY_FOR_TEMP_STRING` | 4007 | No memory for temp string |
|
|
| `ERR_NOT_INITIALIZED_STRING` | 4008 | Not initialized string |
|
|
| `ERR_NOT_INITIALIZED_ARRAYSTRING` | 4009 | Not initialized string array |
|
|
| `ERR_NO_MEMORY_FOR_ARRAYSTRING` | 4010 | No memory for string array |
|
|
| `ERR_TOO_LONG_STRING` | 4011 | String too long |
|
|
| `ERR_ZERO_DIVIDE` | 4013 | Division by zero |
|
|
| `ERR_UNKNOWN_COMMAND` | 4014 | Unknown command |
|
|
| `ERR_WRONG_JUMP` | 4015 | Wrong jump |
|
|
| `ERR_NOT_INITIALIZED_ARRAY` | 4016 | Array not initialized |
|
|
| `ERR_CUSTOM_INDICATOR_ERROR` | 4055 | Custom indicator error |
|
|
| `ERR_INCOMPATIBLE_ARRAYS` | 4056 | Incompatible arrays |
|
|
| `ERR_INVALID_FUNCTION_PARAMSCNT` | 4059 | Invalid function parameters count |
|
|
| `ERR_INVALID_FUNCTION_PARAMVALUE` | 4063 | Invalid function parameter value |
|
|
| `ERR_STRING_FUNCTION_INTERNAL` | 4062 | String function internal error |
|
|
| `ERR_ARRAY_AS_PARAMETER_EXPECTED` | 4065 | Array as parameter expected |
|
|
| `ERR_NO_ORDER_SELECTED` | 4105 | No order selected |
|
|
| `ERR_UNKNOWN_SYMBOL` | 4106 | Unknown symbol |
|
|
| `ERR_INVALID_PRICE_PARAM` | 4107 | Invalid price parameter |
|
|
| `ERR_INVALID_TICKET` | 4108 | Invalid ticket |
|
|
| `ERR_TRADE_NOT_ALLOWED` | 4109 | Trade not allowed (EA or AutoTrading disabled) |
|
|
| `ERR_LONGS_NOT_ALLOWED` | 4110 | Longs not allowed |
|
|
| `ERR_SHORTS_NOT_ALLOWED` | 4111 | Shorts not allowed |
|
|
| `ERR_OBJECT_ALREADY_EXISTS` | 4200 | Object already exists |
|
|
| `ERR_UNKNOWN_OBJECT_PROPERTY` | 4201 | Unknown object property |
|
|
| `ERR_OBJECT_DOES_NOT_EXIST` | 4202 | Object does not exist |
|
|
| `ERR_UNKNOWN_OBJECT_TYPE` | 4203 | Unknown object type |
|
|
|
|
### Robust Error Handling Pattern with Retry Logic
|
|
|
|
```mql4
|
|
#include <stdlib.mqh>
|
|
|
|
int SendOrderWithRetry(string symbol, int cmd, double volume, double price,
|
|
int slippage, double sl, double tp, string comment,
|
|
int magic, int maxRetries = 5)
|
|
{
|
|
int ticket = -1;
|
|
|
|
for(int attempt = 0; attempt < maxRetries; attempt++)
|
|
{
|
|
ResetLastError();
|
|
RefreshRates();
|
|
|
|
// Update price for market orders
|
|
if(cmd == OP_BUY) price = MarketInfo(symbol, MODE_ASK);
|
|
if(cmd == OP_SELL) price = MarketInfo(symbol, MODE_BID);
|
|
|
|
ticket = OrderSend(symbol, cmd, volume, price, slippage,
|
|
sl, tp, comment, magic, 0, clrGreen);
|
|
|
|
if(ticket >= 0)
|
|
{
|
|
Print("Order sent successfully. Ticket: ", ticket);
|
|
return ticket;
|
|
}
|
|
|
|
int err = GetLastError();
|
|
Print("OrderSend attempt ", attempt + 1, " failed. Error ", err,
|
|
": ", ErrorDescription(err));
|
|
|
|
switch(err)
|
|
{
|
|
case ERR_NO_ERROR:
|
|
return ticket;
|
|
|
|
// Retriable errors
|
|
case ERR_SERVER_BUSY:
|
|
case ERR_TRADE_TIMEOUT:
|
|
case ERR_PRICE_CHANGED:
|
|
case ERR_REQUOTE:
|
|
case ERR_OFF_QUOTES:
|
|
case ERR_BROKER_BUSY:
|
|
case ERR_TRADE_CONTEXT_BUSY:
|
|
case ERR_TOO_FREQUENT_REQUESTS:
|
|
case ERR_TOO_MANY_REQUESTS:
|
|
Sleep(1000 * (attempt + 1)); // Progressive delay
|
|
break;
|
|
|
|
// Fatal errors - stop retrying
|
|
case ERR_INVALID_TRADE_PARAMETERS:
|
|
case ERR_INVALID_STOPS:
|
|
case ERR_INVALID_TRADE_VOLUME:
|
|
case ERR_NOT_ENOUGH_MONEY:
|
|
case ERR_TRADE_DISABLED:
|
|
case ERR_MARKET_CLOSED:
|
|
case ERR_ACCOUNT_DISABLED:
|
|
case ERR_TRADE_NOT_ALLOWED:
|
|
Print("Fatal trade error. Aborting.");
|
|
return -1;
|
|
|
|
default:
|
|
Sleep(500);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Print("OrderSend failed after ", maxRetries, " attempts");
|
|
return -1;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Common Gotchas
|
|
|
|
### 1. Double Comparison with NormalizeDouble
|
|
|
|
Floating-point numbers cannot be compared directly due to precision issues.
|
|
|
|
```mql4
|
|
// WRONG: Direct comparison
|
|
if(price1 == price2) // May fail due to floating-point precision
|
|
|
|
// CORRECT: Use NormalizeDouble
|
|
if(NormalizeDouble(price1 - price2, Digits) == 0)
|
|
|
|
// Or use a helper function
|
|
bool IsEqual(double a, double b, int digits)
|
|
{
|
|
return NormalizeDouble(a - b, digits) == 0;
|
|
}
|
|
|
|
bool IsGreater(double a, double b, int digits)
|
|
{
|
|
return NormalizeDouble(a - b, digits) > 0;
|
|
}
|
|
|
|
// IMPORTANT: Always NormalizeDouble prices before using in OrderSend/OrderModify
|
|
double sl = NormalizeDouble(Ask - 50 * Point, Digits);
|
|
double tp = NormalizeDouble(Ask + 100 * Point, Digits);
|
|
```
|
|
|
|
### 2. Four-Digit vs Five-Digit Broker Detection
|
|
|
|
Some brokers use 4-digit quotes (EURUSD = 1.2345), others use 5-digit (EURUSD = 1.23456). For JPY pairs, it is 2 vs 3 digits. You must handle this for pip calculations and slippage.
|
|
|
|
```mql4
|
|
double PipSize;
|
|
int PipDigits;
|
|
int SlippagePoints;
|
|
|
|
int OnInit()
|
|
{
|
|
if(Digits == 5 || Digits == 3) // 5-digit broker
|
|
{
|
|
PipSize = Point * 10;
|
|
PipDigits = Digits - 1;
|
|
SlippagePoints = 30; // 3.0 pips
|
|
}
|
|
else // 4-digit broker
|
|
{
|
|
PipSize = Point;
|
|
PipDigits = Digits;
|
|
SlippagePoints = 3; // 3.0 pips
|
|
}
|
|
|
|
// Now use PipSize for calculations
|
|
double stopLoss = 50 * PipSize; // 50 pips regardless of broker type
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
```
|
|
|
|
### 3. Slippage in Points, Not Pips
|
|
|
|
`OrderSend()` slippage parameter is always in **points** (the smallest price unit), not pips.
|
|
|
|
```mql4
|
|
// For a 5-digit broker where 1 pip = 10 points:
|
|
// If you want 3 pips slippage, use slippage = 30
|
|
int slippage = 3; // This is 3 POINTS = 0.3 pips on 5-digit!
|
|
// Correct for 3 pips:
|
|
int slippagePips = 3;
|
|
int slippagePoints = (Digits == 5 || Digits == 3) ? slippagePips * 10 : slippagePips;
|
|
```
|
|
|
|
### 4. RefreshRates() for Stale Prices
|
|
|
|
```mql4
|
|
// After long calculations or Sleep(), Ask/Bid may be stale
|
|
Sleep(5000);
|
|
RefreshRates(); // Update Ask, Bid, and predefined arrays
|
|
double freshAsk = Ask;
|
|
```
|
|
|
|
### 5. Stop Level Violations
|
|
|
|
The broker imposes a minimum distance for stop loss and take profit from the current price.
|
|
|
|
```mql4
|
|
double stopLevel = MarketInfo(_Symbol, MODE_STOPLEVEL) * Point;
|
|
double freezeLevel = MarketInfo(_Symbol, MODE_FREEZELEVEL) * Point;
|
|
|
|
// Ensure SL/TP are far enough from the current price
|
|
double sl = Ask - 50 * Point;
|
|
if(MathAbs(Ask - sl) < stopLevel)
|
|
{
|
|
sl = NormalizeDouble(Ask - stopLevel - Point, Digits);
|
|
Print("SL adjusted to meet stop level requirement");
|
|
}
|
|
```
|
|
|
|
### 6. Trade Context Busy (IsTradeAllowed)
|
|
|
|
Only one EA can send trade requests at a time in MT4.
|
|
|
|
```mql4
|
|
// Check if trading is allowed
|
|
if(!IsTradeAllowed())
|
|
{
|
|
Print("Trade context is busy. Waiting...");
|
|
// Wait for trade context
|
|
int attempts = 0;
|
|
while(!IsTradeAllowed() && attempts < 50)
|
|
{
|
|
Sleep(100);
|
|
attempts++;
|
|
}
|
|
if(!IsTradeAllowed())
|
|
{
|
|
Print("Trade context still busy after waiting. Aborting.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Also check these conditions
|
|
if(!IsConnected()) { Print("Not connected to server"); return; }
|
|
if(!IsTradeAllowed()) { Print("AutoTrading is disabled"); return; }
|
|
if(IsStopped()) { Print("EA is being stopped"); return; }
|
|
if(!IsExpertEnabled()) { Print("Expert Advisors disabled"); return; }
|
|
```
|
|
|
|
### 7. ECN Two-Step Order Placement
|
|
|
|
ECN/STP brokers often reject orders with SL/TP set at the time of opening. You must open the order first without SL/TP, then modify.
|
|
|
|
```mql4
|
|
bool OpenOrderECN(int type, double lots, double sl, double tp,
|
|
string comment, int magic)
|
|
{
|
|
double price = (type == OP_BUY) ? Ask : Bid;
|
|
|
|
// Step 1: Open order WITHOUT SL/TP
|
|
int ticket = OrderSend(_Symbol, type, lots, price, 3,
|
|
0, 0, comment, magic, 0, clrGreen);
|
|
|
|
if(ticket < 0)
|
|
{
|
|
Print("OrderSend failed: ", GetLastError());
|
|
return false;
|
|
}
|
|
|
|
// Step 2: Modify to add SL/TP
|
|
if(sl != 0 || tp != 0)
|
|
{
|
|
sl = NormalizeDouble(sl, Digits);
|
|
tp = NormalizeDouble(tp, Digits);
|
|
|
|
if(!OrderModify(ticket, price, sl, tp, 0, clrBlue))
|
|
{
|
|
Print("OrderModify failed: ", GetLastError(),
|
|
" - Order is open but without SL/TP!");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## File Operations
|
|
|
|
### File Modes
|
|
|
|
| Constant | Description |
|
|
|----------|-------------|
|
|
| `FILE_READ` | Open for reading |
|
|
| `FILE_WRITE` | Open for writing (creates/overwrites) |
|
|
| `FILE_BIN` | Binary mode |
|
|
| `FILE_CSV` | CSV mode (comma-separated) |
|
|
| `FILE_TXT` | Text mode |
|
|
| `FILE_COMMON` | Use common data folder (shared between terminals) |
|
|
| `FILE_ANSI` | ANSI encoding |
|
|
| `FILE_UNICODE` | Unicode encoding |
|
|
|
|
**Security:** File operations are sandboxed to `MQL4/Files/` directory (or `Terminal/Common/Files/` with `FILE_COMMON`). You cannot access files outside these directories.
|
|
|
|
### File Functions
|
|
|
|
```mql4
|
|
// int FileOpen(string filename, int flags, short delimiter=';', uint codepage=CP_ACP)
|
|
// Returns file handle (>= 0) or INVALID_HANDLE (-1) on failure.
|
|
int handle = FileOpen("data.csv", FILE_WRITE|FILE_CSV, ',');
|
|
|
|
// void FileClose(int handle)
|
|
FileClose(handle);
|
|
|
|
// uint FileWrite(int handle, ...)
|
|
// Writes data to a CSV or TXT file. Returns number of bytes written.
|
|
FileWrite(handle, "Symbol", "Price", "Time");
|
|
|
|
// string FileReadString(int handle, int length=0)
|
|
string line = FileReadString(handle);
|
|
|
|
// double FileReadDouble(int handle, int size=DOUBLE_VALUE)
|
|
double value = FileReadDouble(handle);
|
|
|
|
// int FileReadInteger(int handle, int size=INT_VALUE)
|
|
int num = FileReadInteger(handle);
|
|
|
|
// bool FileIsEnding(int handle)
|
|
while(!FileIsEnding(handle))
|
|
{
|
|
string data = FileReadString(handle);
|
|
}
|
|
|
|
// bool FileDelete(string filename, int common_flag=0)
|
|
FileDelete("old_data.csv");
|
|
|
|
// bool FileIsExist(string filename, int common_flag=0)
|
|
if(FileIsExist("config.txt"))
|
|
{
|
|
// Read config
|
|
}
|
|
```
|
|
|
|
### Write CSV File Example
|
|
|
|
```mql4
|
|
void SaveTradeHistory()
|
|
{
|
|
int handle = FileOpen("trade_history.csv", FILE_WRITE|FILE_CSV, ',');
|
|
if(handle == INVALID_HANDLE)
|
|
{
|
|
Print("FileOpen failed. Error: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// Header
|
|
FileWrite(handle, "Ticket", "Symbol", "Type", "Lots",
|
|
"OpenPrice", "ClosePrice", "Profit", "OpenTime", "CloseTime");
|
|
|
|
// Data
|
|
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
|
|
if(OrderSymbol() != _Symbol) continue;
|
|
|
|
string typeStr = (OrderType() == OP_BUY) ? "BUY" : "SELL";
|
|
|
|
FileWrite(handle,
|
|
OrderTicket(),
|
|
OrderSymbol(),
|
|
typeStr,
|
|
DoubleToString(OrderLots(), 2),
|
|
DoubleToString(OrderOpenPrice(), Digits),
|
|
DoubleToString(OrderClosePrice(), Digits),
|
|
DoubleToString(OrderProfit(), 2),
|
|
TimeToString(OrderOpenTime()),
|
|
TimeToString(OrderCloseTime()));
|
|
}
|
|
|
|
FileClose(handle);
|
|
Print("Trade history saved to MQL4/Files/trade_history.csv");
|
|
}
|
|
```
|
|
|
|
### Read CSV File Example
|
|
|
|
```mql4
|
|
void LoadSettings()
|
|
{
|
|
if(!FileIsExist("settings.csv"))
|
|
{
|
|
Print("Settings file not found");
|
|
return;
|
|
}
|
|
|
|
int handle = FileOpen("settings.csv", FILE_READ|FILE_CSV, ',');
|
|
if(handle == INVALID_HANDLE)
|
|
{
|
|
Print("FileOpen failed: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
while(!FileIsEnding(handle))
|
|
{
|
|
string key = FileReadString(handle);
|
|
string value = FileReadString(handle);
|
|
Print("Setting: ", key, " = ", value);
|
|
}
|
|
|
|
FileClose(handle);
|
|
}
|
|
```
|
|
|
|
### Write/Read Binary File Example
|
|
|
|
```mql4
|
|
// Write binary
|
|
void SaveBuffer(double &buffer[], int count)
|
|
{
|
|
int handle = FileOpen("buffer.bin", FILE_WRITE|FILE_BIN);
|
|
if(handle == INVALID_HANDLE) return;
|
|
|
|
FileWriteInteger(handle, count, INT_VALUE);
|
|
for(int i = 0; i < count; i++)
|
|
FileWriteDouble(handle, buffer[i], DOUBLE_VALUE);
|
|
|
|
FileClose(handle);
|
|
}
|
|
|
|
// Read binary
|
|
void LoadBuffer(double &buffer[])
|
|
{
|
|
int handle = FileOpen("buffer.bin", FILE_READ|FILE_BIN);
|
|
if(handle == INVALID_HANDLE) return;
|
|
|
|
int count = FileReadInteger(handle, INT_VALUE);
|
|
ArrayResize(buffer, count);
|
|
for(int i = 0; i < count; i++)
|
|
buffer[i] = FileReadDouble(handle, DOUBLE_VALUE);
|
|
|
|
FileClose(handle);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## WebRequest
|
|
|
|
Two function signatures. **Whitelist URL first:** Tools > Options > Expert Advisors. Only in EAs/Scripts (not indicators, not Strategy Tester).
|
|
|
|
```mql4
|
|
// Variant 1: Simple (cookie/referer)
|
|
int WebRequest(const string method, const string url,
|
|
const string cookie, const string referer,
|
|
int timeout, const char &data[], int data_size,
|
|
char &result[], string &headers);
|
|
|
|
// Variant 2: Custom headers (recommended)
|
|
int WebRequest(const string method, const string url,
|
|
const string headers, int timeout,
|
|
const char &data[], char &result[], string &result_headers);
|
|
|
|
// Returns: HTTP status code (200, 404, etc.) or -1 on error.
|
|
```
|
|
|
|
**Key notes:**
|
|
- `StringToCharArray()` adds null terminator; subtract 1 from size for binary data
|
|
- Error 4060 = URL not whitelisted
|
|
- HTTPS supported and recommended
|
|
|
|
> **Full examples** (GET, POST/JSON, CHttpClient class, Node.js patterns, error handling): See [external-communication.md](external-communication.md)
|
|
|
|
---
|
|
|
|
## Utility Functions
|
|
|
|
### Mathematical Functions
|
|
|
|
```mql4
|
|
double MathAbs(double value); // Absolute value
|
|
double MathCeil(double value); // Round up
|
|
double MathFloor(double value); // Round down
|
|
double MathRound(double value); // Round to nearest
|
|
double MathMax(double a, double b); // Maximum
|
|
double MathMin(double a, double b); // Minimum
|
|
double MathPow(double base, double exp); // Power
|
|
double MathSqrt(double value); // Square root
|
|
double MathLog(double value); // Natural logarithm
|
|
double MathExp(double value); // e^x
|
|
double MathMod(double a, double b); // Modulo for doubles
|
|
int MathRand(); // Random number 0-32767
|
|
void MathSrand(int seed); // Seed random generator
|
|
double NormalizeDouble(double value, int digits); // Round to digits
|
|
```
|
|
|
|
### Date and Time Functions
|
|
|
|
```mql4
|
|
datetime TimeCurrent(); // Server time (last known)
|
|
datetime TimeLocal(); // Local computer time
|
|
datetime TimeGMT(); // GMT time
|
|
int TimeYear(datetime t); // Year
|
|
int TimeMonth(datetime t); // Month (1-12)
|
|
int TimeDay(datetime t); // Day of month (1-31)
|
|
int TimeHour(datetime t); // Hour (0-23)
|
|
int TimeMinute(datetime t); // Minute (0-59)
|
|
int TimeSeconds(datetime t); // Seconds (0-59)
|
|
int TimeDayOfWeek(datetime t); // Day of week (0=Sunday)
|
|
int TimeDayOfYear(datetime t); // Day of year (1-366)
|
|
string TimeToString(datetime t, int mode=TIME_DATE|TIME_MINUTES);
|
|
datetime StringToTime(string value);
|
|
|
|
// Example: Trade only during London session
|
|
int hour = TimeHour(TimeCurrent());
|
|
if(hour >= 8 && hour < 16) // London hours
|
|
{
|
|
// Trading allowed
|
|
}
|
|
```
|
|
|
|
### Chart Functions
|
|
|
|
```mql4
|
|
long ChartID(); // Current chart ID
|
|
bool ChartSetInteger(long chart_id, int prop, long value);
|
|
bool ChartSetDouble(long chart_id, int prop, double value);
|
|
bool ChartSetString(long chart_id, int prop, string value);
|
|
void ChartRedraw(long chart_id=0); // Redraw chart
|
|
|
|
// Example: Add comment to chart
|
|
Comment("Balance: ", AccountBalance(), "\n",
|
|
"Equity: ", AccountEquity(), "\n",
|
|
"Spread: ", MarketInfo(_Symbol, MODE_SPREAD));
|
|
```
|
|
|
|
### Object Functions
|
|
|
|
```mql4
|
|
bool ObjectCreate(string name, int type, int window, datetime time1, double price1, ...);
|
|
bool ObjectDelete(string name);
|
|
bool ObjectSet(string name, int prop, double value);
|
|
bool ObjectSetText(string name, string text, int font_size, string font, color text_color);
|
|
|
|
// Example: Draw horizontal line
|
|
ObjectCreate("SupportLine", OBJ_HLINE, 0, 0, 1.23456);
|
|
ObjectSet("SupportLine", OBJPROP_COLOR, clrBlue);
|
|
ObjectSet("SupportLine", OBJPROP_WIDTH, 2);
|
|
ObjectSet("SupportLine", OBJPROP_STYLE, STYLE_DASH);
|
|
```
|
|
|
|
### Print and Alert
|
|
|
|
```mql4
|
|
Print("Message to Experts log"); // Experts tab in Terminal
|
|
Alert("Alert popup message"); // Pop-up dialog
|
|
Comment("On-chart comment"); // Displayed on chart
|
|
SendNotification("Push notification"); // Mobile push (if configured)
|
|
SendMail("Subject", "Email body"); // Email (if configured)
|
|
PlaySound("alert.wav"); // Play sound file
|
|
```
|
|
|
|
### Miscellaneous
|
|
|
|
```mql4
|
|
void Sleep(int milliseconds); // Pause execution (not in indicators!)
|
|
bool IsTesting(); // Running in Strategy Tester?
|
|
bool IsOptimization(); // Running optimization?
|
|
bool IsVisualMode(); // Visual mode in tester?
|
|
bool IsDemo(); // Demo account?
|
|
bool IsConnected(); // Connected to server?
|
|
bool IsTradeAllowed(); // Trade context free?
|
|
bool IsExpertEnabled(); // Expert Advisors enabled?
|
|
bool IsStopped(); // EA being terminated?
|
|
bool IsDllsAllowed(); // DLL imports allowed?
|
|
string TerminalInfoString(int prop); // Terminal info
|
|
string Symbol(); // Current symbol (same as _Symbol)
|
|
int Period(); // Current period (same as _Period)
|
|
int UninitializeReason(); // Deinitialization reason
|
|
void ExpertRemove(); // Remove EA from chart
|
|
```
|
|
|
|
---
|
|
|
|
## Global Terminal Variables
|
|
|
|
Not to be confused with global program variables. These are key-value pairs stored at the terminal level, shared between programs.
|
|
|
|
```mql4
|
|
// bool GlobalVariableSet(string name, double value)
|
|
// Creates or updates a global terminal variable.
|
|
GlobalVariableSet("LastTradeTime_EURUSD", (double)TimeCurrent());
|
|
|
|
// double GlobalVariableGet(string name)
|
|
// Returns the value. Returns 0 if not found (check with GlobalVariableCheck).
|
|
double lastTime = GlobalVariableGet("LastTradeTime_EURUSD");
|
|
|
|
// bool GlobalVariableCheck(string name)
|
|
// Returns true if the variable exists.
|
|
if(GlobalVariableCheck("LastTradeTime_EURUSD"))
|
|
{
|
|
datetime t = (datetime)GlobalVariableGet("LastTradeTime_EURUSD");
|
|
}
|
|
|
|
// bool GlobalVariableDel(string name)
|
|
GlobalVariableDel("LastTradeTime_EURUSD");
|
|
|
|
// bool GlobalVariableSetOnCondition(string name, double new_value, double check_value)
|
|
// Atomic set: only sets if the current value matches check_value. Useful for locking.
|
|
// Returns true if the value was set.
|
|
if(GlobalVariableSetOnCondition("TradeLock", 1.0, 0.0))
|
|
{
|
|
// We acquired the lock
|
|
// ... trade ...
|
|
GlobalVariableSet("TradeLock", 0.0); // Release lock
|
|
}
|
|
```
|