Files
2026-03-19 21:41:57 +07:00

186 lines
6.0 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//+------------------------------------------------------------------+
//| 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 |
//+------------------------------------------------------------------+
#property copyright "SimpleFVG"
#property version "2.00"
#property description "FVG strategy visualizer EMA trend + FVG zones on chart"
#include "SimpleFVG/Config.mqh"
#include "SimpleFVG/Trend.mqh"
#include "SimpleFVG/FVG.mqh"
#include "SimpleFVG/Trade.mqh"
#include "SimpleFVG/Drawing.mqh"
//+------------------------------------------------------------------+
//| OnInit |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Step 1: Initialize trend (EMA handles + chart indicators) ---
if(!TrendInit())
return INIT_FAILED;
//--- Step 2: Initialize FVG array ---
FVGInit();
//--- Initial scan on existing bars ---
TrendUpdate();
FVGUpdate();
//--- Step 4: Draw everything ---
DrawAll();
if(InpDebugLog)
PrintFormat("[INIT] SimpleFVG v2.0 | %s %s | EMA%d/%d | FVG lookback=%d maxAge=%d",
GetTradeSymbol(), EnumToString(InpTimeframe),
InpEMAFastPeriod, InpEMASlowPeriod,
InpFVGLookbackBars, InpFVGMaxAgeBars);
//--- Initialize last processed exit time so we don't reset based on old history.
g_LastExitDealTime = GetLatestTP_SL_ExitDealTime();
return INIT_SUCCEEDED;
}
//--- 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;
}
//+------------------------------------------------------------------+
//| OnDeinit |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
TrendDeinit();
DrawCleanup();
}
//+------------------------------------------------------------------+
//| OnTick |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar())
return;
//--- 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
}
TrendUpdate();
FVGUpdate();
ManageFVGTrades();
DrawAll();
}