2026-03-11 01:01:25 +07:00
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//| SimpleFVG.mq5 – Fair Value Gap Visual Strategy (Test mode) |
|
|
|
|
|
|
//| |
|
|
|
|
|
|
//| Modules: |
|
|
|
|
|
|
//| Config.mqh → Step 0: Inputs, enums, constants |
|
|
|
|
|
|
//| Trend.mqh → Step 1: EMA34/EMA89 trend detection |
|
|
|
|
|
|
//| FVG.mqh → Step 2: FVG scanning & management |
|
|
|
|
|
|
//| Drawing.mqh → Step 4: Chart visualization |
|
2026-03-11 01:01:25 +07:00
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
#property copyright "SimpleFVG"
|
2026-03-11 16:06:24 +07:00
|
|
|
|
#property version "2.00"
|
|
|
|
|
|
#property description "FVG strategy visualizer – EMA trend + FVG zones on chart"
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
#include "SimpleFVG/Config.mqh"
|
|
|
|
|
|
#include "SimpleFVG/Trend.mqh"
|
|
|
|
|
|
#include "SimpleFVG/FVG.mqh"
|
2026-03-11 18:13:27 +07:00
|
|
|
|
#include "SimpleFVG/Trade.mqh"
|
2026-03-11 16:06:24 +07:00
|
|
|
|
#include "SimpleFVG/Drawing.mqh"
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//| OnInit |
|
2026-03-11 01:01:25 +07:00
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
int OnInit()
|
|
|
|
|
|
{
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//--- Step 1: Initialize trend (EMA handles + chart indicators) ---
|
|
|
|
|
|
if(!TrendInit())
|
|
|
|
|
|
return INIT_FAILED;
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//--- Step 2: Initialize FVG array ---
|
|
|
|
|
|
FVGInit();
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//--- Initial scan on existing bars ---
|
|
|
|
|
|
TrendUpdate();
|
|
|
|
|
|
FVGUpdate();
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//--- Step 4: Draw everything ---
|
|
|
|
|
|
DrawAll();
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
if(InpDebugLog)
|
|
|
|
|
|
PrintFormat("[INIT] SimpleFVG v2.0 | %s %s | EMA%d/%d | FVG lookback=%d maxAge=%d",
|
|
|
|
|
|
GetTradeSymbol(), EnumToString(InpTimeframe),
|
|
|
|
|
|
InpEMAFastPeriod, InpEMASlowPeriod,
|
|
|
|
|
|
InpFVGLookbackBars, InpFVGMaxAgeBars);
|
|
|
|
|
|
|
2026-03-19 21:41:57 +07:00
|
|
|
|
//--- Initialize last processed exit time so we don't reset based on old history.
|
|
|
|
|
|
g_LastExitDealTime = GetLatestTP_SL_ExitDealTime();
|
|
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
return INIT_SUCCEEDED;
|
2026-03-11 01:01:25 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 21:41:57 +07:00
|
|
|
|
//--- Track last processed TP/SL exit so we can reset strategy state
|
|
|
|
|
|
//--- only when a new SL/TP happens (not from older history).
|
|
|
|
|
|
datetime g_LastExitDealTime = 0;
|
|
|
|
|
|
|
|
|
|
|
|
datetime GetLatestTP_SL_ExitDealTime()
|
|
|
|
|
|
{
|
|
|
|
|
|
datetime now = TimeCurrent();
|
|
|
|
|
|
if(now == 0)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
if(!HistorySelect(0, now))
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
datetime latest = 0;
|
|
|
|
|
|
string symbol = GetTradeSymbol();
|
|
|
|
|
|
|
|
|
|
|
|
int deals = HistoryDealsTotal();
|
|
|
|
|
|
for(int i = 0; i < deals; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
ulong dealTicket = HistoryDealGetTicket(i);
|
|
|
|
|
|
if(dealTicket == 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
string dealSymbol = (string)HistoryDealGetString(dealTicket, DEAL_SYMBOL);
|
|
|
|
|
|
long dealMagic = (long)HistoryDealGetInteger(dealTicket, DEAL_MAGIC);
|
|
|
|
|
|
if(dealSymbol != symbol || dealMagic != InpEAMagic)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(dealTicket, DEAL_ENTRY);
|
|
|
|
|
|
if(entry != DEAL_ENTRY_OUT && entry != DEAL_ENTRY_INOUT)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(dealTicket, DEAL_REASON);
|
|
|
|
|
|
if(reason != DEAL_REASON_TP && reason != DEAL_REASON_SL)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
datetime dealTime = (datetime)HistoryDealGetInteger(dealTicket, DEAL_TIME);
|
|
|
|
|
|
if(dealTime > latest)
|
|
|
|
|
|
latest = dealTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
return latest;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--- If a new TP/SL exit is detected since the last processed time,
|
|
|
|
|
|
//--- reset all FVG statuses by re-initializing the array and rescanning.
|
|
|
|
|
|
bool CheckAndResetOnNewTP_SL_Exit()
|
|
|
|
|
|
{
|
|
|
|
|
|
datetime now = TimeCurrent();
|
|
|
|
|
|
if(now == 0)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
if(!HistorySelect(0, now))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
datetime latestExit = g_LastExitDealTime;
|
|
|
|
|
|
string symbol = GetTradeSymbol();
|
|
|
|
|
|
|
|
|
|
|
|
int deals = HistoryDealsTotal();
|
|
|
|
|
|
for(int i = 0; i < deals; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
ulong dealTicket = HistoryDealGetTicket(i);
|
|
|
|
|
|
if(dealTicket == 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
string dealSymbol = (string)HistoryDealGetString(dealTicket, DEAL_SYMBOL);
|
|
|
|
|
|
long dealMagic = (long)HistoryDealGetInteger(dealTicket, DEAL_MAGIC);
|
|
|
|
|
|
if(dealSymbol != symbol || dealMagic != InpEAMagic)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(dealTicket, DEAL_ENTRY);
|
|
|
|
|
|
if(entry != DEAL_ENTRY_OUT && entry != DEAL_ENTRY_INOUT)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(dealTicket, DEAL_REASON);
|
|
|
|
|
|
if(reason != DEAL_REASON_TP && reason != DEAL_REASON_SL)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
datetime dealTime = (datetime)HistoryDealGetInteger(dealTicket, DEAL_TIME);
|
|
|
|
|
|
if(dealTime > g_LastExitDealTime && dealTime > latestExit)
|
|
|
|
|
|
latestExit = dealTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(latestExit <= g_LastExitDealTime)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
//--- Only reset strategy state when our position is fully closed.
|
|
|
|
|
|
//--- This avoids resetting on partial TP/SL deals while position still exists.
|
|
|
|
|
|
if(CountOurPositions() > 0)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
g_LastExitDealTime = latestExit;
|
|
|
|
|
|
|
|
|
|
|
|
//--- Cancel any pending limit orders left from before the exit.
|
|
|
|
|
|
CancelAllOurLimitOrders();
|
|
|
|
|
|
|
|
|
|
|
|
//--- Reset FVG states completely and rescan from scratch.
|
|
|
|
|
|
FVGInit();
|
|
|
|
|
|
TrendUpdate();
|
|
|
|
|
|
FVGUpdate();
|
|
|
|
|
|
|
|
|
|
|
|
if(InpDebugLog)
|
|
|
|
|
|
PrintFormat("[RESET] New SL/TP exit at %s → reset FVG array",
|
|
|
|
|
|
TimeToString(g_LastExitDealTime));
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//| OnDeinit |
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-11 01:01:25 +07:00
|
|
|
|
void OnDeinit(const int reason)
|
|
|
|
|
|
{
|
2026-03-11 16:06:24 +07:00
|
|
|
|
TrendDeinit();
|
|
|
|
|
|
DrawCleanup();
|
2026-03-11 01:01:25 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//| OnTick |
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-03-11 01:01:25 +07:00
|
|
|
|
void OnTick()
|
|
|
|
|
|
{
|
2026-03-11 16:06:24 +07:00
|
|
|
|
if(!IsNewBar())
|
|
|
|
|
|
return;
|
2026-03-11 01:01:25 +07:00
|
|
|
|
|
2026-03-19 21:41:57 +07:00
|
|
|
|
//--- IMPORTANT: reset internal FVG status after TP/SL so we don't reuse
|
|
|
|
|
|
//--- old TOUCHED/MITIGATED states.
|
|
|
|
|
|
if(CheckAndResetOnNewTP_SL_Exit())
|
|
|
|
|
|
{
|
|
|
|
|
|
DrawAll();
|
|
|
|
|
|
return; // avoid entering a new trade on the same bar immediately
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 16:06:24 +07:00
|
|
|
|
TrendUpdate();
|
|
|
|
|
|
FVGUpdate();
|
2026-03-11 18:13:27 +07:00
|
|
|
|
ManageFVGTrades();
|
2026-03-11 16:06:24 +07:00
|
|
|
|
DrawAll();
|
2026-03-11 01:01:25 +07:00
|
|
|
|
}
|