MQL5 คืออะไร
MQL5 (MetaQuotes Language 5) เป็นภาษาโปรแกรมสำหรับพัฒนา Trading Applications บน MetaTrader 5 ซึ่งเป็นแพลตฟอร์มเทรดที่นิยมที่สุดในโลก MQL5 รองรับ Object-Oriented Programming (OOP) เต็มรูปแบบ มี Standard Library ที่ครบครัน และ Strategy Tester ที่ทรงพลังสำหรับ Backtest
เมื่อเทียบกับ MQL4 ที่เป็น Procedural เป็นหลัก MQL5 มีความสามารถมากกว่า รองรับ Classes, Inheritance, Polymorphism, Templates และ Event-driven Programming ทำให้เขียน Code ที่ซับซ้อนได้ง่ายขึ้น
โครงสร้างพื้นฐาน MQL5 Expert Advisor
//+------------------------------------------------------------------+
//| BasicEA.mq5 — โครงสร้างพื้นฐาน Expert Advisor |
//+------------------------------------------------------------------+
#property copyright "SiamCafe Blog"
#property version "1.0"
#property strict
// Include Standard Library
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Indicators\Trend.mqh>
// Input Parameters
input group "=== Trading Settings ==="
input double InpLotSize = 0.01; // Lot Size
input int InpStopLoss = 50; // Stop Loss (points)
input int InpTakeProfit = 100; // Take Profit (points)
input int InpMagic = 12345; // Magic Number
input group "=== Indicator Settings ==="
input int InpFastMA = 10; // Fast MA Period
input int InpSlowMA = 20; // Slow MA Period
input ENUM_MA_METHOD InpMAMethod = MODE_EMA; // MA Method
input group "=== Risk Management ==="
input double InpMaxRisk = 2.0; // Max Risk % per Trade
input int InpMaxTrades = 3; // Max Open Trades
// Global Objects
CTrade trade;
CPositionInfo posInfo;
CSymbolInfo symInfo;
// Indicator Handles
int handleFastMA;
int handleSlowMA;
// Buffers
double fastMA[];
double slowMA[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// ตั้งค่า Trade Object
trade.SetExpertMagicNumber(InpMagic);
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// สร้าง Indicator Handles
handleFastMA = iMA(_Symbol, PERIOD_CURRENT, InpFastMA, 0,
InpMAMethod, PRICE_CLOSE);
handleSlowMA = iMA(_Symbol, PERIOD_CURRENT, InpSlowMA, 0,
InpMAMethod, PRICE_CLOSE);
if(handleFastMA == INVALID_HANDLE || handleSlowMA == INVALID_HANDLE)
{
Print("Error creating indicator handles");
return(INIT_FAILED);
}
// Set arrays as series
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);
Print("EA initialized successfully");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
IndicatorRelease(handleFastMA);
IndicatorRelease(handleSlowMA);
Print("EA deinitialized. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// ตรวจสอบ New Bar
if(!IsNewBar())
return;
// Copy indicator data
if(CopyBuffer(handleFastMA, 0, 0, 3, fastMA) < 3) return;
if(CopyBuffer(handleSlowMA, 0, 0, 3, slowMA) < 3) return;
// Update Symbol Info
symInfo.Name(_Symbol);
symInfo.RefreshRates();
// ตรวจสอบ Signal
int signal = GetSignal();
// จัดการ Positions
ManagePositions(signal);
// เปิด Position ใหม่
if(signal != 0 && CountPositions() < InpMaxTrades)
OpenPosition(signal);
}
//+------------------------------------------------------------------+
//| ตรวจสอบ New Bar |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| คำนวณ Signal |
//+------------------------------------------------------------------+
int GetSignal()
{
// MA Crossover
bool fastAboveSlow = fastMA[1] > slowMA[1];
bool fastBelowSlow = fastMA[1] < slowMA[1];
bool prevFastAbove = fastMA[2] > slowMA[2];
bool prevFastBelow = fastMA[2] < slowMA[2];
// Golden Cross — Buy Signal
if(fastAboveSlow && prevFastBelow)
return 1;
// Death Cross — Sell Signal
if(fastBelowSlow && prevFastAbove)
return -1;
return 0;
}
//+------------------------------------------------------------------+
//| เปิด Position |
//+------------------------------------------------------------------+
void OpenPosition(int signal)
{
double price, sl, tp;
double point = symInfo.Point();
double lot = CalculateLotSize();
if(lot <= 0) return;
if(signal == 1) // Buy
{
price = symInfo.Ask();
sl = price - InpStopLoss * point;
tp = price + InpTakeProfit * point;
trade.Buy(lot, _Symbol, price, sl, tp, "MA Cross Buy");
}
else if(signal == -1) // Sell
{
price = symInfo.Bid();
sl = price + InpStopLoss * point;
tp = price - InpTakeProfit * point;
trade.Sell(lot, _Symbol, price, sl, tp, "MA Cross Sell");
}
if(trade.ResultRetcode() == TRADE_RETCODE_DONE)
Print("Position opened: ", signal == 1 ? "BUY" : "SELL",
" Lot: ", lot);
else
Print("Trade failed: ", trade.ResultRetcodeDescription());
}
//+------------------------------------------------------------------+
//| คำนวณ Lot Size ตาม Risk % |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = balance * InpMaxRisk / 100.0;
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(tickValue == 0 || tickSize == 0) return InpLotSize;
double lot = riskAmount / (InpStopLoss * tickValue / tickSize);
// Normalize
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lot = MathMax(minLot, MathMin(maxLot, lot));
lot = MathRound(lot / lotStep) * lotStep;
return NormalizeDouble(lot, 2);
}
//+------------------------------------------------------------------+
//| นับ Positions ของ EA นี้ |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(posInfo.SelectByIndex(i))
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == InpMagic)
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| จัดการ Positions (Trailing Stop) |
//+------------------------------------------------------------------+
void ManagePositions(int signal)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(!posInfo.SelectByIndex(i)) continue;
if(posInfo.Symbol() != _Symbol || posInfo.Magic() != InpMagic) continue;
// ปิด Position ถ้า Signal กลับทิศ
if(posInfo.PositionType() == POSITION_TYPE_BUY && signal == -1)
trade.PositionClose(posInfo.Ticket());
else if(posInfo.PositionType() == POSITION_TYPE_SELL && signal == 1)
trade.PositionClose(posInfo.Ticket());
}
}
OOP Design Pattern สำหรับ MQL5
//+------------------------------------------------------------------+
//| TradingStrategy.mqh — Strategy Pattern สำหรับ MQL5 |
//+------------------------------------------------------------------+
// Base Strategy Interface
class CStrategy
{
protected:
string m_name;
string m_symbol;
ENUM_TIMEFRAMES m_period;
int m_magic;
public:
CStrategy(string name, string symbol, ENUM_TIMEFRAMES period, int magic)
: m_name(name), m_symbol(symbol), m_period(period), m_magic(magic) {}
virtual ~CStrategy() {}
// Pure Virtual Methods — ต้อง Override
virtual bool Init() = 0;
virtual void Deinit() = 0;
virtual int GetSignal() = 0;
virtual double GetLotSize() = 0;
virtual double GetStopLoss(int signal) = 0;
virtual double GetTakeProfit(int signal) = 0;
string GetName() { return m_name; }
};
// RSI Strategy Implementation
class CRSIStrategy : public CStrategy
{
private:
int m_rsiHandle;
int m_rsiPeriod;
double m_rsiOverbought;
double m_rsiOversold;
double m_rsiBuffer[];
public:
CRSIStrategy(string symbol, ENUM_TIMEFRAMES period, int magic,
int rsiPeriod=14, double ob=70, double os=30)
: CStrategy("RSI Strategy", symbol, period, magic),
m_rsiPeriod(rsiPeriod), m_rsiOverbought(ob), m_rsiOversold(os)
{
ArraySetAsSeries(m_rsiBuffer, true);
}
bool Init() override
{
m_rsiHandle = iRSI(m_symbol, m_period, m_rsiPeriod, PRICE_CLOSE);
return (m_rsiHandle != INVALID_HANDLE);
}
void Deinit() override
{
IndicatorRelease(m_rsiHandle);
}
int GetSignal() override
{
if(CopyBuffer(m_rsiHandle, 0, 0, 3, m_rsiBuffer) < 3)
return 0;
// RSI Cross Oversold → Buy
if(m_rsiBuffer[2] < m_rsiOversold && m_rsiBuffer[1] >= m_rsiOversold)
return 1;
// RSI Cross Overbought → Sell
if(m_rsiBuffer[2] > m_rsiOverbought && m_rsiBuffer[1] <= m_rsiOverbought)
return -1;
return 0;
}
double GetLotSize() override { return 0.01; }
double GetStopLoss(int signal) override { return 50 * _Point; }
double GetTakeProfit(int signal) override { return 100 * _Point; }
};
// Strategy Manager — จัดการหลาย Strategies
class CStrategyManager
{
private:
CStrategy* m_strategies[];
CTrade m_trade;
public:
~CStrategyManager()
{
for(int i = 0; i < ArraySize(m_strategies); i++)
delete m_strategies[i];
}
void AddStrategy(CStrategy* strategy)
{
int size = ArraySize(m_strategies);
ArrayResize(m_strategies, size + 1);
m_strategies[size] = strategy;
}
bool InitAll()
{
for(int i = 0; i < ArraySize(m_strategies); i++)
if(!m_strategies[i].Init())
return false;
return true;
}
void ProcessAll()
{
for(int i = 0; i < ArraySize(m_strategies); i++)
{
int signal = m_strategies[i].GetSignal();
if(signal != 0)
Print(m_strategies[i].GetName(), " Signal: ", signal);
}
}
};
Python — Backtest Analysis
# mt5_backtest.py — วิเคราะห์ผล Backtest จาก MT5
import MetaTrader5 as mt5
import pandas as pd
import numpy as np
from datetime import datetime
class MT5BacktestAnalyzer:
"""วิเคราะห์ผลการเทรดจาก MetaTrader 5"""
def __init__(self):
if not mt5.initialize():
raise RuntimeError(f"MT5 init failed: {mt5.last_error()}")
def get_deals(self, from_date, to_date, magic=None):
"""ดึงประวัติการเทรด"""
deals = mt5.history_deals_get(from_date, to_date)
if deals is None:
return pd.DataFrame()
df = pd.DataFrame(list(deals), columns=deals[0]._asdict().keys())
if magic:
df = df[df["magic"] == magic]
df["time"] = pd.to_datetime(df["time"], unit="s")
return df
def calculate_metrics(self, deals_df):
"""คำนวณ Performance Metrics"""
trades = deals_df[deals_df["entry"] == 1] # Exit deals
if len(trades) == 0:
return {}
profits = trades["profit"].values
wins = profits[profits > 0]
losses = profits[profits < 0]
total_profit = profits.sum()
win_rate = len(wins) / len(profits) * 100
avg_win = wins.mean() if len(wins) > 0 else 0
avg_loss = abs(losses.mean()) if len(losses) > 0 else 0
profit_factor = wins.sum() / abs(losses.sum()) if len(losses) > 0 else float("inf")
# Max Drawdown
cumulative = np.cumsum(profits)
peak = np.maximum.accumulate(cumulative)
drawdown = peak - cumulative
max_dd = drawdown.max()
# Sharpe Ratio (annualized)
daily_returns = pd.Series(profits).groupby(
trades["time"].dt.date
).sum()
sharpe = (daily_returns.mean() / daily_returns.std() *
np.sqrt(252)) if daily_returns.std() > 0 else 0
return {
"Total Trades": len(profits),
"Win Rate": f"{win_rate:.1f}%",
"Total Profit": f"",
"Avg Win": f"",
"Avg Loss": f"",
"Profit Factor": f"{profit_factor:.2f}",
"Max Drawdown": f"",
"Sharpe Ratio": f"{sharpe:.2f}",
"Expectancy": f"",
}
def print_report(self, metrics):
"""แสดงรายงาน"""
print("=" * 40)
print("Backtest Performance Report")
print("=" * 40)
for key, value in metrics.items():
print(f" {key:<20} {value}")
def __del__(self):
mt5.shutdown()
# ตัวอย่าง
# analyzer = MT5BacktestAnalyzer()
# deals = analyzer.get_deals(
# datetime(2024, 1, 1), datetime(2024, 12, 31), magic=12345
# )
# metrics = analyzer.calculate_metrics(deals)
# analyzer.print_report(metrics)
แหล่งเรียนรู้ MQL5
- MQL5 Reference: เอกสารอ้างอิงอย่างเป็นทางการ ครอบคลุมทุก Function และ Class
- MQL5 CodeBase: รวม Source Code จาก Community ทั้ง EA, Indicator และ Script
- MQL5 Articles: บทความสอนจากผู้เชี่ยวชาญ ครอบคลุมตั้งแต่พื้นฐานถึงขั้นสูง
- MQL5 Forum: ชุมชนถามตอบ มี Expert ช่วยตอบ
- MetaEditor: IDE ที่มากับ MT5 มี Code Completion, Debugger และ Profiler
- Strategy Tester: เครื่องมือ Backtest ที่ทรงพลัง รองรับ Multi-currency และ Optimization
MQL5 คืออะไร
MQL5 เป็นภาษาโปรแกรมสำหรับ MetaTrader 5 ใช้เขียน Expert Advisors, Custom Indicators, Scripts ไวยากรณ์คล้าย C++ รองรับ OOP เต็มรูปแบบ มี Standard Library และ Strategy Tester ที่ทรงพลัง
MQL5 ต่างจาก MQL4 อย่างไร
MQL5 รองรับ OOP เต็มรูปแบบ มี Event-driven Model ดีกว่า รองรับ Netting และ Hedging, Multi-currency Tester, Built-in Indicators มากกว่า ประสิทธิภาพสูงกว่า MQL4 ที่เป็น Procedural เป็นหลัก
เริ่มต้นเรียน MQL5 ต้องทำอย่างไร
ดาวน์โหลด MT5 เปิด MetaEditor เริ่มจากโครงสร้างโปรแกรม OnInit OnTick OnDeinit ฝึกเขียน Script ง่ายๆ ค่อยเขียน Indicator แล้ว EA ศึกษาจาก MQL5 Reference และ CodeBase
Strategy Tester ใน MT5 ใช้งานอย่างไร
เปิด Strategy Tester (Ctrl+R) เลือก EA Symbol Period Date Range เลือก Modeling Mode รัน Backtest ดู Report ใช้ Optimization หา Parameter ที่ดีที่สุด รองรับ Multi-currency และ Forward Testing
สรุป
MQL5 เป็นภาษาที่ทรงพลังสำหรับพัฒนา Trading Applications บน MetaTrader 5 รองรับ OOP เต็มรูปแบบ มี Standard Library ที่ครบครัน Strategy Tester ที่ดีเยี่ยม เริ่มจากเรียนรู้โครงสร้างพื้นฐาน แล้วใช้ OOP Design Patterns เขียน Code ที่ดูแลรักษาง่าย ใช้ Python ร่วมกับ MetaTrader5 Library สำหรับ Data Analysis และ Backtest Evaluation
