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
1256 lines
38 KiB
Markdown
1256 lines
38 KiB
Markdown
# MQL5 Language Reference
|
|
|
|
Comprehensive reference for MQL5 development on MetaTrader 5.
|
|
|
|
## Table of Contents
|
|
|
|
- [Key Differences from MQL4](#key-differences-from-mql4)
|
|
- [OOP Features](#oop-features)
|
|
- [Trade Functions](#trade-functions)
|
|
- [Event Handlers](#event-handlers)
|
|
- [Standard Library](#standard-library)
|
|
- [Key Enumerations](#key-enumerations)
|
|
- [MQL5-Specific Features](#mql5-specific-features)
|
|
- [MQL5 vs MQL4 Summary Table](#mql5-vs-mql4-summary-table)
|
|
|
|
---
|
|
|
|
## Key Differences from MQL4
|
|
|
|
### Architectural Paradigm
|
|
|
|
MQL5 is a full object-oriented language (C++-like) compared to MQL4's procedural (C-like) approach. The most fundamental difference is the trade model:
|
|
|
|
| Concept | Description |
|
|
|---------|-------------|
|
|
| **Order** | A trade request sent to the server. Can be market (executed immediately) or pending (waits for price). |
|
|
| **Deal** | An executed trade operation resulting from a filled order. Recorded in history. |
|
|
| **Position** | The net result of one or more deals on a symbol. This is the current open exposure. |
|
|
|
|
### Account Models
|
|
|
|
| Model | Behavior | Notes |
|
|
|-------|----------|-------|
|
|
| **Netting** | One position per symbol. New deals increase/decrease/reverse the single position. | Default for most brokers. `ACCOUNT_MARGIN_MODE_RETAIL_NETTING`. |
|
|
| **Hedging** | Multiple independent positions per symbol. Each has its own ticket. | Closer to MQL4 behavior. `ACCOUNT_MARGIN_MODE_RETAIL_HEDGING`. |
|
|
|
|
Detect at runtime:
|
|
|
|
```mql5
|
|
ENUM_ACCOUNT_MARGIN_MODE marginMode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
|
|
if(marginMode == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
|
|
Print("Hedging account");
|
|
```
|
|
|
|
---
|
|
|
|
## OOP Features
|
|
|
|
### Classes
|
|
|
|
```mql5
|
|
class CMyClass
|
|
{
|
|
private:
|
|
int m_id;
|
|
double m_value;
|
|
string m_name;
|
|
|
|
protected:
|
|
double CalculateInternal() const { return m_value * 2.0; }
|
|
|
|
public:
|
|
// Default constructor
|
|
CMyClass() : m_id(0), m_value(0.0), m_name("") {}
|
|
|
|
// Parametric constructor with initialization list
|
|
CMyClass(int id, double value, string name)
|
|
: m_id(id), m_value(value), m_name(name) {}
|
|
|
|
// Copy constructor
|
|
CMyClass(const CMyClass &other)
|
|
: m_id(other.m_id), m_value(other.m_value), m_name(other.m_name) {}
|
|
|
|
// Destructor
|
|
~CMyClass() { Print("Destroyed: ", m_name); }
|
|
|
|
// Const method (does not modify object state)
|
|
int GetId() const { return m_id; }
|
|
double GetValue() const { return m_value; }
|
|
string GetName() const { return m_name; }
|
|
|
|
// Mutator methods
|
|
void SetValue(double value) { m_value = value; }
|
|
|
|
// Regular method
|
|
void PrintInfo()
|
|
{
|
|
PrintFormat("ID=%d, Value=%.2f, Name=%s", m_id, m_value, m_name);
|
|
}
|
|
};
|
|
```
|
|
|
|
### Inheritance
|
|
|
|
```mql5
|
|
class CBase
|
|
{
|
|
public:
|
|
virtual void Process() { Print("CBase::Process"); }
|
|
virtual string GetType() const { return "Base"; }
|
|
};
|
|
|
|
class CDerived : public CBase // Single inheritance only
|
|
{
|
|
public:
|
|
void Process() override { Print("CDerived::Process"); } // override keyword
|
|
string GetType() const override final { return "Derived"; } // final = no further override
|
|
};
|
|
|
|
class CFinalClass final : public CDerived // final class = cannot be inherited
|
|
{
|
|
public:
|
|
void Process() override { Print("CFinalClass::Process"); }
|
|
// Cannot override GetType() because it's marked final in CDerived
|
|
};
|
|
```
|
|
|
|
### Virtual Functions and Polymorphism
|
|
|
|
```mql5
|
|
// Abstract class with pure virtual function
|
|
class CSignal
|
|
{
|
|
public:
|
|
virtual int GetSignal() = 0; // Pure virtual (= 0), makes class abstract
|
|
virtual void Release() { delete &this; }
|
|
virtual ~CSignal() {}
|
|
};
|
|
|
|
class CMASignal : public CSignal
|
|
{
|
|
public:
|
|
int GetSignal() override
|
|
{
|
|
// MA crossover logic
|
|
return 1; // Buy
|
|
}
|
|
};
|
|
|
|
class CRSISignal : public CSignal
|
|
{
|
|
public:
|
|
int GetSignal() override
|
|
{
|
|
// RSI overbought/oversold logic
|
|
return -1; // Sell
|
|
}
|
|
};
|
|
|
|
// Dynamic dispatch with pointer arrays
|
|
CSignal *signals[];
|
|
void OnInit()
|
|
{
|
|
ArrayResize(signals, 2);
|
|
signals[0] = new CMASignal(); // new allocates on heap
|
|
signals[1] = new CRSISignal();
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
for(int i = 0; i < ArraySize(signals); i++)
|
|
delete signals[i]; // delete frees heap memory
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
for(int i = 0; i < ArraySize(signals); i++)
|
|
Print("Signal[", i, "]: ", signals[i].GetSignal()); // Polymorphic call
|
|
}
|
|
```
|
|
|
|
### Interfaces
|
|
|
|
```mql5
|
|
// interface keyword: no data members, all methods implicitly pure virtual
|
|
interface ITradeExecutor
|
|
{
|
|
bool Execute(string symbol, double volume, int direction);
|
|
void Cancel();
|
|
};
|
|
|
|
interface ILogger
|
|
{
|
|
void Log(string message);
|
|
void LogError(string message);
|
|
};
|
|
|
|
// Multiple interface inheritance is allowed
|
|
class CSmartTrader : public ITradeExecutor, public ILogger
|
|
{
|
|
private:
|
|
string m_logPrefix;
|
|
|
|
public:
|
|
CSmartTrader(string prefix) : m_logPrefix(prefix) {}
|
|
|
|
// Must implement ALL interface methods
|
|
bool Execute(string symbol, double volume, int direction) override
|
|
{
|
|
Log(StringFormat("Executing %s %.2f lots dir=%d", symbol, volume, direction));
|
|
return true;
|
|
}
|
|
|
|
void Cancel() override { Log("Trade cancelled"); }
|
|
|
|
void Log(string message) override
|
|
{
|
|
Print(m_logPrefix, ": ", message);
|
|
}
|
|
|
|
void LogError(string message) override
|
|
{
|
|
Print(m_logPrefix, " ERROR: ", message);
|
|
}
|
|
};
|
|
```
|
|
|
|
### Operator Overloading
|
|
|
|
```mql5
|
|
class CPrice
|
|
{
|
|
public:
|
|
double value;
|
|
|
|
CPrice() : value(0.0) {}
|
|
CPrice(double v) : value(v) {}
|
|
|
|
// Binary operators
|
|
CPrice operator+(const CPrice &rhs) const { return CPrice(value + rhs.value); }
|
|
CPrice operator-(const CPrice &rhs) const { return CPrice(value - rhs.value); }
|
|
CPrice operator*(double factor) const { return CPrice(value * factor); }
|
|
CPrice operator/(double divisor) const { return CPrice(value / divisor); }
|
|
|
|
// Comparison operators
|
|
bool operator==(const CPrice &rhs) const { return MathAbs(value - rhs.value) < 0.000001; }
|
|
bool operator!=(const CPrice &rhs) const { return !(this == rhs); }
|
|
bool operator<(const CPrice &rhs) const { return value < rhs.value; }
|
|
bool operator>(const CPrice &rhs) const { return value > rhs.value; }
|
|
|
|
// Assignment operators
|
|
CPrice *operator=(const CPrice &rhs) { value = rhs.value; return &this; }
|
|
CPrice *operator+=(const CPrice &rhs) { value += rhs.value; return &this; }
|
|
|
|
// Unary operators
|
|
CPrice operator-() const { return CPrice(-value); }
|
|
CPrice operator++() { value += _Point; return this; } // prefix
|
|
CPrice operator++(int) { CPrice tmp = this; value += _Point; return tmp; } // postfix
|
|
|
|
// Indexing operator (for array-like objects)
|
|
// double operator[](int index) const { ... }
|
|
};
|
|
```
|
|
|
|
### Templates
|
|
|
|
```mql5
|
|
// Function template
|
|
template<typename T>
|
|
T Max(T a, T b)
|
|
{
|
|
return (a > b) ? a : b;
|
|
}
|
|
|
|
// Class template
|
|
template<typename T>
|
|
class CStack
|
|
{
|
|
private:
|
|
T m_data[];
|
|
int m_top;
|
|
|
|
public:
|
|
CStack() : m_top(-1) { ArrayResize(m_data, 0); }
|
|
|
|
void Push(T item)
|
|
{
|
|
m_top++;
|
|
ArrayResize(m_data, m_top + 1);
|
|
m_data[m_top] = item;
|
|
}
|
|
|
|
T Pop()
|
|
{
|
|
if(m_top < 0) return (T)NULL;
|
|
T item = m_data[m_top];
|
|
m_top--;
|
|
ArrayResize(m_data, m_top + 1);
|
|
return item;
|
|
}
|
|
|
|
int Size() const { return m_top + 1; }
|
|
bool IsEmpty() const { return m_top < 0; }
|
|
};
|
|
|
|
// Usage
|
|
CStack<double> priceStack;
|
|
priceStack.Push(1.2345);
|
|
double val = priceStack.Pop();
|
|
|
|
int maxVal = Max<int>(10, 20); // explicit type
|
|
double maxD = Max(1.5, 2.5); // type deduction
|
|
```
|
|
|
|
---
|
|
|
|
## Trade Functions
|
|
|
|
### CTrade Class
|
|
|
|
Include: `#include <Trade/Trade.mqh>`
|
|
|
|
#### Configuration
|
|
|
|
```mql5
|
|
#include <Trade/Trade.mqh>
|
|
CTrade trade;
|
|
|
|
void OnInit()
|
|
{
|
|
trade.SetExpertMagicNumber(12345);
|
|
trade.SetDeviationInPoints(10);
|
|
trade.SetTypeFillingBySymbol(_Symbol); // Auto-detect filling (PREFERRED)
|
|
trade.SetAsyncMode(false); // true = non-blocking OrderSendAsync
|
|
}
|
|
```
|
|
|
|
#### CTrade Methods Summary
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `Buy(vol, sym, price, sl, tp, comment)` | Market buy (price=0 for current Ask) |
|
|
| `Sell(vol, sym, price, sl, tp, comment)` | Market sell (price=0 for current Bid) |
|
|
| `BuyLimit(vol, price, sym, sl, tp, type_time, exp, comment)` | Pending buy below market |
|
|
| `SellLimit(vol, price, sym, sl, tp, type_time, exp, comment)` | Pending sell above market |
|
|
| `BuyStop(vol, price, sym, sl, tp, type_time, exp, comment)` | Pending buy above market |
|
|
| `SellStop(vol, price, sym, sl, tp, type_time, exp, comment)` | Pending sell below market |
|
|
| `PositionOpen(sym, type, vol, price, sl, tp, comment)` | Open position (alternative) |
|
|
| `PositionModify(sym_or_ticket, sl, tp)` | Modify SL/TP |
|
|
| `PositionClose(sym_or_ticket, deviation)` | Close entire position |
|
|
| `PositionClosePartial(sym_or_ticket, vol, deviation)` | Partial close |
|
|
| `PositionCloseBy(ticket, ticketOpposite)` | Close by opposite (hedging) |
|
|
| `OrderOpen(sym, type, vol, limitPrice, price, sl, tp, type_time, exp, comment)` | Generic pending |
|
|
| `OrderModify(ticket, price, sl, tp, type_time, exp)` | Modify pending |
|
|
| `OrderDelete(ticket)` | Delete pending |
|
|
|
|
#### Result Access
|
|
|
|
```mql5
|
|
if(trade.Buy(0.1, _Symbol))
|
|
{
|
|
uint retcode = trade.ResultRetcode();
|
|
string desc = trade.ResultRetcodeDescription();
|
|
ulong deal = trade.ResultDeal();
|
|
ulong order = trade.ResultOrder();
|
|
double volume = trade.ResultVolume();
|
|
double price = trade.ResultPrice();
|
|
}
|
|
```
|
|
|
|
### Native Trade Functions
|
|
|
|
#### Position / Order / History Access
|
|
|
|
```mql5
|
|
// Positions (open trades)
|
|
int total = PositionsTotal();
|
|
for(int i = 0; i < total; i++) {
|
|
ulong ticket = PositionGetTicket(i);
|
|
// PositionGetString(POSITION_SYMBOL), PositionGetInteger(POSITION_TYPE)
|
|
// PositionGetDouble(POSITION_VOLUME/POSITION_PRICE_OPEN/POSITION_SL/POSITION_TP/POSITION_PROFIT)
|
|
// PositionGetInteger(POSITION_MAGIC/POSITION_IDENTIFIER)
|
|
}
|
|
PositionSelect(_Symbol); // Select by symbol (netting)
|
|
PositionSelectByTicket(ticket); // Select by ticket (hedging)
|
|
|
|
// Pending orders
|
|
int totalOrd = OrdersTotal();
|
|
for(int i = 0; i < totalOrd; i++) {
|
|
ulong ticket = OrderGetTicket(i);
|
|
// OrderGetString(ORDER_SYMBOL), OrderGetInteger(ORDER_TYPE)
|
|
// OrderGetDouble(ORDER_VOLUME_CURRENT/ORDER_PRICE_OPEN/ORDER_SL/ORDER_TP)
|
|
}
|
|
|
|
// History (deals + orders)
|
|
HistorySelect(from, to); // Select time range
|
|
HistorySelectByPosition(positionId); // Select by position ID
|
|
int deals = HistoryDealsTotal(); // HistoryDealGetTicket(i)
|
|
int orders = HistoryOrdersTotal(); // HistoryOrderGetTicket(i)
|
|
// HistoryDealGetDouble(ticket, DEAL_PROFIT/DEAL_COMMISSION/DEAL_SWAP)
|
|
// HistoryDealGetInteger(ticket, DEAL_TYPE/DEAL_ENTRY)
|
|
```
|
|
|
|
#### OrderSend / OrderSendAsync
|
|
|
|
```mql5
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
request.action = TRADE_ACTION_DEAL;
|
|
request.symbol = _Symbol;
|
|
request.volume = 0.1;
|
|
request.type = ORDER_TYPE_BUY;
|
|
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
request.sl = request.price - 500 * _Point;
|
|
request.tp = request.price + 1000 * _Point;
|
|
request.deviation = 10;
|
|
request.magic = 12345;
|
|
request.type_filling = ORDER_FILLING_FOK;
|
|
|
|
if(!OrderSend(request, result))
|
|
PrintFormat("Error %d: retcode=%u", GetLastError(), result.retcode);
|
|
|
|
// Async: OrderSendAsync(request, result) - handle in OnTradeTransaction()
|
|
```
|
|
|
|
> **Production patterns** (retry logic, filling policy detection, error handling, trailing stops, risk management): See [trading-operations.md](trading-operations.md)
|
|
|
|
---
|
|
|
|
## Event Handlers
|
|
|
|
### Complete Event Handler Table
|
|
|
|
| Handler | Context | Parameters | Description |
|
|
|---------|---------|------------|-------------|
|
|
| `OnInit()` | EA, Indicator, Script | None. Returns `int` (INIT_SUCCEEDED, INIT_FAILED, etc.) | Called once on load/recompile. Initialize resources. |
|
|
| `OnDeinit(const int reason)` | EA, Indicator, Script | `reason`: REASON_PROGRAM, REASON_REMOVE, REASON_RECOMPILE, REASON_CHARTCHANGE, REASON_CHARTCLOSE, REASON_PARAMETERS, REASON_ACCOUNT, REASON_TEMPLATE, REASON_INITFAILED, REASON_CLOSE | Called on unload. Cleanup resources, delete objects. |
|
|
| `OnTick()` | EA | None. Returns `void` | Called on every new tick. Main EA logic. |
|
|
| `OnTimer()` | EA, Indicator | None. Returns `void` | Called on timer event. Set with `EventSetTimer(seconds)` or `EventSetMillisecondTimer(ms)`. Kill with `EventKillTimer()`. |
|
|
| `OnTrade()` | EA | None. Returns `void` | Called when a trade event occurs (order placed, modified, deleted, deal executed, position changed). No parameters about what changed. |
|
|
| `OnTradeTransaction()` | EA | `const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result` | Called with details about each trade transaction. More granular than `OnTrade()`. |
|
|
| `OnBookEvent(const string &symbol)` | EA | `symbol`: Symbol name | Called when Depth of Market changes. Must call `MarketBookAdd(symbol)` first. Call `MarketBookRelease(symbol)` in OnDeinit. |
|
|
| `OnChartEvent()` | EA, Indicator | `const int id, const long &lparam, const double &dparam, const string &sparam` | Chart events: mouse clicks, key presses, object events, custom events. |
|
|
| `OnCalculate()` | Indicator | Two forms (see below) | Called on every new tick. Main indicator calculation logic. |
|
|
| `OnTester()` | EA | None. Returns `double` | Called after backtesting. Return custom optimization criterion. |
|
|
| `OnTesterInit()` | EA | None. Returns `void` | Called before optimization starts (in the optimization agent). |
|
|
| `OnTesterPass()` | EA | None. Returns `void` | Called when an optimization pass result is received. Use `FrameFirst()`/`FrameNext()`. |
|
|
| `OnTesterDeinit()` | EA | None. Returns `void` | Called after optimization ends. Cleanup. |
|
|
|
|
### OnTradeTransaction Example
|
|
|
|
```mql5
|
|
void OnTradeTransaction(const MqlTradeTransaction &trans,
|
|
const MqlTradeRequest &request,
|
|
const MqlTradeResult &result)
|
|
{
|
|
// trans.type is ENUM_TRADE_TRANSACTION_TYPE:
|
|
// TRADE_TRANSACTION_ORDER_ADD - new order added
|
|
// TRADE_TRANSACTION_ORDER_UPDATE - order updated
|
|
// TRADE_TRANSACTION_ORDER_DELETE - order removed from active
|
|
// TRADE_TRANSACTION_DEAL_ADD - deal executed
|
|
// TRADE_TRANSACTION_DEAL_UPDATE - deal updated
|
|
// TRADE_TRANSACTION_DEAL_DELETE - deal deleted
|
|
// TRADE_TRANSACTION_HISTORY_ADD - order moved to history
|
|
// TRADE_TRANSACTION_HISTORY_UPDATE - history order updated
|
|
// TRADE_TRANSACTION_HISTORY_DELETE - history order deleted
|
|
// TRADE_TRANSACTION_POSITION - position changed (not related to deal)
|
|
// TRADE_TRANSACTION_REQUEST - trade request processed
|
|
|
|
switch(trans.type)
|
|
{
|
|
case TRADE_TRANSACTION_DEAL_ADD:
|
|
PrintFormat("Deal added: ticket=%I64u, symbol=%s, type=%d, volume=%.2f, price=%.5f",
|
|
trans.deal, trans.symbol, trans.deal_type, trans.volume, trans.price);
|
|
|
|
// For async trading: match via trans.order to your sent order
|
|
if(HistoryDealSelect(trans.deal))
|
|
{
|
|
double profit = HistoryDealGetDouble(trans.deal, DEAL_PROFIT);
|
|
long entry = HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
|
|
if(entry == DEAL_ENTRY_IN)
|
|
Print("Position opened");
|
|
else if(entry == DEAL_ENTRY_OUT)
|
|
PrintFormat("Position closed, profit=%.2f", profit);
|
|
}
|
|
break;
|
|
|
|
case TRADE_TRANSACTION_REQUEST:
|
|
PrintFormat("Request processed: retcode=%u, order=%I64u",
|
|
result.retcode, result.order);
|
|
break;
|
|
}
|
|
}
|
|
```
|
|
|
|
### OnTester Example
|
|
|
|
```mql5
|
|
double OnTester()
|
|
{
|
|
// Custom optimization criterion
|
|
// Return value is used as the optimization target when "Custom max" is selected
|
|
|
|
double profit = TesterStatistics(STAT_PROFIT);
|
|
double dd = TesterStatistics(STAT_EQUITY_DD_RELATIVE); // % max drawdown
|
|
int trades = (int)TesterStatistics(STAT_TRADES);
|
|
double pf = TesterStatistics(STAT_PROFIT_FACTOR);
|
|
|
|
// Example: profit factor weighted by number of trades, penalize low trade count
|
|
if(trades < 30 || dd > 30.0)
|
|
return 0.0;
|
|
|
|
// Calmar-like ratio: profit / drawdown
|
|
double criterion = (dd > 0.0) ? profit / dd : 0.0;
|
|
return criterion;
|
|
}
|
|
```
|
|
|
|
### OnCalculate Forms
|
|
|
|
```mql5
|
|
// Form 1: Short form (for indicators that use price data directly)
|
|
int OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const int begin,
|
|
const double &price[])
|
|
{
|
|
for(int i = (prev_calculated > 0 ? prev_calculated - 1 : 0); i < rates_total; i++)
|
|
{
|
|
// price[] corresponds to the "Apply to" setting (Close, Open, High, etc.)
|
|
Buffer[i] = price[i];
|
|
}
|
|
return rates_total;
|
|
}
|
|
|
|
// Form 2: Full form (access to OHLCV and time arrays)
|
|
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[])
|
|
{
|
|
for(int i = (prev_calculated > 0 ? prev_calculated - 1 : 0); i < rates_total; i++)
|
|
{
|
|
Buffer[i] = (high[i] + low[i] + close[i]) / 3.0; // Typical price
|
|
}
|
|
return rates_total;
|
|
}
|
|
```
|
|
|
|
### OnBookEvent Example
|
|
|
|
```mql5
|
|
int OnInit()
|
|
{
|
|
MarketBookAdd(_Symbol); // Subscribe to DOM updates
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
MarketBookRelease(_Symbol); // Unsubscribe from DOM
|
|
}
|
|
|
|
void OnBookEvent(const string &symbol)
|
|
{
|
|
if(symbol != _Symbol) return;
|
|
|
|
MqlBookInfo book[];
|
|
if(MarketBookGet(symbol, book))
|
|
{
|
|
for(int i = 0; i < ArraySize(book); i++)
|
|
{
|
|
PrintFormat("Type=%s, Price=%.5f, Volume=%.0f",
|
|
(book[i].type == BOOK_TYPE_SELL) ? "ASK" : "BID",
|
|
book[i].price, book[i].volume);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Standard Library
|
|
|
|
### Trade Classes (`#include <Trade/...>`)
|
|
|
|
| Class | Include | Purpose |
|
|
|-------|---------|---------|
|
|
| `CTrade` | `<Trade/Trade.mqh>` | Trade execution: market orders, pending orders, position/order management. |
|
|
| `CPositionInfo` | `<Trade/PositionInfo.mqh>` | Query open position properties (symbol, type, volume, SL, TP, profit, etc.). |
|
|
| `COrderInfo` | `<Trade/OrderInfo.mqh>` | Query pending order properties. |
|
|
| `CDealInfo` | `<Trade/DealInfo.mqh>` | Query historical deal properties. |
|
|
| `CSymbolInfo` | `<Trade/SymbolInfo.mqh>` | Symbol properties: bid, ask, point, digits, spread, volume limits, session times, etc. |
|
|
| `CAccountInfo` | `<Trade/AccountInfo.mqh>` | Account properties: balance, equity, margin, free margin, leverage, etc. |
|
|
| `CTerminalInfo` | `<Trade/TerminalInfo.mqh>` | Terminal info: connected, trade allowed, community account, path, etc. |
|
|
|
|
```mql5
|
|
#include <Trade/Trade.mqh>
|
|
#include <Trade/PositionInfo.mqh>
|
|
#include <Trade/SymbolInfo.mqh>
|
|
#include <Trade/AccountInfo.mqh>
|
|
|
|
CTrade trade;
|
|
CPositionInfo posInfo;
|
|
CSymbolInfo symInfo;
|
|
CAccountInfo accInfo;
|
|
|
|
void OnInit()
|
|
{
|
|
symInfo.Name(_Symbol);
|
|
trade.SetExpertMagicNumber(12345);
|
|
trade.SetTypeFillingBySymbol(_Symbol);
|
|
|
|
PrintFormat("Balance=%.2f, Leverage=%d", accInfo.Balance(), accInfo.Leverage());
|
|
PrintFormat("Point=%.5f, Digits=%d, Spread=%d",
|
|
symInfo.Point(), symInfo.Digits(), symInfo.Spread());
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
symInfo.RefreshRates(); // Must refresh before accessing prices
|
|
|
|
double ask = symInfo.Ask();
|
|
double bid = symInfo.Bid();
|
|
|
|
// Iterate open positions
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(posInfo.SelectByIndex(i))
|
|
{
|
|
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == 12345)
|
|
{
|
|
PrintFormat("Pos: type=%s, vol=%.2f, profit=%.2f",
|
|
posInfo.TypeDescription(), posInfo.Volume(), posInfo.Profit());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Indicator Classes (`#include <Indicators/...>`)
|
|
|
|
#### Trend Indicators
|
|
|
|
| Class | Indicator |
|
|
|-------|-----------|
|
|
| `CiMA` | Moving Average |
|
|
| `CiADX` | Average Directional Index |
|
|
| `CiBands` | Bollinger Bands |
|
|
| `CiIchimoku` | Ichimoku Kinko Hyo |
|
|
| `CiParabolicSAR` | Parabolic SAR |
|
|
| `CiStdDev` | Standard Deviation |
|
|
| `CiDEMA` | Double Exponential MA |
|
|
| `CiTEMA` | Triple Exponential MA |
|
|
| `CiFrAMA` | Fractal Adaptive MA |
|
|
| `CiAMA` | Adaptive MA |
|
|
| `CiVIDyA` | Variable Index Dynamic Average |
|
|
| `CiEnvelopes` | Envelopes |
|
|
|
|
#### Oscillators
|
|
|
|
| Class | Indicator |
|
|
|-------|-----------|
|
|
| `CiMACD` | MACD |
|
|
| `CiRSI` | Relative Strength Index |
|
|
| `CiStochastic` | Stochastic Oscillator |
|
|
| `CiCCI` | Commodity Channel Index |
|
|
| `CiATR` | Average True Range |
|
|
| `CiMomentum` | Momentum |
|
|
| `CiOsMA` | Moving Average of Oscillator |
|
|
| `CiWPR` | Williams' Percent Range |
|
|
| `CiRVI` | Relative Vigor Index |
|
|
| `CiForce` | Force Index |
|
|
| `CiDeMarker` | DeMarker |
|
|
| `CiBearsPower` | Bears Power |
|
|
| `CiBullsPower` | Bulls Power |
|
|
| `CiTriX` | Triple Exponential MA Oscillator |
|
|
| `CiAO` | Awesome Oscillator |
|
|
| `CiAC` | Accelerator Oscillator |
|
|
|
|
#### Volume Indicators
|
|
|
|
| Class | Indicator |
|
|
|-------|-----------|
|
|
| `CiVolumes` | Volumes |
|
|
| `CiOBV` | On Balance Volume |
|
|
| `CiMFI` | Money Flow Index |
|
|
| `CiAD` | Accumulation/Distribution |
|
|
|
|
#### Usage Pattern
|
|
|
|
```mql5
|
|
#include <Indicators/Trend.mqh>
|
|
#include <Indicators/Oscilators.mqh>
|
|
|
|
CiMA ma;
|
|
CiRSI rsi;
|
|
CiMACD macd;
|
|
|
|
int OnInit()
|
|
{
|
|
// Create(symbol, timeframe, period, shift, method, applied_price)
|
|
if(!ma.Create(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE))
|
|
return INIT_FAILED;
|
|
|
|
// Create(symbol, timeframe, period, applied_price)
|
|
if(!rsi.Create(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE))
|
|
return INIT_FAILED;
|
|
|
|
// Create(symbol, timeframe, fast_ema, slow_ema, signal, applied_price)
|
|
if(!macd.Create(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE))
|
|
return INIT_FAILED;
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
ma.Refresh(); // Must call Refresh() on each tick
|
|
rsi.Refresh();
|
|
macd.Refresh();
|
|
|
|
double maValue = ma.Main(0); // Main(index) - 0 = current bar
|
|
double maValue1 = ma.Main(1); // Previous bar
|
|
|
|
double rsiValue = rsi.Main(0);
|
|
|
|
double macdMain = macd.Main(0); // MACD main line
|
|
double macdSignal = macd.Signal(0); // MACD signal line
|
|
|
|
// For Bollinger Bands
|
|
// CiBands bands;
|
|
// bands.Create(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
|
|
// bands.Refresh();
|
|
// double upper = bands.Upper(0);
|
|
// double base = bands.Base(0);
|
|
// double lower = bands.Lower(0);
|
|
}
|
|
```
|
|
|
|
### Other Standard Library Classes
|
|
|
|
| Class | Include | Purpose |
|
|
|-------|---------|---------|
|
|
| `CObject` | `<Object.mqh>` | Base class for all standard library objects. |
|
|
| `CArrayInt` | `<Arrays/ArrayInt.mqh>` | Dynamic array of int. |
|
|
| `CArrayDouble` | `<Arrays/ArrayDouble.mqh>` | Dynamic array of double. |
|
|
| `CArrayString` | `<Arrays/ArrayString.mqh>` | Dynamic array of string. |
|
|
| `CArrayObj` | `<Arrays/ArrayObj.mqh>` | Dynamic array of CObject pointers. |
|
|
| `CList` | `<Arrays/List.mqh>` | Doubly-linked list of CObject pointers. |
|
|
| `CString` | `<Strings/String.mqh>` | String wrapper with utility methods. |
|
|
| `CFile` | `<Files/File.mqh>` | File operations (base class for CFileTxt, CFileBin). |
|
|
| `CCanvas` | `<Canvas/Canvas.mqh>` | Pixel-level drawing on charts (for custom UIs). |
|
|
|
|
---
|
|
|
|
## Key Enumerations
|
|
|
|
### ENUM_TRADE_REQUEST_ACTIONS
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `TRADE_ACTION_DEAL` | Place a market order (immediate execution). |
|
|
| `TRADE_ACTION_PENDING` | Place a pending order. |
|
|
| `TRADE_ACTION_SLTP` | Modify SL/TP of an existing position. |
|
|
| `TRADE_ACTION_MODIFY` | Modify parameters of a pending order. |
|
|
| `TRADE_ACTION_REMOVE` | Delete a pending order. |
|
|
| `TRADE_ACTION_CLOSE_BY` | Close a position by an opposite one (hedging only). |
|
|
|
|
### ENUM_ORDER_TYPE
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `ORDER_TYPE_BUY` | Market buy order. |
|
|
| `ORDER_TYPE_SELL` | Market sell order. |
|
|
| `ORDER_TYPE_BUY_LIMIT` | Pending buy limit (below market). |
|
|
| `ORDER_TYPE_SELL_LIMIT` | Pending sell limit (above market). |
|
|
| `ORDER_TYPE_BUY_STOP` | Pending buy stop (above market). |
|
|
| `ORDER_TYPE_SELL_STOP` | Pending sell stop (below market). |
|
|
| `ORDER_TYPE_BUY_STOP_LIMIT` | Pending buy stop-limit. When price reaches stop, a buy limit is placed. |
|
|
| `ORDER_TYPE_SELL_STOP_LIMIT` | Pending sell stop-limit. When price reaches stop, a sell limit is placed. |
|
|
|
|
### ENUM_POSITION_TYPE
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `POSITION_TYPE_BUY` | Long position. |
|
|
| `POSITION_TYPE_SELL` | Short position. |
|
|
|
|
### ENUM_ORDER_TYPE_FILLING
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `ORDER_FILLING_FOK` | Fill or Kill. Entire volume must be filled or order is cancelled. |
|
|
| `ORDER_FILLING_IOC` | Immediate or Cancel. Fill what's available, cancel remainder. |
|
|
| `ORDER_FILLING_RETURN` | Return. Used for market-making; partial fills return remainder as pending. |
|
|
|
|
**Important**: Always detect the correct filling mode per symbol:
|
|
|
|
```mql5
|
|
ENUM_ORDER_TYPE_FILLING GetFillingMode(string symbol)
|
|
{
|
|
long fillMode = SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
|
|
|
|
if((fillMode & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
|
|
return ORDER_FILLING_FOK;
|
|
|
|
if((fillMode & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
|
|
return ORDER_FILLING_IOC;
|
|
|
|
return ORDER_FILLING_RETURN;
|
|
}
|
|
```
|
|
|
|
Or simply use `CTrade::SetTypeFillingBySymbol(_Symbol)`.
|
|
|
|
### ENUM_SYMBOL_INFO_DOUBLE (Selected)
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `SYMBOL_BID` | Current Bid price. |
|
|
| `SYMBOL_ASK` | Current Ask price. |
|
|
| `SYMBOL_POINT` | Point value (e.g., 0.00001 for 5-digit). |
|
|
| `SYMBOL_TRADE_TICK_VALUE` | Value of one tick in account currency. |
|
|
| `SYMBOL_TRADE_TICK_SIZE` | Minimum price change. |
|
|
| `SYMBOL_TRADE_CONTRACT_SIZE` | Contract size (e.g., 100000 for standard forex lot). |
|
|
| `SYMBOL_VOLUME_MIN` | Minimum volume for a deal (e.g., 0.01). |
|
|
| `SYMBOL_VOLUME_MAX` | Maximum volume for a deal. |
|
|
| `SYMBOL_VOLUME_STEP` | Volume step (e.g., 0.01). |
|
|
| `SYMBOL_TRADE_STOPS_LEVEL` | Minimum distance in points for SL/TP from current price. |
|
|
| `SYMBOL_TRADE_FREEZE_LEVEL` | Distance in points within which order modification/deletion is frozen. |
|
|
|
|
### ENUM_ACCOUNT_INFO_DOUBLE (Selected)
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `ACCOUNT_BALANCE` | Account balance. |
|
|
| `ACCOUNT_EQUITY` | Account equity. |
|
|
| `ACCOUNT_PROFIT` | Current floating profit/loss. |
|
|
| `ACCOUNT_MARGIN` | Margin currently used. |
|
|
| `ACCOUNT_MARGIN_FREE` | Free margin available. |
|
|
| `ACCOUNT_MARGIN_LEVEL` | Margin level as percentage (Equity / Margin * 100). |
|
|
|
|
---
|
|
|
|
## MQL5-Specific Features
|
|
|
|
### Database (SQLite)
|
|
|
|
MQL5 has built-in SQLite database support for persistent structured storage.
|
|
|
|
```mql5
|
|
int db = INVALID_HANDLE;
|
|
|
|
int OnInit()
|
|
{
|
|
// Open or create database in the common files folder
|
|
db = DatabaseOpen("my_ea_data.sqlite", DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |
|
|
DATABASE_OPEN_COMMON);
|
|
if(db == INVALID_HANDLE)
|
|
{
|
|
Print("DB open failed: ", GetLastError());
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Create table
|
|
if(!DatabaseExecute(db,
|
|
"CREATE TABLE IF NOT EXISTS trades ("
|
|
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
|
"symbol TEXT NOT NULL,"
|
|
"type INTEGER,"
|
|
"volume REAL,"
|
|
"open_price REAL,"
|
|
"close_price REAL,"
|
|
"profit REAL,"
|
|
"open_time TEXT,"
|
|
"close_time TEXT)"))
|
|
{
|
|
Print("CREATE TABLE failed: ", GetLastError());
|
|
}
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void InsertTrade(string symbol, int type, double volume, double price)
|
|
{
|
|
string sql = StringFormat(
|
|
"INSERT INTO trades (symbol, type, volume, open_price, open_time) "
|
|
"VALUES ('%s', %d, %.2f, %.5f, '%s')",
|
|
symbol, type, volume, price, TimeToString(TimeCurrent()));
|
|
|
|
if(!DatabaseExecute(db, sql))
|
|
Print("INSERT failed: ", GetLastError());
|
|
}
|
|
|
|
void ReadTrades()
|
|
{
|
|
int request = DatabasePrepare(db, "SELECT id, symbol, profit FROM trades WHERE profit > 0");
|
|
if(request == INVALID_HANDLE)
|
|
{
|
|
Print("Prepare failed: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
int id;
|
|
string symbol;
|
|
double profit;
|
|
|
|
while(DatabaseRead(request))
|
|
{
|
|
DatabaseColumnInteger(request, 0, id);
|
|
DatabaseColumnText(request, 1, symbol);
|
|
DatabaseColumnDouble(request, 2, profit);
|
|
PrintFormat("Trade #%d: %s, Profit=%.2f", id, symbol, profit);
|
|
}
|
|
|
|
DatabaseFinalize(request);
|
|
}
|
|
|
|
// Transactions for batch operations
|
|
void BatchInsert()
|
|
{
|
|
DatabaseTransactionBegin(db);
|
|
|
|
for(int i = 0; i < 100; i++)
|
|
{
|
|
if(!DatabaseExecute(db, StringFormat("INSERT INTO trades (symbol) VALUES ('ITEM_%d')", i)))
|
|
{
|
|
DatabaseTransactionRollback(db);
|
|
return;
|
|
}
|
|
}
|
|
|
|
DatabaseTransactionCommit(db);
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if(db != INVALID_HANDLE)
|
|
DatabaseClose(db);
|
|
}
|
|
```
|
|
|
|
### Network Sockets
|
|
|
|
Available only in EAs and scripts (NOT indicators). Allows raw TCP and TLS connections.
|
|
|
|
```mql5
|
|
int OnInit()
|
|
{
|
|
// Create socket
|
|
int socket = SocketCreate();
|
|
if(socket == INVALID_HANDLE)
|
|
{
|
|
Print("SocketCreate failed: ", GetLastError());
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Connect to server (TCP)
|
|
if(!SocketConnect(socket, "api.example.com", 443, 5000)) // host, port, timeout_ms
|
|
{
|
|
Print("SocketConnect failed: ", GetLastError());
|
|
SocketClose(socket);
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// TLS handshake for HTTPS
|
|
if(!SocketTlsHandshake(socket, "api.example.com"))
|
|
{
|
|
Print("TLS handshake failed: ", GetLastError());
|
|
SocketClose(socket);
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Build HTTP request
|
|
string request = "GET /data HTTP/1.1\r\n"
|
|
"Host: api.example.com\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n";
|
|
|
|
// Send via TLS
|
|
uchar reqData[];
|
|
StringToCharArray(request, reqData, 0, WHOLE_ARRAY, CP_UTF8);
|
|
int sent = SocketTlsSend(socket, reqData, ArraySize(reqData) - 1); // exclude null terminator
|
|
|
|
if(sent <= 0)
|
|
{
|
|
Print("SocketTlsSend failed: ", GetLastError());
|
|
SocketClose(socket);
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Read response
|
|
uchar response[];
|
|
string result = "";
|
|
uint timeout = 5000;
|
|
|
|
do
|
|
{
|
|
uint len = SocketTlsReadAvailable(socket, response, timeout);
|
|
if(len > 0)
|
|
result += CharArrayToString(response, 0, WHOLE_ARRAY, CP_UTF8);
|
|
}
|
|
while(SocketTlsRead(socket, response, 1024, timeout) > 0);
|
|
|
|
Print("Response: ", result);
|
|
|
|
SocketClose(socket);
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
// For non-TLS (plain TCP):
|
|
// SocketSend(socket, data, dataLen);
|
|
// SocketRead(socket, response, responseLen, timeout);
|
|
```
|
|
|
|
### Resources
|
|
|
|
Embed external files (images, sounds, data) directly into the compiled EX5 file.
|
|
|
|
```mql5
|
|
// Embed resource at compile time
|
|
#resource "\\Images\\logo.bmp" // Relative to source file
|
|
#resource "\\Sounds\\alert.wav"
|
|
#resource "\\Files\\config.txt"
|
|
|
|
void OnInit()
|
|
{
|
|
// Access resource as "::Images\\logo.bmp"
|
|
ObjectCreate(0, "Logo", OBJ_BITMAP_LABEL, 0, 0, 0);
|
|
ObjectSetString(0, "Logo", OBJPROP_BMPFILE, "::Images\\logo.bmp");
|
|
|
|
// Play sound from resource
|
|
PlaySound("::Sounds\\alert.wav");
|
|
|
|
// Create dynamic resource from pixel data
|
|
uint pixels[];
|
|
int width = 100, height = 100;
|
|
ArrayResize(pixels, width * height);
|
|
|
|
for(int i = 0; i < ArraySize(pixels); i++)
|
|
pixels[i] = ColorToARGB(clrBlue, 200);
|
|
|
|
ResourceCreate("::DynImage", pixels, width, height, 0, 0, width, COLOR_FORMAT_ARGB_NORMALIZE);
|
|
|
|
// Read an image resource
|
|
uint data[];
|
|
int w, h;
|
|
ResourceReadImage("::Images\\logo.bmp", data, w, h);
|
|
|
|
// Save resource to file
|
|
ResourceSave("::Images\\logo.bmp", "SavedFiles\\logo.bmp");
|
|
|
|
// Free dynamic resource
|
|
ResourceFree("::DynImage");
|
|
}
|
|
```
|
|
|
|
### OpenCL
|
|
|
|
GPU-accelerated parallel computing for intensive calculations (optimization, neural networks, etc.).
|
|
|
|
```mql5
|
|
void RunOpenCL()
|
|
{
|
|
// 1. Create context (0 = default device)
|
|
int clContext = CLContextCreate(CL_USE_GPU_ONLY);
|
|
if(clContext == INVALID_HANDLE)
|
|
{
|
|
Print("CLContextCreate failed");
|
|
return;
|
|
}
|
|
|
|
// 2. Create program from OpenCL kernel source
|
|
string kernelSource =
|
|
"__kernel void multiply(__global double *a, __global double *b, __global double *c, int n) {"
|
|
" int i = get_global_id(0);"
|
|
" if(i < n) c[i] = a[i] * b[i];"
|
|
"}";
|
|
|
|
string buildLog;
|
|
int clProgram = CLProgramCreate(clContext, kernelSource, buildLog);
|
|
if(clProgram == INVALID_HANDLE)
|
|
{
|
|
Print("CLProgramCreate failed: ", buildLog);
|
|
CLContextFree(clContext);
|
|
return;
|
|
}
|
|
|
|
// 3. Create kernel
|
|
int clKernel = CLKernelCreate(clProgram, "multiply");
|
|
|
|
// 4. Prepare data
|
|
int n = 1000;
|
|
double a[], b[], c[];
|
|
ArrayResize(a, n);
|
|
ArrayResize(b, n);
|
|
ArrayResize(c, n);
|
|
|
|
for(int i = 0; i < n; i++) { a[i] = i * 1.5; b[i] = i * 2.0; }
|
|
|
|
// 5. Create buffers and write data
|
|
int bufA = CLBufferCreate(clContext, n * sizeof(double), CL_MEM_READ_ONLY);
|
|
int bufB = CLBufferCreate(clContext, n * sizeof(double), CL_MEM_READ_ONLY);
|
|
int bufC = CLBufferCreate(clContext, n * sizeof(double), CL_MEM_WRITE_ONLY);
|
|
|
|
CLBufferWrite(bufA, a);
|
|
CLBufferWrite(bufB, b);
|
|
|
|
// 6. Set kernel arguments
|
|
CLSetKernelArgMem(clKernel, 0, bufA);
|
|
CLSetKernelArgMem(clKernel, 1, bufB);
|
|
CLSetKernelArgMem(clKernel, 2, bufC);
|
|
CLSetKernelArg(clKernel, 3, n);
|
|
|
|
// 7. Execute
|
|
uint globalWorkSize[1] = {(uint)n};
|
|
CLExecute(clKernel, 1, 0, globalWorkSize);
|
|
|
|
// 8. Read results
|
|
CLBufferRead(bufC, c);
|
|
|
|
// 9. Cleanup
|
|
CLBufferFree(bufA);
|
|
CLBufferFree(bufB);
|
|
CLBufferFree(bufC);
|
|
CLKernelFree(clKernel);
|
|
CLProgramFree(clProgram);
|
|
CLContextFree(clContext);
|
|
}
|
|
```
|
|
|
|
### WebRequest (MQL5 Variant)
|
|
|
|
Two function signatures. URL must be whitelisted in Tools > Options > Expert Advisors. Only available in EAs and scripts, NOT indicators or Strategy Tester.
|
|
|
|
```mql5
|
|
// Form 1: Custom headers
|
|
void WebRequestWithHeaders()
|
|
{
|
|
string url = "https://api.example.com/webhook";
|
|
string headers = "Content-Type: application/json\r\n"
|
|
"Authorization: Bearer YOUR_TOKEN\r\n";
|
|
int timeout = 5000;
|
|
|
|
// Build JSON body
|
|
string jsonBody = StringFormat(
|
|
"{\"symbol\":\"%s\",\"price\":%.5f,\"action\":\"BUY\"}",
|
|
_Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK));
|
|
|
|
char postData[];
|
|
char resultData[];
|
|
string resultHeaders;
|
|
|
|
StringToCharArray(jsonBody, postData, 0, WHOLE_ARRAY, CP_UTF8);
|
|
// Remove null terminator
|
|
ArrayResize(postData, ArraySize(postData) - 1);
|
|
|
|
int statusCode = WebRequest(
|
|
"POST", // string method
|
|
url, // string url
|
|
headers, // string headers
|
|
timeout, // int timeout
|
|
postData, // char &data[]
|
|
resultData, // char &result[]
|
|
resultHeaders // string &result_headers
|
|
);
|
|
|
|
if(statusCode == -1)
|
|
{
|
|
Print("WebRequest error: ", GetLastError());
|
|
Print("Add URL to allowed list: Tools > Options > Expert Advisors");
|
|
return;
|
|
}
|
|
|
|
string response = CharArrayToString(resultData, 0, WHOLE_ARRAY, CP_UTF8);
|
|
PrintFormat("HTTP %d: %s", statusCode, response);
|
|
}
|
|
|
|
// Form 2: Simple headers as string (cookie, referer)
|
|
void WebRequestSimple()
|
|
{
|
|
string cookie = "", headers = "", response = "";
|
|
char postData[], resultData[];
|
|
string resultHeaders;
|
|
|
|
int statusCode = WebRequest(
|
|
"GET", // method
|
|
"https://api.example.com/data", // url
|
|
cookie, // cookie
|
|
"", // referer
|
|
5000, // timeout
|
|
postData, // data (empty for GET)
|
|
0, // data_size
|
|
resultData, // result
|
|
resultHeaders // result_headers
|
|
);
|
|
|
|
if(statusCode == 200)
|
|
{
|
|
response = CharArrayToString(resultData, 0, WHOLE_ARRAY, CP_UTF8);
|
|
Print("Response: ", response);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## MQL5 vs MQL4 Summary Table
|
|
|
|
| Feature | MQL4 | MQL5 |
|
|
|---------|------|------|
|
|
| **OOP** | Limited (classes added later) | Full OOP: classes, inheritance, interfaces, templates, operator overloading |
|
|
| **Account model** | Hedging only | Netting + Hedging |
|
|
| **Trade model** | Orders only (`OrderSend`, `OrderModify`, `OrderClose`) | Orders + Deals + Positions (`CTrade`, `OrderSend` with `MqlTradeRequest`) |
|
|
| **Standard Library** | Minimal | Comprehensive (Trade, Indicators, Arrays, Canvas, etc.) |
|
|
| **Event handlers** | `OnInit`, `OnDeinit`, `OnTick`, `OnTimer`, `OnChartEvent`, `OnCalculate`, `OnTester` | All MQL4 handlers + `OnTrade`, `OnTradeTransaction`, `OnBookEvent`, `OnTesterInit/Pass/Deinit` |
|
|
| **Indicator buffers** | Max 8 | Max 512 |
|
|
| **Draw styles** | 6 basic (LINE, SECTION, HISTOGRAM, ARROW, ZIGZAG, NONE) | 18 styles including color variants (DRAW_COLOR_LINE, DRAW_FILLING, DRAW_BARS, DRAW_CANDLES, etc.) |
|
|
| **OpenCL** | Not available | Full OpenCL support for GPU computing |
|
|
| **SQLite database** | Not available | Built-in `DatabaseOpen`, `DatabaseExecute`, `DatabasePrepare`, etc. |
|
|
| **Network sockets** | Not available | TCP + TLS via `SocketCreate`, `SocketConnect`, `SocketTlsHandshake`, etc. |
|
|
| **WebRequest** | `WebRequest()` (same function) | `WebRequest()` with two signatures (custom headers or simple) |
|
|
| **Multi-currency testing** | Limited | Full multi-symbol/multi-timeframe backtesting |
|
|
| **Cloud optimization** | Not available | MQL5 Cloud Network for distributed optimization |
|
|
| **Resources** | `#resource` for images | `#resource` for any file type + `ResourceCreate`/`ResourceReadImage`/`ResourceSave`/`ResourceFree` |
|
|
| **Custom optimization** | `OnTester()` returns double | `OnTester()` + `OnTesterInit/Pass/Deinit` + `FrameFirst/FrameNext/FrameAdd` for custom criteria and frame communication |
|
|
| **Timeseries access** | `iClose()`, `iOpen()`, etc. with shift | `CopyClose()`, `CopyOpen()`, etc. copying into arrays, or `iClose()` with MQL4-compatible syntax |
|
|
| **Indicator access** | `iMA()`, `iRSI()` return value directly | `iMA()`, `iRSI()` return handle (int). Use `CopyBuffer()` to get values, or use indicator classes. |
|
|
|
|
### Indicator Handle Pattern (MQL5)
|
|
|
|
```mql5
|
|
int maHandle;
|
|
double maBuffer[];
|
|
|
|
int OnInit()
|
|
{
|
|
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
|
|
if(maHandle == INVALID_HANDLE) return INIT_FAILED;
|
|
|
|
ArraySetAsSeries(maBuffer, true); // Index 0 = newest bar
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
if(CopyBuffer(maHandle, 0, 0, 3, maBuffer) < 3) return;
|
|
// maBuffer[0] = current bar MA value
|
|
// maBuffer[1] = previous bar MA value
|
|
// maBuffer[2] = two bars ago
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
IndicatorRelease(maHandle); // Free the indicator handle
|
|
}
|
|
```
|