De complete V6-strategie (Opening Range Breakout + Filter B + ATR 1.5) als gratis MetaTrader 5 Expert Advisor. Backtest-gevalideerd op NQ 5-minuten data 2020–2026: PF 1.56 · WR 35% · MDD −5.8%.
Het Expert Advisor bronbestand (MQL5). Kopieer naar MQL5/Experts/, compileer in MetaEditor (F7) en hang hem aan een US100/NAS100 M5-chart. v1.10: entries via pending BUY/SELL STOP-orders — dezelfde trigger als de live bot.
Volledige installatiegids: tijdzone-tabel (servertijd), VOLUME_SCALE voor CFD-puntwaarden, alle inputs, Telegram-setup en aanbevolen werkwijze.
⬇ Download READMEDe complete Expert Advisor-broncode — kopieer hem direct, of download het .mq5-bestand hierboven.
//+------------------------------------------------------------------+
//| ORB_V6_EA.mq5 |
//| ORB Ares 2 V6 — Filter B (ORB-ligging) + ATR 1.5 momentum |
//| |
//| Volledige V6-logica (gevalideerd op NQ 5m, 2020-2026): |
//| PF 1.56 · WR 35% · MDD -5.8% (futures, Ares-sizing) |
//| |
//| v1.10 (28 aug 2026): entry via PENDING STOP-orders |
//| (BUY STP boven ORB-high / SELL STP onder ORB-low) — zelfde |
//| trigger als de live bot (25 aug). SL 45pt hangt aan de order. |
//| |
//| Tijden in SERVER-tijd. Default = EU-tijd (CET/CEST): |
//| ORB 09:00-09:30 ET = 15:00-15:30 EU |
//| EOD 15:55 ET = 21:55 EU |
//| (EU is altijd 6 uur vóór ET — zomer én winter) |
//| |
//| Sizing: Ares = max(1, round(0.31 * equity / 10_000)) lots |
//| Alerts: Telegram (WebRequest) + MT5 Alert + Notifications |
//+------------------------------------------------------------------+
#property copyright "Symtrade"
#property version "1.14"
#property strict
#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
//| INPUTS |
//+------------------------------------------------------------------+
input group "=== Tijden (SERVER-tijd) ==="
input int ORB_START_HOUR = 15; // ORB start uur (default EU: 15 = 09:00 ET)
input int ORB_START_MIN = 0; // ORB start minuut
input int ORB_END_HOUR = 15; // ORB einde uur (default EU: 15 = 09:30 ET)
input int ORB_END_MIN = 30; // ORB einde minuut
input int EOD_HOUR = 21; // EOD exit uur (default EU: 21 = 15:55 ET)
input int EOD_MIN = 55; // EOD exit minuut
input group "=== Strategie (V6) ==="
input double LONG_BUFFER = 10.0; // LONG buffer boven ORB-high (pt)
input double SHORT_BUFFER = 75.0; // SHORT buffer onder ORB-low (pt)
input double STOP_PTS = 45.0; // Stop loss (pt)
input double MIN_ORB_RANGE = 20.0; // Minimale ORB-range (pt)
input bool FILTER_B = true; // Filter B: LONG alleen als ORB boven vorige close
input double ATR_MULT = 1.5; // ATR momentum multiplier
input int ATR_LEN = 14; // ATR periode (bars)
input group "=== Sizing ==="
input string SIZING_MODE = "ares"; // "ares" of "fixed"
input double FIXED_VOLUME = 1.0; // Volume bij SIZING_MODE=fixed
input double VOLUME_SCALE = 1.0; // Schaal op Ares-lots (CFD-puntwaarde-correctie)
input double MAX_VOLUME = 5.0; // Veiligheidslimiet: max lots per trade
input group "=== Alerts ==="
input bool USE_TELEGRAM = true; // Telegram via WebRequest
input string TG_TOKEN = ""; // Bot token
input string TG_CHAT_ID = ""; // Chat ID
input bool USE_ALERT = true; // MT5 Alert() popup
input bool USE_NOTIFY = false; // MT5 push-notificatie
//+------------------------------------------------------------------+
//| GLOBALS |
//+------------------------------------------------------------------+
string g_symbol;
double g_orb_high = 0, g_orb_low = 0;
bool g_orb_complete = false;
string g_orb_date = "";
bool g_trade_done = false; // order geplaatst of dag geblokkeerd
double g_prev_close = 0;
bool g_prev_close_ok = false;
datetime g_last_bar_time = 0;
string g_last_tg_day = "";
ulong g_magic = 20260828; // eigen magic (niet afhankelijk van CTrade-getter)
bool g_order_placed = false; // pending STOP-order staat open
bool g_fill_notified = false; // fill-melding verstuurd
//+------------------------------------------------------------------+
//| Helpers |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime t = iTime(g_symbol, PERIOD_M5, 0);
if(t != g_last_bar_time)
{
g_last_bar_time = t;
return true;
}
return false;
}
string TodayStr()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
return StringFormat("%04d-%02d-%02d", dt.year, dt.mon, dt.day);
}
double GetPrevDayClose()
{
// Close van de vorige dag (D1 bar, shift 1) — voor Filter B
return iClose(g_symbol, PERIOD_D1, 1);
}
bool HasPendingOrder()
{
for(int i = 0; i < OrdersTotal(); i++)
{
ulong ticket = OrderGetTicket(i);
if(ticket == 0) continue;
if(OrderGetString(ORDER_SYMBOL) == g_symbol &&
OrderGetInteger(ORDER_MAGIC) == g_magic)
return true;
}
return false;
}
void DeletePendingOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong ticket = OrderGetTicket(i);
if(ticket == 0) continue;
if(OrderGetString(ORDER_SYMBOL) == g_symbol &&
OrderGetInteger(ORDER_MAGIC) == g_magic)
{
if(trade.OrderDelete(ticket))
Print("🧹 Pending order verwijderd: #", ticket);
}
}
}
//+------------------------------------------------------------------+
//| Normaliseer volume binnen broker-limieten |
//+------------------------------------------------------------------+
double NormalizeVol(double vol)
{
// Expliciete SymbolInfoDouble (waterdicht; geen afhankelijkheid van macro's)
double minv = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_MIN);
double maxv = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_STEP);
vol = MathMax(minv, MathMin(maxv, vol));
if(step > 0)
vol = MathRound(vol / step) * step;
return vol;
}
//+------------------------------------------------------------------+
//| Ares-sizing: qty = max(1, round(0.31 * equity / 10_000)) |
//+------------------------------------------------------------------+
double AresVolume()
{
double eq = AccountInfoDouble(ACCOUNT_EQUITY);
int lots = (int)MathMax(1, MathRound(0.31 * eq / 10000.0));
double v = NormalizeVol(lots * VOLUME_SCALE);
Print("🔍 AresVolume: eq=", DoubleToString(eq, 2),
" → lots=", lots, " scale=", DoubleToString(VOLUME_SCALE, 2),
" → vol=", DoubleToString(v, 2));
return v;
}
//+------------------------------------------------------------------+
//| ATR14: gemiddelde range van de ATR_LEN bars vóór shift |
//+------------------------------------------------------------------+
double CalcATR(int shift)
{
double sum = 0;
for(int k = 1; k <= ATR_LEN; k++)
{
double h = iHigh(g_symbol, PERIOD_M5, shift + k);
double l = iLow(g_symbol, PERIOD_M5, shift + k);
if(h <= 0 || l <= 0) return -1;
sum += (h - l);
}
return sum / ATR_LEN;
}
//+------------------------------------------------------------------+
//| URL-encode voor Telegram |
//+------------------------------------------------------------------+
string UrlEncode(string s)
{
string out = "";
for(int i = 0; i < StringLen(s); i++)
{
ushort c = StringGetCharacter(s, i);
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
|| c == '-' || c == '_' || c == '.' || c == '~')
out += ShortToString(c);
else
out += StringFormat("%%%02X", c);
}
return out;
}
//+------------------------------------------------------------------+
//| Telegram versturen via WebRequest |
//+------------------------------------------------------------------+
bool SendTelegram(string msg)
{
if(!USE_TELEGRAM || StringLen(TG_TOKEN) == 0 || StringLen(TG_CHAT_ID) == 0)
return false;
string url = "https://api.telegram.org/bot" + TG_TOKEN + "/sendMessage";
string body = "chat_id=" + TG_CHAT_ID + "&text=" + UrlEncode(msg) + "&parse_mode=HTML";
uchar post[];
uchar result[];
string headers;
StringToCharArray(body, post, 0, StringLen(body));
ResetLastError();
int code = WebRequest("POST", url, "", NULL, 5000, post, ArraySize(post), result, headers);
if(code == -1)
{
Print("⚠️ Telegram WebRequest fout (", GetLastError(),
") — zet api.telegram.org in Tools > Options > Expert Advisors > Allow WebRequest");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Alert versturen (Telegram + MT5 popup + push) |
//+------------------------------------------------------------------+
void Notify(string msg)
{
Print(msg);
if(USE_ALERT) Alert(msg);
if(USE_NOTIFY) SendNotification(msg);
SendTelegram(msg);
}
//+------------------------------------------------------------------+
//| ORB-ligging t.o.v. vorige close ("boven"/"rond"/"onder") |
//+------------------------------------------------------------------+
string OrbPos()
{
if(!g_prev_close_ok || g_orb_high <= 0 || g_orb_low <= 0) return "";
if(g_orb_low > g_prev_close) return "boven";
if(g_orb_high < g_prev_close) return "onder";
return "rond";
}
//+------------------------------------------------------------------+
//| OnInit |
//+------------------------------------------------------------------+
int OnInit()
{
g_symbol = _Symbol;
trade.SetExpertMagicNumber(g_magic);
// Controleer minimum timeframe-data
if(iTime(g_symbol, PERIOD_M5, 0) == 0)
{
Print("❌ Geen M5-data voor ", g_symbol);
return INIT_FAILED;
}
Print("🚀 ORB V6 EA v1.13 gestart op ", g_symbol);
Print(" ORB venster: ", ORB_START_HOUR, ":", StringFormat("%02d", ORB_START_MIN),
" - ", ORB_END_HOUR, ":", StringFormat("%02d", ORB_END_MIN),
" server-tijd (default EU = 09:00-09:30 ET)");
Print(" EOD exit: ", EOD_HOUR, ":", StringFormat("%02d", EOD_MIN), " server-tijd");
Print(" Filter B: ", (FILTER_B ? "AAN" : "UIT"),
" | ATR ", ATR_MULT, "x", ATR_LEN,
" | Stop ", STOP_PTS, "pt | Min range ", MIN_ORB_RANGE, "pt");
Print(" Entry: pending STOP-orders (BUY STP / SELL STP)");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| OnDeinit |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("ORB V6 EA gestopt (reason=", reason, ")");
}
//+------------------------------------------------------------------+
//| OnTick |
//+------------------------------------------------------------------+
void OnTick()
{
// Alleen handelen op nieuwe M5-bar (lookahead-vrij)
if(!IsNewBar()) return;
datetime now = TimeCurrent();
MqlDateTime dt;
TimeToStruct(now, dt);
int cur_min = dt.hour * 60 + dt.min;
int orb_start = ORB_START_HOUR * 60 + ORB_START_MIN;
int orb_end = ORB_END_HOUR * 60 + ORB_END_MIN;
int eod = EOD_HOUR * 60 + EOD_MIN;
string today = TodayStr();
// ─── Dagelijkse reset ──────────────────────────────────────────
if(g_orb_date != today)
{
g_orb_date = today;
g_orb_high = 0;
g_orb_low = 0;
g_orb_complete = false;
g_trade_done = false;
g_order_placed = false;
g_fill_notified = false;
g_prev_close = GetPrevDayClose();
g_prev_close_ok = (g_prev_close > 0);
DeletePendingOrders(); // veiligheid: restanten van gisteren opruimen
Print("📅 ", today, " | prev close = ", (g_prev_close_ok ? DoubleToString(g_prev_close, _Digits) : "n/a"));
}
// ─── ORB accumuleren binnen venster ────────────────────────────
if(!g_orb_complete && cur_min >= orb_start && cur_min < orb_end)
{
double h = iHigh(g_symbol, PERIOD_M5, 1); // vorige gesloten bar
double l = iLow(g_symbol, PERIOD_M5, 1);
if(h > 0 && l > 0)
{
if(g_orb_high == 0 || h > g_orb_high) g_orb_high = h;
if(g_orb_low == 0 || l < g_orb_low) g_orb_low = l;
}
}
// ─── ORB compleet melden ───────────────────────────────────────
if(!g_orb_complete && cur_min >= orb_end && g_orb_high > 0 && g_orb_low > 0)
{
g_orb_complete = true;
double range = g_orb_high - g_orb_low;
string opos = OrbPos();
string fb = (FILTER_B && opos != "") ? (" · Filter B: " + opos) : "";
Print("📊 ORB compleet: H=", g_orb_high, " L=", g_orb_low,
" range=", range, "pt", fb);
if(g_last_tg_day != today)
{
g_last_tg_day = today;
string msg = "📊 <b>ORB V6 — " + g_symbol + "</b>\n"
+ "ORB: H=" + DoubleToString(g_orb_high, _Digits)
+ " · L=" + DoubleToString(g_orb_low, _Digits)
+ " · range=" + DoubleToString(range, 1) + "pt"
+ (fb != "" ? "\n" + fb : "")
+ "\nLONG ≥ " + DoubleToString(g_orb_high + LONG_BUFFER, _Digits)
+ " · SHORT ≤ " + DoubleToString(g_orb_low - SHORT_BUFFER, _Digits);
SendTelegram(msg);
}
if(range < MIN_ORB_RANGE)
{
Notify("⚪ ORB V6: range " + DoubleToString(range, 1) + "pt < " +
DoubleToString(MIN_ORB_RANGE, 1) + "pt → geen trade vandaag");
g_trade_done = true; // blokkeer entries
}
}
// ─── EOD: positie sluiten + pending orders opruimen ────────────
if(cur_min >= eod)
{
if(PositionSelect(g_symbol))
{
double close = iClose(g_symbol, PERIOD_M5, 1);
if(close > 0)
{
trade.PositionClose(g_symbol);
Notify("🕓 ORB V6 EOD: positie gesloten @ " + DoubleToString(close, _Digits));
}
g_trade_done = true;
}
DeletePendingOrders();
g_order_placed = false;
return;
}
// ─── Fill-detectie: pending STOP werd gevuld ───────────────────
if(g_order_placed && !g_fill_notified && PositionSelect(g_symbol))
{
g_fill_notified = true;
Notify("✅ ORB V6: STOP-entry GEVULD — positie open (" + g_symbol + ")");
}
// ─── Entry-check ───────────────────────────────────────────────
if(g_trade_done || !g_orb_complete || g_orb_high <= 0)
return;
if(PositionSelect(g_symbol) || HasPendingOrder())
return;
// ATR-momentum check op de vorige gesloten bar (shift 1)
double atr14 = CalcATR(1);
if(atr14 < 0)
return;
double bar_range = iHigh(g_symbol, PERIOD_M5, 1) - iLow(g_symbol, PERIOD_M5, 1);
if(bar_range < ATR_MULT * atr14)
return; // zwakke bar: geen momentum
double close1 = iClose(g_symbol, PERIOD_M5, 1);
double long_level = g_orb_high + LONG_BUFFER;
double short_level = g_orb_low - SHORT_BUFFER;
string opos = OrbPos();
int direction = 0;
if(close1 >= long_level)
{
if(FILTER_B && opos != "" && opos != "boven")
return; // Filter B: LONG alleen als ORB boven
direction = 1; // LONG
}
else if(close1 <= short_level)
{
if(FILTER_B && opos == "rond")
return; // Filter B: SHORT niet als ORB rond
direction = -1; // SHORT
}
else
return;
// Sizing (met MAX_VOLUME veiligheidslimiet)
double vol = (SIZING_MODE == "ares") ? AresVolume() : NormalizeVol(FIXED_VOLUME);
vol = NormalizeVol(MathMin(vol, MAX_VOLUME));
Print("🔍 Entry vol=", DoubleToString(vol, 2), " (MAX_VOLUME=", DoubleToString(MAX_VOLUME, 2), ")");
// Pending STOP-order op het level (zelfde trigger als live bot, 25 aug).
// MT5-eis: BUY STOP > Ask, SELL STOP < Bid. Als de close het level al
// gepasseerd heeft, is de pending order ongeldig ([Invalid price]) →
// direct markt-order (zelfde effect als een STP die direct triggert).
double tp = 0; // geen TP — EOD/stop
bool ok = false;
bool as_pending = false;
double entry_ref = 0;
double sl_used = 0;
if(direction == 1)
{
entry_ref = long_level;
sl_used = long_level - STOP_PTS;
ok = trade.BuyStop(vol, long_level, g_symbol, sl_used, tp, ORDER_TIME_GTC, 0, "ORB-V6 LONG STP");
if(ok)
as_pending = true;
else
{
double ask = SymbolInfoDouble(g_symbol, SYMBOL_ASK);
entry_ref = ask;
sl_used = ask - STOP_PTS;
ok = trade.Buy(vol, g_symbol, 0.0, sl_used, tp, "ORB-V6 LONG");
}
}
else
{
entry_ref = short_level;
sl_used = short_level + STOP_PTS;
ok = trade.SellStop(vol, short_level, g_symbol, sl_used, tp, ORDER_TIME_GTC, 0, "ORB-V6 SHORT STP");
if(ok)
as_pending = true;
else
{
double bid = SymbolInfoDouble(g_symbol, SYMBOL_BID);
entry_ref = bid;
sl_used = bid + STOP_PTS;
ok = trade.Sell(vol, g_symbol, 0.0, sl_used, tp, "ORB-V6 SHORT");
}
}
if(ok)
{
g_trade_done = true;
g_order_placed = as_pending;
if(as_pending)
Notify("📤 ORB V6 " + (direction == 1 ? "LONG" : "SHORT") +
" entry geplaatst (STP) @ " + DoubleToString(entry_ref, _Digits) +
" vol=" + DoubleToString(vol, 2) + " · SL=" + DoubleToString(sl_used, _Digits) +
" — wacht op trigger" +
(FILTER_B && opos != "" ? " (Filter B: " + opos + ")" : ""));
else
Notify("⚡ ORB V6 " + (direction == 1 ? "LONG" : "SHORT") +
" entry DIRECT (MKT — level al gepasseerd) @ " + DoubleToString(entry_ref, _Digits) +
" · SL=" + DoubleToString(sl_used, _Digits) +
(FILTER_B && opos != "" ? " (Filter B: " + opos + ")" : ""));
}
else
{
Print("❌ Order mislukt: ", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
MQL5/Experts/https://api.telegram.org (Extra → Opties → Expert Advisors)De EA werkt in de servertijd van je broker. Defaults zijn EU-tijd (CET/CEST). EU is altijd 6 uur vóór ET:
| Broker-servertijd | ORB (09:00–09:30 ET) | EOD (15:55 ET) |
|---|---|---|
| EU (CET/CEST) | 15:00–15:30 | 21:55 |
| GMT+3 (veel CFD-brokers) | 16:00–16:30 | 22:55 |
| GMT+2 | 15:00–15:30 | 21:55 |
Controleer je servertijd in MT5 (Marktkoersen → server-kolom). Verkeerde tijden = verkeerde ORB = verkeerde trades. Zie de README voor VOLUME_SCALE (CFD-puntwaarde).
Deze Expert Advisor wordt uitsluitend voor educatieve doeleinden aangeboden. Handelen brengt aanzienlijk risico op verlies met zich mee; historische resultaten garanderen geen toekomstige prestaties. Test altijd eerst op een demo-account. Zie onze volledige disclaimer.