459 lines
12 KiB
MQL5
459 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| CommonHelper.mqh |
| |
//| Copyright 2025, MetaQuotes Ltd. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2025, MetaQuotes Ltd."
| |
#property link "https://www.mql5.com"
| |
#property version "1.00"
| |
| |
#include <Mql5Book\Barsbydate.mqh>
| |
#include <Mql5Book\Timer.mqh>
| |
#include "Indicator.mqh"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class StructureLevels
| |
{
| |
public:
| |
TimePrice protectedHigh;
| |
TimePrice protectedLow;
| |
| |
TimePrice bullNoBos;
| |
TimePrice bearNoBos;
| |
| |
TimePrice bullConfirmedLow;
| |
TimePrice bearConfirmedHigh;
| |
| |
int direction;
| |
};
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class CommonHelper
| |
{
| |
private:
| |
ENUM_TIMEFRAMES timeframe;
| |
string symbol;
| |
| |
CBarsbydate bar;
| |
CNewBar newBar;
| |
| |
| |
public:
| |
CommonHelper();
| |
~CommonHelper();
| |
Swing swing;
| |
void UpdateBars(ENUM_TIMEFRAMES timefrme, string symbl, bool useMonths = false, int monthsBack = 100)
| |
{
| |
timeframe = timefrme;
| |
symbol = symbl;
| |
bar.UpdateFromMonthsBack(symbol, timeframe, monthsBack, useMonths);
| |
| |
swing.UpdateFromMonthsBack(monthsBack, useMonths);
| |
}
| |
int OnInit(string s, ENUM_TIMEFRAMES tf, int lr = 3, int look = 1)
| |
{
| |
symbol = s;
| |
timeframe = tf;
| |
bar.SetAsSeries(false);
| |
swing.SetAsSeries(false);
| |
| |
if(swing.Init("Fractal", s, tf, lr, look) == -1)
| |
{
| |
Print("Error creating Swing Indicator: ", GetLastError());
| |
return INIT_FAILED;
| |
}
| |
return INIT_SUCCEEDED;
| |
}
| |
| |
void SetAsSeries(bool isAsSeries)
| |
{
| |
bar.SetAsSeries(isAsSeries);
| |
}
| |
bool OnNewBar()
| |
{
| |
return newBar.CheckNewBar(symbol, timeframe);
| |
}
| |
int Bars()
| |
{
| |
return bar.Size();
| |
}
| |
int LastBar()
| |
{
| |
return bar.Size() - 1;
| |
}
| |
| |
bool HasBars(int count)
| |
{
| |
return bar.Size() >= count;
| |
}
| |
| |
bool IsValidIndex(int index = 0)
| |
{
| |
return (index >= 0 && index < bar.Size());
| |
}
| |
| |
datetime TimeAt(int index = 0)
| |
{
| |
return bar.Time(index);
| |
}
| |
| |
double OpenAt(int index = 0)
| |
{
| |
return bar.Open(index);
| |
}
| |
| |
double HighAt(int index = 0)
| |
{
| |
return bar.High(index);
| |
}
| |
| |
double LowAt(int index = 0)
| |
{
| |
return bar.Low(index);
| |
}
| |
| |
double CloseAt(int index = 0)
| |
{
| |
return bar.Close(index);
| |
}
| |
| |
double RangeAt(int index = 0)
| |
{
| |
return bar.High(index) - bar.Low(index);
| |
}
| |
| |
double BodyTop(int index = 0)
| |
{
| |
return MathMax(bar.Open(index), bar.Close(index));
| |
}
| |
| |
double BodyBottom(int index = 0)
| |
{
| |
return MathMin(bar.Open(index), bar.Close(index));
| |
}
| |
| |
double BodySize(int index = 0)
| |
{
| |
return MathAbs(bar.Close(index) - bar.Open(index));
| |
}
| |
| |
double UpperWick(int index = 0)
| |
{
| |
return bar.High(index) - BodyTop(index);
| |
}
| |
| |
double LowerWick(int index = 0)
| |
{
| |
return BodyBottom(index) - bar.Low(index);
| |
}
| |
| |
double MidPrice(double a, double b)
| |
{
| |
return (a + b) * 0.5;
| |
}
| |
| |
double CandleMid(int index = 0)
| |
{
| |
return MidPrice(bar.High(index), bar.Low(index));
| |
}
| |
int TimeIndex(datetime t)
| |
{
| |
if(t <= 0)
| |
return -1;
| |
return bar.IndexByTime(t);
| |
}
| |
| |
//========================
| |
// Price helpers
| |
//========================
| |
double PointValue()
| |
{
| |
return bar.Point();
| |
}
| |
| |
double PointsToPrice(int points)
| |
{
| |
return points * PointValue();
| |
}
| |
| |
bool NearPrice(double a, double b, int tolerancePoints)
| |
{
| |
return MathAbs(a - b) <= PointsToPrice(tolerancePoints);
| |
}
| |
| |
//========================
| |
// Break helpers
| |
//========================
| |
bool BreakAboveHigh(int refIndex = 0, int barIndex = 0)
| |
{
| |
if(!IsValidIndex(refIndex) || !IsValidIndex(barIndex))
| |
return false;
| |
return bar.Close(barIndex) > bar.High(refIndex);
| |
}
| |
| |
bool BreakBelowLow(int refIndex = 0, int barIndex = 0)
| |
{
| |
if(!IsValidIndex(refIndex) || !IsValidIndex(barIndex))
| |
return false;
| |
return bar.Close(barIndex) < bar.Low(refIndex);
| |
}
| |
| |
bool WickAboveHigh(int refIndex = 0, int barIndex = 0)
| |
{
| |
if(!IsValidIndex(refIndex) || !IsValidIndex(barIndex))
| |
return false;
| |
return bar.High(barIndex) > bar.High(refIndex);
| |
}
| |
| |
bool WickBelowLow(int refIndex = 0, int barIndex = 0)
| |
{
| |
if(!IsValidIndex(refIndex) || !IsValidIndex(barIndex))
| |
return false;
| |
return bar.Low(barIndex) < bar.Low(refIndex);
| |
}
| |
| |
//========================
| |
// Candle state
| |
//========================
| |
bool IsBullishCandle(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
return bar.Close(index) > bar.Open(index);
| |
}
| |
| |
bool IsBearishCandle(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
return bar.Close(index) < bar.Open(index);
| |
}
| |
| |
bool IsDojiCandle(int index = 0, double maxBodyToRange = 0.10)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
| |
double range = RangeAt(index);
| |
if(range <= 0.0)
| |
return false;
| |
| |
return (BodySize(index) / range) <= maxBodyToRange;
| |
}
| |
| |
bool IsSellToBuyCandle(int index = 0, double wickToBodyRatio = 1.2)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
| |
double body = BodySize(index);
| |
if(body <= 0.0)
| |
body = _Point;
| |
| |
return LowerWick(index) >= body * wickToBodyRatio;
| |
}
| |
| |
bool IsBuyToSellCandle(int index = 0, double wickToBodyRatio = 1.2)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
| |
double body = BodySize(index);
| |
if(body <= 0.0)
| |
body = _Point;
| |
| |
return UpperWick(index) >= body * wickToBodyRatio;
| |
}
| |
| |
//========================
| |
// Extremes in range
| |
//========================
| |
int FindLowestIndex(int fromIndex = 0, int toIndex = 0, bool inclusive = false)
| |
{
| |
if(fromIndex > toIndex)
| |
{
| |
int temp = fromIndex;
| |
fromIndex = toIndex;
| |
toIndex = temp;
| |
}
| |
| |
int start = (inclusive ? fromIndex : fromIndex + 1);
| |
int end = (inclusive ? toIndex : toIndex - 1);
| |
| |
if(start > end)
| |
return -1;
| |
| |
int lowestIndex = -1;
| |
| |
for(int i = start; i <= end; i++)
| |
{
| |
if(!IsValidIndex(i))
| |
continue;
| |
| |
if(lowestIndex == -1 || bar.Low(i) < bar.Low(lowestIndex))
| |
lowestIndex = i;
| |
}
| |
| |
return lowestIndex;
| |
}
| |
| |
int FindHighestIndex(int fromIndex = 0, int toIndex = 0, bool inclusive = false)
| |
{
| |
if(fromIndex > toIndex)
| |
{
| |
int temp = fromIndex;
| |
fromIndex = toIndex;
| |
toIndex = temp;
| |
}
| |
| |
int start = (inclusive ? fromIndex : fromIndex + 1);
| |
int end = (inclusive ? toIndex : toIndex - 1);
| |
| |
if(start > end)
| |
return -1;
| |
| |
int highestIndex = -1;
| |
| |
for(int i = start; i <= end; i++)
| |
{
| |
if(!IsValidIndex(i))
| |
continue;
| |
| |
if(highestIndex == -1 || bar.High(i) > bar.High(highestIndex))
| |
highestIndex = i;
| |
}
| |
| |
return highestIndex;
| |
}
| |
//========================
| |
// Swing helpers
| |
//========================
| |
bool IsValidSwingValue(double value)
| |
{
| |
return swing.IsValidValue(value);
| |
}
| |
| |
bool IsSwingHigh(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
return swing.IsValidValue(swing.FullHigh(index));
| |
}
| |
| |
bool IsSwingLow(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
return swing.IsValidValue(swing.FullLow(index));
| |
}
| |
double SwingHigh(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return 0;
| |
if(!swing.IsValidValue(swing.FullHigh(index)))
| |
return 0;
| |
return swing.High(index);
| |
}
| |
| |
double SwingLow(int index = 0)
| |
{
| |
if(!IsValidIndex(index))
| |
return false;
| |
if(!swing.IsValidValue(swing.FullLow(index)))
| |
return false;
| |
return swing.Low(index);
| |
}
| |
int PrevSwingHighIndex(int anchor = 0, int n = 1)
| |
{
| |
int found = -1;
| |
| |
for(int i = anchor; i >= 0; i--)
| |
{
| |
if(IsSwingHigh(i))
| |
{
| |
found++;
| |
if(found == n)
| |
return i;
| |
}
| |
}
| |
| |
return -1;
| |
}
| |
bool HasValidTime(datetime t)
| |
{
| |
return t > 0;
| |
}
| |
| |
bool IsOlderTime(datetime olderTime, datetime newerTime)
| |
{
| |
if(!HasValidTime(olderTime) || !HasValidTime(newerTime))
| |
return false;
| |
return olderTime < newerTime;
| |
}
| |
| |
bool IsOlderOrSameTime(datetime olderTime, datetime newerTime)
| |
{
| |
if(!HasValidTime(olderTime) || !HasValidTime(newerTime))
| |
return false;
| |
return olderTime <= newerTime;
| |
}
| |
| |
int CountClosedBarsAfterTime(datetime anchorTime, datetime currentTime)
| |
{
| |
if(!IsOlderTime(anchorTime, currentTime))
| |
return -1;
| |
| |
int anchorIndex = TimeIndex(anchorTime);
| |
int currentIndex = TimeIndex(currentTime);
| |
| |
if(!IsValidIndex(anchorIndex) || !IsValidIndex(currentIndex))
| |
return -1;
| |
if(currentIndex <= anchorIndex)
| |
return -1;
| |
| |
return (currentIndex - anchorIndex - 1);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+---------------------------j---------------------------------------+
| |
bool AnchorIsMatureForBreak(int minCandles, datetime anchorTime, datetime currentTime)
| |
{
| |
int closedBars = MathAbs(TimeIndex(anchorTime) - TimeIndex(currentTime));
| |
Print(closedBars);
| |
return closedBars >= minCandles;
| |
}
| |
| |
void SyncIndexFromTime(TimePrice &tp)
| |
{
| |
if(tp.x == 0)
| |
{
| |
tp.i = -1;
| |
return;
| |
}
| |
| |
tp.i = TimeIndex(tp.x);
| |
}
| |
| |
int TimeframeMinutes()
| |
{
| |
| |
return PeriodSeconds(timeframe) / 60;
| |
}
| |
};
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CommonHelper::CommonHelper()
| |
{
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CommonHelper::~CommonHelper()
| |
{
| |
}
| |
//+------------------------------------------------------------------+
|