SiamCafe · Blog
MQL5 Book — รวมความรู้เทรด Forex ด้วย MQL5
บทความ

MQL5 Book — รวมความรู้เทรด Forex ด้วย MQL5

เผยแพร่ 28 พฤษภาคม 2569

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 ที่ทรงพลัง