16 KiB
16 KiB
name, description, version, license, compatibility, metadata
| name | description | version | license | compatibility | metadata | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| mql5 | MQL5 development skill for MetaTrader 5 Expert Advisors, Indicators, Scripts, and Services. Focus on positions, orders, indicators, ticks, bars, risk management, backtesting, and multi-instance MT5 operations. Includes programming book and API reference documentation. | 0.1 | MIT | Target: MetaTrader 5 platform. Language: MQL5 (C++-like syntax). File extensions: *.mq5 (source), *.mqh (headers). Run time: Windows native, Linux via Wine, macOS via Wine. |
|
MQL5 Development Skill
Expert development skill for MetaTrader 5. Covers EA, Indicator, Script, and Service creation with emphasis on trading operations, technical indicators, multi-timeframe analysis, risk management, and backtesting workflows.
1. MQL5 Fundamentals
Language and File Types
- MQL5 syntax is similar to C++ but with domain-specific additions
- Source files:
*.mq5(programs),*.mqh(headers) - Compiled output:
*.ex5(same name as source) - Compiler: built into MetaEditor IDE
Program Types
| Type | Purpose | Key Handler | Directory |
|---|---|---|---|
| Expert Advisor | Automated trading | OnTick() |
MQL5/Experts/ |
| Indicator | Technical analysis | OnCalculate() |
MQL5/Indicators/ |
| Script | One-shot execution | OnStart() |
MQL5/Scripts/ |
| Service | Background task | OnStart() + OnTimer() |
MQL5/Services/ |
MQL5 Directory Structure
Default locations per platform:
| Platform | Path |
|---|---|
| Windows 10+ | $env:USERPROFILE\AppData\Roaming\MetaQuotes\Terminal\$INSTANT_HEX\MQL5 |
| Linux (Wine) | ~/.wine/drive_c/Program Files/MetaTrader 5/MQL5/ |
| macOS | Unknown — verify per installation |
Key subdirectories:
MQL5/
├── Experts/ # EA source files (.mq5)
│ ├── Examples/ # Built-in example EAs
│ └── Free Robots/ # Downloaded EAs
├── Indicators/ # Indicator source files
├── Scripts/ # Script source files
├── Services/ # Service source files
├── Include/ # Header files (.mqh)
│ ├── Trade/ # Trading classes (Trade.mqh, PositionInfo.mqh, etc.)
│ ├── Indicators/ # Indicator helpers
│ ├── Expert/ # Expert base classes
│ └── Generic/ # Generic collections
├── Files/ # File I/O sandbox
├── Images/ # Image resources
├── Libraries/ # DLL/shared libraries
├── Profiles/ # Chart profiles
└── Logs/ # Log files
Multi-Instance MT5
Multiple MT5 instances can run simultaneously for different accounts:
- Install MT5 to separate target paths (e.g.
MT5_BrokerA/,MT5_BrokerB/) - Each instance has its own
MQL5/directory - To identify which account an instance is logged into:
AccountInfoInteger(ACCOUNT_LOGIN)— account numberAccountInfoString(ACCOUNT_NAME)— account nameAccountInfoString(ACCOUNT_SERVER)— broker server
- Each instance runs as a separate process — use
Magic Numberto distinguish EA trades across instances on the same symbol
2. Trading Operations
Core Concepts
- Order: instruction to buy/sell (Market or Pending)
- Deal: executed exchange (buy at Ask, sell at Bid)
- Position: current obligation (long or short)
CTrade Class (Standard Library)
#include <Trade\Trade.mqh>
CTrade trade;
// Setup in OnInit()
trade.SetExpertMagicNumber(EA_MAGIC);
trade.SetMarginMode();
trade.SetTypeFillingBySymbol(Symbol());
trade.SetDeviationInPoints(Slippage);
Key methods:
| Method | Purpose |
|---|---|
PositionOpen(symbol, type, volume, price, sl, tp) |
Open a position |
PositionClose(symbol, deviation) |
Close a position |
PositionModify(symbol, sl, tp) |
Modify SL/TP |
PositionClosePartial(symbol, volume) |
Partial close |
Buy(volume, price, sl, tp, comment) |
Shortcut for buy |
Sell(volume, price, sl, tp, comment) |
Shortcut for sell |
BuyLimit/BuyStop/SellLimit/SellStop(...) |
Pending orders |
ResultRetcode() |
Check trade server return code |
ResultDeal() |
Get deal ticket after execution |
Position Queries
// Iterate open positions (Hedging account)
uint total = PositionsTotal();
for (uint i = 0; i < total; i++) {
string sym = PositionGetSymbol(i);
if (sym == _Symbol && PositionGetInteger(POSITION_MAGIC) == EA_MAGIC) {
double vol = PositionGetDouble(POSITION_VOLUME);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
long type = PositionGetInteger(POSITION_TYPE);
}
}
// Netting account — simpler
if (PositionSelect(_Symbol)) {
// position is selected
}
Order Execution Pattern
// Calculate price
double price = (signal == ORDER_TYPE_BUY)
? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Open with SL/TP
trade.PositionOpen(_Symbol, signal, lotSize, price, sl, tp, "EA Signal");
// Always check result
if (trade.ResultRetcode() != TRADE_RETCODE_DONE) {
Print("Trade failed: ", trade.ResultRetcode());
}
Hedging vs Netting
bool IsHedging = ((ENUM_ACCOUNT_MARGIN_MODE)
AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
- Hedging: multiple positions per symbol, must iterate and match Magic Number
- Netting: one position per symbol, use
PositionSelect()
3. Indicators and Multi-Timeframe
Built-in Indicator Handles
// Moving Average
int handle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_SMA, PRICE_CLOSE);
// RSI
int handle = iRSI(_Symbol, PERIOD_H1, 14, PRICE_CLOSE);
// MACD
int handle = iMACD(_Symbol, PERIOD_H1, 12, 26, 9, PRICE_CLOSE);
// Bollinger Bands
int handle = iBands(_Symbol, PERIOD_H1, 20, 0, 2.0, PRICE_CLOSE);
Reading Indicator Values
double buffer[];
ArraySetAsSeries(buffer, true);
if (CopyBuffer(handle, 0, 0, 3, buffer) != 3) {
Print("No indicator data");
return;
}
// buffer[0] = current bar value
// buffer[1] = previous bar value
Multi-Timeframe Analysis
// Higher timeframe trend
int h4_ma = iMA(_Symbol, PERIOD_H4, 50, 0, MODE_SMA, PRICE_CLOSE);
// Entry timeframe signal
int h1_rsi = iRSI(_Symbol, PERIOD_H1, 14, PRICE_CLOSE);
// In OnTick():
double h4_val[], h1_val[];
CopyBuffer(h4_ma, 0, 0, 1, h4_val);
CopyBuffer(h1_rsi, 0, 0, 1, h1_val);
bool bullish = (SymbolInfoDouble(_Symbol, SYMBOL_BID) > h4_val[0]);
bool oversold = (h1_val[0] < 30);
New Bar Detection
datetime lastBarTime = 0;
void OnTick() {
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if (currentBarTime == lastBarTime) return; // not a new bar
lastBarTime = currentBarTime;
// New bar — run analysis here
}
4. Ticks and Bars
Timeseries Access
Index 0 = current (unfinished) bar. Array is reverse-ordered.
MqlRates rates[];
ArraySetAsSeries(rates, true);
CopyRates(_Symbol, _Period, 0, 100, rates);
// rates[0] = current bar
// rates[1] = previous bar
// rates[0].open, .high, .low, .close, .tick_volume, .time
Tick Data
MqlTick tick;
SymbolInfoTick(_Symbol, tick);
// tick.bid, tick.ask, tick.last, tick.volume, tick.time
Key Functions
| Function | Purpose |
|---|---|
CopyRates() |
Bulk OHLCV data |
CopyOpen/High/Low/Close() |
Individual price arrays |
CopyTime() |
Bar open times |
CopyBuffer() |
Indicator buffer values |
iBars() |
Bar count for symbol/period |
iBarShift() |
Bar index by time |
iTime() |
Bar open time by shift |
SymbolInfoTick() |
Current tick data |
5. Risk Management and Lot Sizing
Fixed Percentage Risk
double CalculateLotSize(double riskPercent, double slPoints) {
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = accountBalance * riskPercent / 100.0;
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if (tickValue == 0 || tickSize == 0 || slPoints == 0) return 0;
double slMoneyPerLot = (slPoints * point / tickSize) * tickValue;
double lot = riskAmount / slMoneyPerLot;
// Normalize to broker constraints
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lot = MathFloor(lot / lotStep) * lotStep;
lot = MathMax(lot, minLot);
lot = MathMin(lot, maxLot);
return NormalizeDouble(lot, 2);
}
Risk-to-Reward Ratio
// Minimum 1:2 RR
double slDistance = MathAbs(price - sl);
double tpDistance = slDistance * 2; // 1:2 minimum
double tp = (orderType == ORDER_TYPE_BUY) ? price + tpDistance : price - tpDistance;
Position Sizing Rules
- Never risk more than 1-2% per trade
- Calculate lot size from risk amount and SL distance
- Normalize to broker's lot step and min/max constraints
- Account for spread when calculating SL distance
6. Backtesting and Optimization
Strategy Tester
The Strategy Tester is built into MT5. Key concepts:
- Single Test: run EA once with fixed parameters
- Optimization: genetic algorithm searches parameter space
- Custom Criterion:
OnTester()returns optimization value
OnTester Handler
double OnTester() {
// Called after each test pass
// Return value used as "Custom max" optimization criterion
double profit = TesterStatistics(STAT_PROFIT);
double dd = TesterStatistics(STAT_BALANCE_DDREL_PERCENT);
double trades = TesterStatistics(STAT_TRADES);
double pf = TesterStatistics(STAT_PROFIT_FACTOR);
double sharpe = TesterStatistics(STAT_SHARPE_RATIO);
// Minimum trade count filter
if (trades < 50) return 0;
// Custom criterion: profit factor * (1 - max drawdown%)
return pf * (1.0 - dd / 100.0);
}
Key Statistics
| Stat | Description |
|---|---|
STAT_PROFIT |
Net profit/loss |
STAT_PROFIT_FACTOR |
Gross profit / gross loss |
STAT_BALANCE_DDREL_PERCENT |
Max balance drawdown % |
STAT_SHARPE_RATIO |
Sharpe ratio |
STAT_TRADES |
Number of trades |
STAT_PROFIT_TRADES |
Winning trades |
STAT_LOSS_TRADES |
Losing trades |
STAT_EXPECTED_PAYOFF |
Average profit per trade |
STAT_RECOVERY_FACTOR |
Profit / max drawdown |
Backtesting Workflow
- Code the EA with
OnTick(),OnInit(),OnDeinit() - Add
OnTester()for custom optimization criterion - In MT5: Strategy Tester → select EA → set symbol/timeframe/period
- Choose "Open prices only" for speed, "Every tick" for accuracy
- Run single test → check results
- Run optimization → find best parameters
- Validate with out-of-sample data
Automated Backtesting Loop
EA Development Cycle:
Code → Compile → Single Test → Check Results
↓
If promising → Optimize → Analyze Results
↓
If validated → Forward Test → Deploy
↓
Monitor → Collect Data → Refine → Repeat
7. Event Handlers Reference
| Handler | When Called | Use Case |
|---|---|---|
OnInit() |
EA/indicator starts | Initialize handles, variables |
OnDeinit() |
EA/indicator stops | Cleanup, release handles |
OnTick() |
New tick received | EA main logic |
OnTimer() |
Timer event | Periodic operations |
OnTrade() |
Trade event | React to trade changes |
OnTradeTransaction() |
Trade transaction | Detailed trade tracking |
OnChartEvent() |
Chart interaction | GUI buttons, objects |
OnCalculate() |
Indicator calculation | Indicator main logic |
OnTester() |
Test complete | Custom optimization criterion |
OnTesterInit() |
Optimization start | Setup for optimization |
OnTesterPass() |
Each optimization pass | Log intermediate results |
8. Common Pitfalls
- Always check
ResultRetcode()afterPositionOpen()— success != execution - Use
SetExpertMagicNumber()to distinguish your EA's trades - Normalize prices with
SymbolInfoInteger(_Symbol, SYMBOL_DIGITS) - Check
Bars() > Nbefore trading to ensure enough history - Use
ArraySetAsSeries(true)for timeseries arrays (index 0 = latest) - Release indicator handles in
OnDeinit()withIndicatorRelease() - Don't trade on
OnInit()— wait for firstOnTick() - Account type matters: Hedging requires iterating positions, Netting uses select
- Spread varies: use
SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)for live spread - Timer in tester: use
EventSetTimer()inOnInit(), not hardcoded delays
9. Quick Reference — EA Skeleton
//+------------------------------------------------------------------+
//| MyExpertAdvisor.mq5 |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property link ""
#property version "1.00"
#include <Trade\Trade.mqh>
input double RiskPercent = 1.0; // Risk % per trade
input int Slippage = 10; // Max slippage in points
input int MagicNumber = 12345; // EA magic number
#define EA_MAGIC MagicNumber
CTrade trade;
bool IsHedging;
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
int OnInit() {
IsHedging = ((ENUM_ACCOUNT_MARGIN_MODE)
AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
trade.SetExpertMagicNumber(EA_MAGIC);
trade.SetMarginMode();
trade.SetTypeFillingBySymbol(Symbol());
trade.SetDeviationInPoints(Slippage);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
// Cleanup
}
//+------------------------------------------------------------------+
void OnTick() {
// New bar check
datetime barTime = iTime(_Symbol, _Period, 0);
if (barTime == lastBarTime) return;
lastBarTime = barTime;
// Analysis and trading logic here
// ...
}
//+------------------------------------------------------------------+
double OnTester() {
// Custom optimization criterion
double trades = TesterStatistics(STAT_TRADES);
if (trades < 30) return 0;
return TesterStatistics(STAT_PROFIT_FACTOR);
}
10. References
In this skill
references/book/— Programming book (learning path, 581 pages)00-intro/— Introduction and IDE01-basis/— Language fundamentals02-oop/— Object-oriented programming03-common/— Common functions (strings, files, math)04-applications/— Charts, indicators, objects, events05-automation/— Trading, symbols, tester06-advanced/— Resources, SQLite, Python, OpenCL
references/docs/— API reference (4135 pages)19-trading/— Trading functions (OrderSend, PositionGet, etc.)16-series/— Timeseries access (CopyRates, CopyBuffer, etc.)26-indicators/— Built-in indicators (iMA, iRSI, iMACD, etc.)24-customind/— Custom indicator creation13-event-handlers/— Event handlers (OnTick, OnTester, etc.)34-standardlibrary/— Standard library (CTrade, CPositionInfo, etc.)