252 lines
8.4 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| 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);
| |||
}
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|