252 lignes
8,4 Kio
MQL5
252 lignes
8,4 Kio
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|