Martingale Code MQL4 — วิธีเขียน Expert Advisor
Martingale Strategy คืออะไร
Martingale เป็นกลยุทธ์การจัดการเงิน (Money Management) ที่มาจากทฤษฎีความน่าจะเป็น หลักการคือเพิ่ม Lot Size เป็น 2 เท่าหลังจากขาดทุนแต่ละครั้ง เมื่อชนะครั้งเดียวจะได้กำไรคืนทั้งหมดที่ขาดทุนไปบวกกำไรเท่ากับ Lot แรก
ตัวอย่าง เริ่มที่ 0.01 Lot ขาดทุน → เพิ่มเป็น 0.02 Lot ขาดทุนอีก → เพิ่มเป็น 0.04 Lot ชนะ → ได้กำไรคืนทั้งหมด กลับไปเริ่มที่ 0.01 Lot ข้อเสียคือถ้าขาดทุนติดกันหลายครั้ง Lot Size จะใหญ่มากจนอาจ Margin Call ดังนั้นต้องมี Risk Control ที่ดี
Martingale Expert Advisor — MQL4 Code
//+------------------------------------------------------------------+
//| MartingaleEA.mq4 — Martingale Expert Advisor |
//| พร้อม Risk Management และ Safety Features |
//+------------------------------------------------------------------+
#property copyright "SiamCafe Blog"
#property version "2.0"
#property strict
//--- Input Parameters
input double BaseLot = 0.01; // Lot เริ่มต้น
input double Multiplier = 2.0; // ตัวคูณ Lot (Martingale)
input int MaxLevel = 6; // จำนวนครั้งสูงสุดที่เพิ่ม Lot
input int TakeProfit = 30; // Take Profit (pips)
input int StopLoss = 30; // Stop Loss (pips)
input int MagicNumber = 12345; // Magic Number
input int MaxSpread = 3; // Max Spread ที่ยอมรับ (pips)
input double MaxDrawdownPct = 30.0; // Max Drawdown % ก่อนหยุดเทรด
input bool UseTimeFilter = true; // ใช้ Time Filter
input int StartHour = 8; // เริ่มเทรด (ชั่วโมง Server)
input int EndHour = 20; // หยุดเทรด (ชั่วโมง Server)
input int SignalPeriod = 14; // RSI Period สำหรับ Signal
//--- Global Variables
int currentLevel = 0;
double currentLot;
datetime lastTradeTime;
double initialBalance;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
initialBalance = AccountBalance();
currentLot = BaseLot;
currentLevel = 0;
Print("Martingale EA initialized. Balance: ", initialBalance);
Print("Base Lot: ", BaseLot, " | Max Level: ", MaxLevel);
Print("TP: ", TakeProfit, " | SL: ", StopLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// ตรวจสอบ Drawdown
if(CheckDrawdown())
{
Comment("STOPPED: Max Drawdown reached (",
MaxDrawdownPct, "%)");
return;
}
// ตรวจสอบเวลาเทรด
if(UseTimeFilter && !IsTradeTime())
return;
// ตรวจสอบ Spread
double spread = MarketInfo(Symbol(), MODE_SPREAD);
if(spread > MaxSpread * 10)
return;
// ตรวจสอบว่ามี Order เปิดอยู่หรือไม่
if(CountOpenOrders() > 0)
return;
// ตรวจสอบ Order ล่าสุดว่าชนะหรือแพ้
CheckLastOrder();
// คำนวณ Signal
int signal = GetSignal();
if(signal == 1) // Buy Signal
OpenOrder(OP_BUY);
else if(signal == -1) // Sell Signal
OpenOrder(OP_SELL);
}
//+------------------------------------------------------------------+
//| คำนวณ Trading Signal ด้วย RSI |
//+------------------------------------------------------------------+
int GetSignal()
{
double rsi = iRSI(Symbol(), PERIOD_CURRENT, SignalPeriod, PRICE_CLOSE, 0);
double rsi_prev = iRSI(Symbol(), PERIOD_CURRENT, SignalPeriod, PRICE_CLOSE, 1);
// RSI Oversold → Buy
if(rsi_prev < 30 && rsi >= 30)
return 1;
// RSI Overbought → Sell
if(rsi_prev > 70 && rsi <= 70)
return -1;
return 0; // No Signal
}
//+------------------------------------------------------------------+
//| เปิด Order |
//+------------------------------------------------------------------+
void OpenOrder(int orderType)
{
double price, sl, tp;
double point = MarketInfo(Symbol(), MODE_POINT);
int digits = (int)MarketInfo(Symbol(), MODE_DIGITS);
// ปรับ Point สำหรับ 5-digit broker
double pip = point;
if(digits == 3 || digits == 5)
pip = point * 10;
if(orderType == OP_BUY)
{
price = Ask;
sl = NormalizeDouble(price - StopLoss * pip, digits);
tp = NormalizeDouble(price + TakeProfit * pip, digits);
}
else
{
price = Bid;
sl = NormalizeDouble(price + StopLoss * pip, digits);
tp = NormalizeDouble(price - TakeProfit * pip, digits);
}
// ตรวจสอบ Lot Size
double lotSize = CalculateLotSize();
if(lotSize <= 0) return;
int ticket = OrderSend(Symbol(), orderType, lotSize, price,
3, sl, tp, "Martingale EA",
MagicNumber, 0, clrGreen);
if(ticket > 0)
{
Print("Order opened: ", orderType == OP_BUY ? "BUY" : "SELL",
" | Lot: ", lotSize, " | Level: ", currentLevel,
" | Price: ", price);
lastTradeTime = TimeCurrent();
}
else
{
Print("Order failed: Error ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| คำนวณ Lot Size ตาม Martingale Level |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
double lot = BaseLot * MathPow(Multiplier, currentLevel);
// ตรวจสอบ Max Lot
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
lot = MathMin(lot, maxLot);
lot = MathMax(lot, minLot);
lot = NormalizeDouble(lot / lotStep, 0) * lotStep;
// ตรวจสอบ Margin
double marginRequired = MarketInfo(Symbol(), MODE_MARGINREQUIRED) * lot;
if(marginRequired > AccountFreeMargin() * 0.8)
{
Print("Not enough margin. Required: ", marginRequired,
" Free: ", AccountFreeMargin());
return 0;
}
return lot;
}
//+------------------------------------------------------------------+
//| ตรวจสอบ Order ล่าสุด |
//+------------------------------------------------------------------+
void CheckLastOrder()
{
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderProfit() >= 0)
{
// ชนะ — Reset กลับ Level 0
currentLevel = 0;
Print("WIN: Reset to Level 0");
}
else
{
// แพ้ — เพิ่ม Level (ถ้าไม่เกิน Max)
if(currentLevel < MaxLevel)
{
currentLevel++;
Print("LOSS: Increase to Level ", currentLevel);
}
else
{
// เกิน Max Level — Reset
currentLevel = 0;
Print("MAX LEVEL reached. Reset to Level 0");
}
}
break;
}
}
}
}
//+------------------------------------------------------------------+
//| นับ Open Orders |
//+------------------------------------------------------------------+
int CountOpenOrders()
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| ตรวจสอบ Drawdown |
//+------------------------------------------------------------------+
bool CheckDrawdown()
{
double currentBalance = AccountBalance();
double drawdown = (initialBalance - currentBalance) / initialBalance * 100;
return (drawdown >= MaxDrawdownPct);
}
//+------------------------------------------------------------------+
//| ตรวจสอบเวลาเทรด |
//+------------------------------------------------------------------+
bool IsTradeTime()
{
int hour = Hour();
return (hour >= StartHour && hour < EndHour);
}
Risk Management Table
| Level | Lot Size | ถ้าชนะ (30 pips) | สะสมขาดทุน | Margin ที่ต้องใช้ (EURUSD) |
|---|---|---|---|---|
| 0 | 0.01 | $3.00 | $0 | ~$11 |
| 1 | 0.02 | $6.00 | -$3.00 | ~$22 |
| 2 | 0.04 | $12.00 | -$9.00 | ~$44 |
| 3 | 0.08 | $24.00 | -$21.00 | ~$88 |
| 4 | 0.16 | $48.00 | -$45.00 | ~$176 |
| 5 | 0.32 | $96.00 | -$93.00 | ~$352 |
| 6 | 0.64 | $192.00 | -$189.00 | ~$704 |
Python Script วิเคราะห์ Martingale Risk
# martingale_analysis.py — วิเคราะห์ความเสี่ยง Martingale
import random
import statistics
def simulate_martingale(base_lot=0.01, multiplier=2.0, max_level=6,
tp_pips=30, sl_pips=30, win_rate=0.55,
initial_balance=1000, num_trades=1000,
pip_value=10):
"""จำลอง Martingale Strategy"""
balance = initial_balance
level = 0
max_drawdown = 0
peak_balance = balance
trades = []
consecutive_losses = 0
max_consecutive = 0
for i in range(num_trades):
lot = base_lot * (multiplier ** level)
# Random win/loss based on win_rate
if random.random() < win_rate:
profit = lot * tp_pips * pip_value
balance += profit
trades.append({"trade": i, "result": "win", "lot": lot,
"profit": profit, "balance": balance,
"level": level})
level = 0 # Reset
consecutive_losses = 0
else:
loss = lot * sl_pips * pip_value
balance -= loss
trades.append({"trade": i, "result": "loss", "lot": lot,
"profit": -loss, "balance": balance,
"level": level})
consecutive_losses += 1
max_consecutive = max(max_consecutive, consecutive_losses)
if level < max_level:
level += 1
else:
level = 0 # Reset at max level
# Track drawdown
peak_balance = max(peak_balance, balance)
drawdown = (peak_balance - balance) / peak_balance * 100
max_drawdown = max(max_drawdown, drawdown)
# Margin Call check
if balance <= 0:
print(f"MARGIN CALL at trade {i}!")
break
profits = [t["profit"] for t in trades]
wins = [t for t in trades if t["result"] == "win"]
print(f"=== Martingale Simulation ===")
print(f"Trades: {len(trades)}")
print(f"Win Rate: {len(wins)/len(trades)*100:.1f}%")
print(f"Final Balance: ")
print(f"Net Profit: ")
print(f"Max Drawdown: {max_drawdown:.1f}%")
print(f"Max Consecutive Losses: {max_consecutive}")
print(f"Avg Profit/Trade: ")
return trades, balance
# จำลอง 10 ครั้ง
results = []
for run in range(10):
_, final = simulate_martingale(win_rate=0.55, num_trades=500)
results.append(final)
print(f"\n=== 10 Simulations Summary ===")
print(f"Avg Final Balance: ")
print(f"Min: | Max: ")
print(f"Profitable: {sum(1 for r in results if r > 1000)}/10")
ข้อควรระวังและ Best Practices
- กำหนด Max Level: จำกัดจำนวนครั้งที่เพิ่ม Lot เช่น 5-7 ครั้ง เกินนี้ Reset กลับ Lot เริ่มต้น
- ใช้ Stop Loss เสมอ: ทุก Order ต้องมี Stop Loss ไม่ปล่อยให้ขาดทุนไม่จำกัด
- Max Drawdown: ตั้งขีดจำกัด Drawdown เช่น 30% เมื่อถึงให้หยุดเทรดอัตโนมัติ
- Backtest อย่างละเอียด: ทดสอบหลาย Period หลาย Symbol หลายสภาวะตลาด
- Demo ก่อน Live: ทดสอบบน Demo Account อย่างน้อย 3 เดือนก่อนใช้เงินจริง
- เงินทุนเพียงพอ: ต้องมีเงินทุนรองรับ Worst Case เช่น ขาดทุน Max Level ติดกัน 2 รอบ
- ไม่เหมาะกับทุกตลาด: Martingale ทำงานดีในตลาด Ranging ไม่ดีในตลาด Trending แรง
Martingale Strategy คืออะไร
Martingale เพิ่ม Lot Size 2 เท่าหลังขาดทุน ชนะครั้งเดียวได้กำไรคืนทั้งหมด ข้อเสียคือ Lot Size ใหญ่มากเมื่อขาดทุนติดกันหลายครั้ง อาจ Margin Call ต้องมี Risk Control ที่ดี