MQL5 Book — รวมความรู้เทรด Forex ด้วย MQL5
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 ที่ทรงพลัง