//+------------------------------------------------------------------+ //| Fvg.mq5 | //| Copyright 2024, rpanchyk | //| https://github.com/rpanchyk | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, rpanchyk" #property link "https://github.com/rpanchyk" #property version "1.03" #property description "Expert Advisor shows fair value gaps" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\Utils\\MetricSaver.mqh" // https://github.com/rpanchyk/mt5-fvg-ind/blob/main/MQL5/Indicators/Fvg.mq5 (convertido a EA) // types enum ENUM_BORDER_STYLE { BORDER_STYLE_SOLID = STYLE_SOLID, // Solid BORDER_STYLE_DASH = STYLE_DASH // Dash }; // config input group "Section :: Main"; input bool InpContinueToMitigation = true; // Continue to mitigation input group "Section :: Style"; input color InpDownTrendColor = clrLightPink; // Down trend color input color InpUpTrendColor = clrLightGreen; // Up trend color input bool InpFill = true; // Fill solid (true) or transparent (false) input ENUM_BORDER_STYLE InpBoderStyle = BORDER_STYLE_SOLID; // Border line style input int InpBorderWidth = 2; // Border line width input group "Section :: Dev"; input bool InpDebugEnabled = false; // Enable debug (verbose logging) // constants const string OBJECT_PREFIX = "FVG"; const string OBJECT_PREFIX_CONTINUATED = OBJECT_PREFIX + "CNT"; const string OBJECT_SEP = "#"; // global variables datetime lastBarTime = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { CMetricsSave::Start(FILE_CODE1); if(InpDebugEnabled) { Print("Fvg expert advisor initialization started"); } lastBarTime = 0; if(InpDebugEnabled) { Print("Fvg expert advisor initialization finished"); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(InpDebugEnabled) { Print("Fvg expert advisor deinitialization started"); } if(!MQLInfoInteger(MQL_TESTER)) { ObjectsDeleteAll(0, OBJECT_PREFIX); } if(InpDebugEnabled) { Print("Fvg expert advisor deinitialization finished"); } CMetricsSave::Destroy(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0); if(lastBarTime == currentBarTime) { return; } lastBarTime = currentBarTime; MqlRates rates[]; ArraySetAsSeries(rates, true); int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, 100, rates); if(copied < 3) { return; } if(InpContinueToMitigation) { int total = ObjectsTotal(0, 0, OBJ_RECTANGLE); for(int i = 0; i < total; i++) { string objName = ObjectName(0, i, 0, OBJ_RECTANGLE); if(StringFind(objName, OBJECT_PREFIX_CONTINUATED) == 0) { string result[]; StringSplit(objName, StringGetCharacter(OBJECT_SEP, 0), result); datetime leftTime = StringToTime(result[1]); double leftPrice = StringToDouble(result[2]); datetime rightTime = rates[0].time; double rightPrice = StringToDouble(result[4]); if(rightPrice < rates[1].high && rightPrice > rates[1].low) { rightTime = rates[1].time; if(ObjectDelete(0, objName)) { DrawBox(leftTime, leftPrice, rightTime, rightPrice, false); } } else { ObjectMove(0, objName, 1, rightTime, rightPrice); if(InpDebugEnabled) { PrintFormat("Expand box %s", objName); } } } } } int limit = copied - 3; if(InpDebugEnabled) { PrintFormat("Copied: %i, Limit: %i", copied, limit); } for(int i = 1; i < limit; i++) { double rightHighPrice = rates[i].high; double rightLowPrice = rates[i].low; double midHighPrice = rates[i + 1].high; double midLowPrice = rates[i + 1].low; double leftHighPrice = rates[i + 2].high; double leftLowPrice = rates[i + 2].low; datetime rightTime = rates[i].time; datetime leftTime = rates[i + 2].time; // Up trend bool upLeft = midLowPrice <= leftHighPrice && midLowPrice > leftLowPrice; bool upRight = midHighPrice >= rightLowPrice && midHighPrice < rightHighPrice; bool upGap = leftHighPrice < rightLowPrice; if(upLeft && upRight && upGap) { if(InpContinueToMitigation) { rightTime = rates[0].time; for(int j = i - 1; j > 0; j--) // Search mitigation bar { if((rightLowPrice < rates[j].high && rightLowPrice >= rates[j].low) || (leftHighPrice > rates[j].low && leftHighPrice <= rates[j].high)) { rightTime = rates[j].time; break; } } } DrawBox(leftTime, leftHighPrice, rightTime, rightLowPrice, InpContinueToMitigation && rightTime == rates[0].time); continue; } // Down trend bool downLeft = midHighPrice >= leftLowPrice && midHighPrice < leftHighPrice; bool downRight = midLowPrice <= rightHighPrice && midLowPrice > rightLowPrice; bool downGap = leftLowPrice > rightHighPrice; if(downLeft && downRight && downGap) { if(InpContinueToMitigation) { rightTime = rates[0].time; for(int j = i - 1; j > 0; j--) // Search mitigation bar { if((rightHighPrice <= rates[j].high && rightHighPrice > rates[j].low) || (leftLowPrice >= rates[j].low && leftLowPrice < rates[j].high)) { rightTime = rates[j].time; break; } } } DrawBox(leftTime, leftLowPrice, rightTime, rightHighPrice, InpContinueToMitigation && rightTime == rates[0].time); continue; } } } //+------------------------------------------------------------------+ //| Draws FVG box | //+------------------------------------------------------------------+ void DrawBox(datetime leftDt, double leftPrice, datetime rightDt, double rightPrice, bool continuated) { string objName = (continuated ? OBJECT_PREFIX_CONTINUATED : OBJECT_PREFIX) + OBJECT_SEP + TimeToString(leftDt) + OBJECT_SEP + DoubleToString(leftPrice) + OBJECT_SEP + TimeToString(rightDt) + OBJECT_SEP + DoubleToString(rightPrice); if(ObjectFind(0, objName) < 0) { ObjectCreate(0, objName, OBJ_RECTANGLE, 0, leftDt, leftPrice, rightDt, rightPrice); ObjectSetInteger(0, objName, OBJPROP_COLOR, leftPrice < rightPrice ? InpUpTrendColor : InpDownTrendColor); ObjectSetInteger(0, objName, OBJPROP_FILL, InpFill); ObjectSetInteger(0, objName, OBJPROP_STYLE, InpBoderStyle); ObjectSetInteger(0, objName, OBJPROP_WIDTH, InpBorderWidth); ObjectSetInteger(0, objName, OBJPROP_BACK, true); ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); ObjectSetInteger(0, objName, OBJPROP_HIDDEN, false); ObjectSetInteger(0, objName, OBJPROP_ZORDER, 0); if(InpDebugEnabled) { PrintFormat("Draw box: %s", objName); } } } //+------------------------------------------------------------------+