5618 lines
95 KiB
Plaintext
5618 lines
95 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Common Library
|
|
// --------------------------------------
|
|
// Name: XCommonLib
|
|
// Description: provide all commonly used functions ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
|
|
//
|
|
// Models ...
|
|
|
|
//
|
|
// Specified Price Type ...
|
|
enum ENUM_X_PRICE
|
|
{
|
|
X_PRICE_HIGH,
|
|
X_PRICE_OPEN,
|
|
X_PRICE_CLOSE,
|
|
X_PRICE_LOW
|
|
};
|
|
|
|
//
|
|
// Swing Types Enum ...
|
|
enum ENUM_X_SWING_TYPE
|
|
{
|
|
X_NO_SWING = 0,
|
|
X_SWING_HIGH = 1,
|
|
X_SWING_LOW = -1,
|
|
};
|
|
|
|
//
|
|
// XPERIOD Calculation Method ...
|
|
enum ENUM_X_PERIOD_METHOD
|
|
{
|
|
//
|
|
X_PERIOD_NOTHING, // Nothing
|
|
X_PERIOD_AUTO, // Auto Select
|
|
X_PERIOD_MANUALLY // Manually
|
|
};
|
|
|
|
//
|
|
// Available Market Cycles ...
|
|
enum ENUM_X_MARKET_CYCLES
|
|
{
|
|
//
|
|
X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle
|
|
X_MARKET_CYCLE_SHORT, // Short Cycle
|
|
X_MARKET_CYCLE_MEDIUM, // Medium Cycle
|
|
X_MARKET_CYCLE_LONG, // Long Cycle
|
|
X_MARKET_CYCLE_HIND, // Hind Cycle
|
|
};
|
|
|
|
//
|
|
// Structs ...
|
|
|
|
//
|
|
// Model a Bar Remains Time ...
|
|
struct XBarRemainsTime
|
|
{
|
|
//
|
|
int days;
|
|
int hours;
|
|
int minutes;
|
|
int seconds;
|
|
|
|
//
|
|
// Constructor ...
|
|
XBarRemainsTime()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Always Calculate Current 0 Bar Timing ...
|
|
bool Init(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL // Trading Period
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
int minuteSecoonds = 60;
|
|
int hourSeconds = minuteSecoonds * 60;
|
|
int daySeconds = 24 * hourSeconds;
|
|
|
|
//
|
|
int periodSeconds = PeriodSeconds(
|
|
mPeriod);
|
|
datetime startTime = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
0
|
|
//
|
|
);
|
|
|
|
//
|
|
int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent();
|
|
|
|
//
|
|
int mWorkingSecondsDiff = secondsDiff;
|
|
if (mWorkingSecondsDiff > daySeconds)
|
|
{
|
|
//
|
|
days = mWorkingSecondsDiff / daySeconds;
|
|
mWorkingSecondsDiff -= days * daySeconds;
|
|
}
|
|
if (mWorkingSecondsDiff > hourSeconds)
|
|
{
|
|
//
|
|
hours = mWorkingSecondsDiff / hourSeconds;
|
|
mWorkingSecondsDiff -= hours * hourSeconds;
|
|
}
|
|
if (mWorkingSecondsDiff > minuteSecoonds)
|
|
{
|
|
//
|
|
minutes = mWorkingSecondsDiff / minuteSecoonds;
|
|
mWorkingSecondsDiff -= minutes * minuteSecoonds;
|
|
}
|
|
seconds = mWorkingSecondsDiff;
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
days = 0;
|
|
hours = 0;
|
|
minutes = 0;
|
|
seconds = 0;
|
|
}
|
|
|
|
//
|
|
// To String Representation ...
|
|
string ToString(
|
|
string dayId = "d",
|
|
string hourId = "h",
|
|
string minuteId = "m",
|
|
string secondId = "s",
|
|
string idSeparator = ": ",
|
|
string separator = ", ",
|
|
bool ignoreZeroValues = true
|
|
//
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
// Days ...
|
|
if (!ignoreZeroValues || days > 0)
|
|
{
|
|
result += dayId + idSeparator + (string)days + separator;
|
|
}
|
|
|
|
//
|
|
// Hours ...
|
|
if (!ignoreZeroValues || hours > 0)
|
|
{
|
|
//
|
|
string strHour = ToString(hours);
|
|
if (StringLen(strHour) == 1)
|
|
{
|
|
strHour = "0" + strHour;
|
|
}
|
|
|
|
//
|
|
result += hourId + idSeparator + strHour + separator;
|
|
}
|
|
|
|
//
|
|
// Minutes ...
|
|
if (!ignoreZeroValues || minutes > 0)
|
|
{
|
|
//
|
|
string strMinute = ToString(minutes);
|
|
if (StringLen(strMinute) == 1)
|
|
{
|
|
strMinute = "0" + strMinute;
|
|
}
|
|
|
|
//
|
|
result += minuteId + idSeparator + strMinute + separator;
|
|
}
|
|
|
|
//
|
|
// Seconds ...
|
|
if (!ignoreZeroValues || seconds > 0)
|
|
{
|
|
//
|
|
string strSec = ToString(seconds);
|
|
if (StringLen(strSec) == 1)
|
|
{
|
|
strSec = "0" + strSec;
|
|
}
|
|
|
|
//
|
|
result += secondId + idSeparator + strSec;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Describe an Specific Candle ...
|
|
struct XOHCL
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
double high;
|
|
double open;
|
|
double close;
|
|
double low;
|
|
|
|
//
|
|
string symbol;
|
|
datetime time;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// Constructor ...
|
|
XOHCL()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Init a Bar ...
|
|
// Using Bar Index ...
|
|
bool Init(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period
|
|
int barIndex = 0 // Bar Index
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
symbol = mSymbol;
|
|
period = mPeriod;
|
|
|
|
//
|
|
time = iTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
open = iOpen(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
close = iClose(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
high = iHigh(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
low = iLow(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
bool result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Init a Bar ...
|
|
// Using Bar Time ...
|
|
bool Init(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period
|
|
datetime mTime = NULL // Bar Time
|
|
)
|
|
{
|
|
//
|
|
mTime = NormalizeTime(mTime);
|
|
|
|
//
|
|
int barIndex = iBarShift(
|
|
mSymbol,
|
|
mPeriod,
|
|
mTime,
|
|
false //
|
|
);
|
|
|
|
//
|
|
bool result = Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
high = 0;
|
|
open = 0;
|
|
close = 0;
|
|
low = 0;
|
|
|
|
//
|
|
time = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
}
|
|
|
|
//
|
|
// Validate Bar ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
high > 0 &&
|
|
open > 0 &&
|
|
close > 0 &&
|
|
low > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate X_PRICE Specified Type ...
|
|
double GetPrice(ENUM_X_PRICE mPType)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (mPType == NULL)
|
|
{
|
|
mPType = X_PRICE_CLOSE;
|
|
}
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
switch (mPType)
|
|
{
|
|
//
|
|
case X_PRICE_OPEN:
|
|
result = open;
|
|
break;
|
|
//
|
|
case X_PRICE_HIGH:
|
|
result = high;
|
|
break;
|
|
//
|
|
case X_PRICE_CLOSE:
|
|
result = close;
|
|
break;
|
|
//
|
|
case X_PRICE_LOW:
|
|
result = low;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Applied Price ...
|
|
double GetPrice(
|
|
ENUM_APPLIED_PRICE appliedTo // Select Application Method
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
// Calculate Applied Price ...
|
|
switch (appliedTo)
|
|
{
|
|
//
|
|
case PRICE_CLOSE:
|
|
result = close;
|
|
break;
|
|
|
|
//
|
|
case PRICE_OPEN:
|
|
result = open;
|
|
break;
|
|
|
|
//
|
|
case PRICE_HIGH:
|
|
result = high;
|
|
break;
|
|
|
|
//
|
|
case PRICE_LOW:
|
|
result = low;
|
|
break;
|
|
|
|
//
|
|
case PRICE_MEDIAN:
|
|
result = (high + low) / 2;
|
|
break;
|
|
|
|
//
|
|
case PRICE_TYPICAL:
|
|
result = (high + low + close) / 3;
|
|
break;
|
|
|
|
//
|
|
case PRICE_WEIGHTED:
|
|
result = (high + low + close + close) / 4;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar Mid Line ...
|
|
double GetMid()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (high + low) / 2;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate up Price ...
|
|
double GetUp()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathMax(open, close);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Down Price ...
|
|
double GetDown()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathMin(open, close);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar Body ...
|
|
double GetBody()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetUp() - GetDown();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar Range ...
|
|
double GetRange()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = high - low;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar Shadows ...
|
|
double GetShadows()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetRange() - GetBody();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar High Shadow ...
|
|
double GetHighShadow()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
high - GetUp()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Bar Low Shadow ...
|
|
double GetLowShadow()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
GetDown() - low;
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar is Bullish ...
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = open < close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar is Bearish ...
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = open > close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Next Bar Time ...
|
|
datetime NextAt()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int prSeconds = PeriodSeconds(period);
|
|
|
|
//
|
|
result = time + prSeconds;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Prev Bar Time ...
|
|
datetime BeforeOn()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int prSeconds = PeriodSeconds(period);
|
|
|
|
//
|
|
result = time - prSeconds;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Current Bar Index on Chart ...
|
|
int Index()
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
symbol,
|
|
period,
|
|
time
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar has Strong Body or Not ...
|
|
bool HasStrongBody()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double body = GetBody();
|
|
double shadow = GetShadows();
|
|
|
|
//
|
|
result = body > shadow * 1.5;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determines Swings based On this Bar ...
|
|
// Calculates Based on atleast 3 Bars Prev ...
|
|
ENUM_X_SWING_TYPE GetSwingType()
|
|
{
|
|
//
|
|
ENUM_X_SWING_TYPE result = X_NO_SWING;
|
|
|
|
//
|
|
// Find Current Index of Bar ...
|
|
int barIndex = Index();
|
|
if (barIndex <= -1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// First we have to Retrieve atleast 3 Bars before this bar ...
|
|
XOHCL bars[];
|
|
int barsCount = GetBars(
|
|
bars,
|
|
symbol,
|
|
period,
|
|
barIndex + 1,
|
|
3
|
|
//
|
|
);
|
|
if (barsCount < 3)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Swing Start Candle has Strong Body ...
|
|
bool isStrongBodyCandle = bars[2].HasStrongBody();
|
|
if (!isStrongBodyCandle)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Swing Low Conditions ...
|
|
bool isSwingLowOrderBlock =
|
|
bars[2].low < bars[1].low &&
|
|
bars[1].low < bars[0].low &&
|
|
bars[2].low < bars[0].low;
|
|
if (isSwingLowOrderBlock)
|
|
{
|
|
result = X_SWING_LOW;
|
|
}
|
|
|
|
//
|
|
// Check Swing High Conditions ...
|
|
bool isSwingHighOrderBlock =
|
|
bars[2].high > bars[1].high &&
|
|
bars[1].high > bars[0].high &&
|
|
bars[2].high > bars[0].high;
|
|
if (isSwingHighOrderBlock)
|
|
{
|
|
result = X_SWING_HIGH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Swings (Highs nd Lows) ...
|
|
int FindSwing(
|
|
ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ...
|
|
int mLength // Loopback ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsValid(swing))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int current = Index();
|
|
int founded = FindNextSwing(
|
|
swing,
|
|
(mLength * 2) + 1,
|
|
current - mLength
|
|
//
|
|
);
|
|
|
|
//
|
|
while (founded != current)
|
|
{
|
|
//
|
|
current = FindNextSwing(
|
|
swing,
|
|
mLength,
|
|
current + 1
|
|
//
|
|
);
|
|
|
|
//
|
|
founded = FindNextSwing(
|
|
swing,
|
|
(mLength * 2) + 1,
|
|
current - mLength
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
result = current;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Next Swing ...
|
|
int FindNextSwing(
|
|
ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ...
|
|
int from, // from Bar Index
|
|
int mLength // Loopback ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsValid(swing))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (from < 0)
|
|
{
|
|
mLength += from;
|
|
from = 0;
|
|
}
|
|
|
|
//
|
|
ENUM_SERIESMODE mode = swing == X_SWING_HIGH
|
|
? MODE_HIGH
|
|
: MODE_LOW;
|
|
|
|
//
|
|
result = swing == X_SWING_HIGH
|
|
? iHighest(
|
|
symbol,
|
|
period,
|
|
mode,
|
|
mLength,
|
|
from)
|
|
: iLowest(
|
|
symbol,
|
|
period,
|
|
mode,
|
|
mLength,
|
|
from);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Lowest Bar Index ...
|
|
int FindHighestIndex(
|
|
int mLength, // Loopback ...
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (mLength < 2)
|
|
{
|
|
mLength = 2;
|
|
}
|
|
|
|
//
|
|
result = iHighest(
|
|
symbol,
|
|
period,
|
|
mode,
|
|
mLength,
|
|
Index());
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Lowest ...
|
|
double FindHighest(
|
|
int mLength, // Loopback ...
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = FindHighestIndex(
|
|
mLength,
|
|
mode);
|
|
if (idx <= -1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_PRICE pMode = ToPrice(mode);
|
|
|
|
//
|
|
XOHCL iH;
|
|
result = iH.Init(
|
|
symbol,
|
|
period,
|
|
idx
|
|
//
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = iH.GetPrice(pMode);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Lowest Bar Index ...
|
|
int FindLowestIndex(
|
|
int mLength, // Loopback ...
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (mLength < 2)
|
|
{
|
|
mLength = 2;
|
|
}
|
|
|
|
//
|
|
result = iLowest(
|
|
symbol,
|
|
period,
|
|
mode,
|
|
mLength,
|
|
Index());
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Lowest ...
|
|
double FindLowest(
|
|
int mLength, // Loopback ...
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int idx = FindLowestIndex(
|
|
mLength,
|
|
mode);
|
|
if (idx <= -1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_PRICE pMode = ToPrice(mode);
|
|
|
|
//
|
|
XOHCL iL;
|
|
result = iL.Init(
|
|
symbol,
|
|
period,
|
|
idx
|
|
//
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = iL.GetPrice(pMode);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Convert to String Representation ...
|
|
string ToString()
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result = GetTypeName(this) +
|
|
"(O(" + ToString(open) + "),H(" + ToString(high) + "),C(" + ToString(close) + "),L(" + ToString(low) + "))";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model Support and Resistance
|
|
// for Specific Bar ...
|
|
struct XOHCLSupRes
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
/// Resistances ...
|
|
double res[];
|
|
|
|
//
|
|
// Supports ...
|
|
double sup[];
|
|
|
|
//
|
|
// Constructor ...
|
|
XOHCLSupRes()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Init ...
|
|
bool Init(
|
|
double price, // Price ...
|
|
const double &pivots[], // Provided Pivot Points ...
|
|
int count = 3, // Number of Requireds ...
|
|
double step = 0 // Distance between each item with it's Last Side ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
if (price <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int pivotsCount = ArraySize(pivots);
|
|
if (pivotsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (count <= 0 ||
|
|
count > pivotsCount - 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double lastR = 0;
|
|
double tmpR[];
|
|
|
|
//
|
|
double lastS = 0;
|
|
double tmpS[];
|
|
|
|
//
|
|
// Extract Supports ...
|
|
// which prices is under low of candle ...
|
|
//
|
|
// Extract Resistance ...
|
|
// which prices is over high of candle ...
|
|
for (int i = 0; i < pivotsCount; i++)
|
|
{
|
|
//
|
|
double iFlat = pivots[i];
|
|
|
|
//
|
|
if (iFlat > price)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastR == 0 || MathAbs(iFlat - lastR) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpR);
|
|
|
|
//
|
|
lastR = iFlat;
|
|
}
|
|
}
|
|
else if (iFlat < price)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastS == 0 || MathAbs(iFlat - lastS) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpS);
|
|
|
|
//
|
|
lastS = iFlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sorting Founded Resistance and Supports ...
|
|
|
|
//
|
|
// Since Resistance Levels must be Increasing ...
|
|
ArraySort(tmpR);
|
|
|
|
//
|
|
// Since Support Levels must be Decreasing ...
|
|
ArraySort(tmpS);
|
|
ArrayReverse(tmpS);
|
|
|
|
//
|
|
// Fill Resistance ...
|
|
int tmpRCount = ArraySize(tmpR);
|
|
if (tmpRCount > 0)
|
|
{
|
|
//
|
|
if (tmpRCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
res,
|
|
tmpR);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
res,
|
|
tmpR,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill Supports ...
|
|
int tmpSCount = ArraySize(tmpS);
|
|
if (tmpSCount > 0)
|
|
{
|
|
//
|
|
if (tmpSCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
sup,
|
|
tmpS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
sup,
|
|
tmpS,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
Clean(sup);
|
|
Clean(res);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
CountSupports() > 0 ||
|
|
CountResistances() > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountSupports()
|
|
{
|
|
return ArraySize(sup);
|
|
}
|
|
|
|
//
|
|
int CountResistances()
|
|
{
|
|
return ArraySize(res);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Tracking Times ...
|
|
struct XTimeTracker
|
|
{
|
|
//
|
|
// Props ...
|
|
int xMonth;
|
|
int xDayOfWeek;
|
|
int xForWeekDay;
|
|
int xDay;
|
|
int xHour;
|
|
|
|
//
|
|
// Constructor ...
|
|
XTimeTracker()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
xDay = -1;
|
|
xHour = -1;
|
|
xMonth = -1;
|
|
xDayOfWeek = -1;
|
|
xForWeekDay = -1;
|
|
}
|
|
|
|
//
|
|
// Detecting New Houre ...
|
|
bool IsNewHour()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.hour != xHour;
|
|
if (result)
|
|
{
|
|
xHour = timeStruct.hour;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Day ...
|
|
bool IsNewDay()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.day_of_year != xDay;
|
|
if (result)
|
|
{
|
|
xDay = timeStruct.day_of_year;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Week ...
|
|
bool IsNewWeek()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Week ...
|
|
// Since Week Starts From Monday in Forex World ...
|
|
// we Calculate Start of Week by 1-Monday ...
|
|
result =
|
|
xDayOfWeek == -1 &&
|
|
xForWeekDay == -1
|
|
? true
|
|
: timeStruct.day_of_week == 1 &&
|
|
timeStruct.day_of_year > xForWeekDay;
|
|
|
|
//
|
|
xForWeekDay = timeStruct.day_of_year;
|
|
xDayOfWeek = timeStruct.day_of_week;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting End Of Week ...
|
|
bool IsWeekEnd()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check WeekEnd ...
|
|
// Since Week Starts From Monday in Forex World ...
|
|
// we Calculate End of Week by 5-Friday ...
|
|
result =
|
|
xDayOfWeek != -1 &&
|
|
timeStruct.day_of_week == 5 &&
|
|
timeStruct.hour == 23 &&
|
|
timeStruct.min == 59 &&
|
|
timeStruct.sec == 59;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Month ...
|
|
bool IsNewMonth()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.mon != xMonth;
|
|
if (result)
|
|
{
|
|
xMonth = timeStruct.mon;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Tracking Bars on Specified Environment ...
|
|
struct XBarTracker
|
|
{
|
|
//
|
|
string symbol; // Tracking Symbol
|
|
ENUM_TIMEFRAMES period; // Tracking Time Frame
|
|
|
|
//
|
|
int lastTrackedBar; // Last Tracked Bar ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XBarTracker()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializer ...
|
|
bool Init(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL // Trading Period
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
this.symbol = mSymbol;
|
|
this.period = mPeriod;
|
|
|
|
//
|
|
this.lastTrackedBar = 0;
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve all Bars ...
|
|
int CountBars()
|
|
{
|
|
//
|
|
return Bars(
|
|
symbol,
|
|
period
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check if it's New Bar ...
|
|
bool IsNewBar()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int currentBars = CountBars();
|
|
|
|
//
|
|
result = currentBars > lastTrackedBar;
|
|
if (result)
|
|
{
|
|
lastTrackedBar = currentBars;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NormalizeSymbol(NULL);
|
|
period = NormalizePeriod(NULL);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Track Value Changes ...
|
|
template <typename T>
|
|
struct XValueTracker
|
|
{
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Model a Value Change ...
|
|
struct XValueChange
|
|
{
|
|
//
|
|
// Props ...
|
|
datetime at; // Change Time
|
|
T from; // Before Change Value
|
|
T to; // After Change Value
|
|
|
|
//
|
|
// Constructor ...
|
|
XValueChange()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
at = NULL;
|
|
from = NULL;
|
|
to = NULL;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(at);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = NotEmpty(from) &&
|
|
NotEmpty(to);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Props ...
|
|
XValueChange changes[]; // Hold Changes
|
|
|
|
//
|
|
// Constructor ...
|
|
XValueTracker()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Track a Change Happens Or Not ...
|
|
bool Track(
|
|
const T &source[] // Data Source for Track Changes
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (ArraySize(source) <= 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime time = TimeCurrent();
|
|
|
|
//
|
|
double from = source[1];
|
|
double to = source[0];
|
|
|
|
//
|
|
result = to != from;
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XValueChange lastChange;
|
|
bool hasLastChange =
|
|
GetLastItem(
|
|
lastChange,
|
|
changes
|
|
//
|
|
);
|
|
result =
|
|
!hasLastChange
|
|
? true
|
|
: lastChange.at < time &&
|
|
lastChange.to != to &&
|
|
lastChange.from != from;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
lastChange.Clean();
|
|
|
|
//
|
|
lastChange.to = to;
|
|
lastChange.at = time;
|
|
lastChange.from = from;
|
|
|
|
//
|
|
AddRef(
|
|
lastChange,
|
|
changes
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
Clean(changes);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Market Cycle ...
|
|
struct XMarketCycle
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string prefix; // Prefix Trag ...
|
|
|
|
//
|
|
string symbol; // Market Symbol ...
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period; // Period of Cycle ...
|
|
ENUM_X_PERIOD_METHOD method; // Period Selection Method ...
|
|
ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ...
|
|
|
|
//
|
|
int length; // Number Of Candles per Current Time Frame ...
|
|
ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ...
|
|
|
|
//
|
|
datetime lastStart; // Last Candle Bar Time ...
|
|
|
|
//
|
|
XBarTracker barTracker; // Bar Tracker ...
|
|
XBarRemainsTime remains; // Current Bar Remains Model ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XMarketCycle()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Init Cycle ...
|
|
bool Init(
|
|
string mSymbol, // Trading Symbol
|
|
ENUM_TIMEFRAMES mHostPeriod, // Host Period
|
|
ENUM_X_MARKET_CYCLES mCycle, // Init Cycle
|
|
string mPrefix = "" // Prefix
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mHostPeriod = NormalizePeriod(mHostPeriod);
|
|
|
|
//
|
|
result = IsValid(mCycle);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
this.cycle = mCycle;
|
|
|
|
//
|
|
// Set Automatically Prefix ...
|
|
if (StringLen(mPrefix) == 0)
|
|
{
|
|
this.prefix = ToString(cycle);
|
|
}
|
|
|
|
//
|
|
result = IsValid(
|
|
method,
|
|
period //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
this.symbol = mSymbol;
|
|
this.hostPeriod = mHostPeriod;
|
|
|
|
//
|
|
// Find Cycle Period ...
|
|
if (method == X_PERIOD_AUTO)
|
|
{
|
|
//
|
|
// Select Period ...
|
|
this.period = GetCyclePeriod(
|
|
this.cycle,
|
|
this.hostPeriod);
|
|
}
|
|
|
|
//
|
|
// Set Prefix if Provided ...
|
|
if (StringLen(mPrefix) > 0)
|
|
{
|
|
this.prefix = mPrefix;
|
|
}
|
|
|
|
//
|
|
// Calculate Required Info ...
|
|
|
|
//
|
|
// Length ...
|
|
this.length = PeriodSeconds(this.period) / PeriodSeconds(this.hostPeriod);
|
|
|
|
//
|
|
// Update Additional Data ...
|
|
result = this.Update(0);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
length = 0;
|
|
lastStart = 0;
|
|
|
|
//
|
|
cycle = NULL;
|
|
prefix = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
method = NULL;
|
|
hostPeriod = NULL;
|
|
|
|
//
|
|
remains.Clean();
|
|
barTracker.Clean();
|
|
}
|
|
|
|
//
|
|
// Check Structure Valid ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(
|
|
method,
|
|
period);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
length > 0 &&
|
|
symbol != NULL &&
|
|
period != NULL &&
|
|
method != NULL &&
|
|
hostPeriod != NULL &&
|
|
method != X_PERIOD_NOTHING
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Update Market Cycle Additional Info ...
|
|
bool Update(int hostBarIndex)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = this.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Init Remains ...
|
|
result = remains.Init(
|
|
this.symbol,
|
|
this.period);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Init Bar Tracker ...
|
|
result = barTracker.Init(
|
|
this.symbol,
|
|
this.period);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Count Bars ...
|
|
int CountBars()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = barTracker.CountBars();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check New Bar ...
|
|
bool IsNewBar()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = barTracker.IsNewBar();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Bar Index based on Host Period bar Index ...
|
|
int GetBarIndex(int barIndex)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int totalBars = CountBars();
|
|
if (barIndex >= totalBars)
|
|
{
|
|
//
|
|
result = totalBars - 1;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime hostBarTime = iTime(
|
|
this.symbol,
|
|
this.hostPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
result = iBarShift(
|
|
this.symbol,
|
|
this.period,
|
|
hostBarTime
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Cycles Specific Bar ...
|
|
XOHCL GetBar(int barIndex)
|
|
{
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
int totalBars = CountBars();
|
|
if (barIndex >= totalBars)
|
|
{
|
|
barIndex = totalBars - 1;
|
|
}
|
|
|
|
//
|
|
XOHCL result;
|
|
result.Init(
|
|
this.symbol,
|
|
this.period,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime GetBarTime(int barIndex)
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
int totalBars = CountBars();
|
|
if (barIndex >= totalBars)
|
|
{
|
|
barIndex = totalBars - 1;
|
|
}
|
|
|
|
//
|
|
result = iTime(
|
|
this.symbol,
|
|
this.period,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Create and String Representation for Unique Taging ...
|
|
string ToString()
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
GetTypeName(this) + "(" +
|
|
"PRFX(" + this.prefix + ")" +
|
|
"SMBL(" + this.symbol + ")" +
|
|
"CYC(" + ToString(this.cycle) + ")" +
|
|
"PRD(" + ToString(this.period) + ")" +
|
|
"PRDHST(" + ToString(this.hostPeriod) + ")" +
|
|
"MTH(" + EnumToString(this.method) + ")" +
|
|
")";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Here we Produce a Summary brief of
|
|
// state of Cycle ...
|
|
string GenerateSummary()
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
bool hasPrefix =
|
|
StringLen(this.prefix) > 0 &&
|
|
this.prefix != ToString(this.cycle);
|
|
result += (hasPrefix ? this.prefix + "[" : "") +
|
|
ToString(this.cycle) +
|
|
(hasPrefix ? "]" : "") + "\n";
|
|
|
|
//
|
|
result += " - PR: " + ToString(this.period) + "\n";
|
|
|
|
//
|
|
XOHCL cBar = GetBar(0);
|
|
|
|
//
|
|
result += " - State: " + (cBar.IsBullish() ? "Bullish" : cBar.IsBearish() ? "Bearish"
|
|
: "Neutural");
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Functions ...
|
|
|
|
//
|
|
// Validators ...
|
|
|
|
//
|
|
// Validate an String has length and not NULL ...
|
|
bool IsValid(string value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
value != NULL &&
|
|
StringLen(value) > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate a Date ...
|
|
bool IsValid(datetime value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = NotEmpty(value) && value != NULL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate a Period Param ...
|
|
bool IsValid(ENUM_TIMEFRAMES value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
value != NULL
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Specified Cycle ...
|
|
bool IsValid(ENUM_X_MARKET_CYCLES value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
value != NULL &&
|
|
value != X_MARKET_CYCLE_UNKNOWN
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Specific Period Mode ...
|
|
bool IsValid(
|
|
ENUM_X_PERIOD_METHOD mMethod, // Period Select Method
|
|
ENUM_TIMEFRAMES mPeriod // Selected Period
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
mMethod == X_PERIOD_NOTHING
|
|
? false
|
|
: mMethod == X_PERIOD_MANUALLY
|
|
? mPeriod != NULL
|
|
: mMethod == X_PERIOD_AUTO
|
|
? true
|
|
: false
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Swing Mode ...
|
|
bool IsValid(ENUM_X_SWING_TYPE value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
value == X_SWING_HIGH ||
|
|
value == X_SWING_LOW
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// As IS ...
|
|
|
|
//
|
|
// Determine a Position type is Long or not ...
|
|
bool IsLong(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == POSITION_TYPE_BUY;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsLong(ENUM_ORDER_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == ORDER_TYPE_BUY;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determine a Position type is Short or not ...
|
|
bool IsShort(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == POSITION_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsShort(ENUM_ORDER_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Expert Running in Testing Mode or not ...
|
|
bool IsRunningOnTestMode()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// check programm mode ...
|
|
result = MQL5InfoInteger(MQL5_TESTING);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalizers ...
|
|
|
|
//
|
|
// Check a Symbol provided or not ...
|
|
// if not use Default ...
|
|
string NormalizeSymbol(string value)
|
|
{
|
|
//
|
|
string result = value;
|
|
|
|
//
|
|
if (!IsValid(result))
|
|
{
|
|
result = _Symbol;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Datetime provided or not ...
|
|
// if not use Current ...
|
|
datetime NormalizeTime(datetime value)
|
|
{
|
|
//
|
|
datetime result = value;
|
|
|
|
//
|
|
if (!IsValid(result))
|
|
{
|
|
result = TimeCurrent();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Period provided or not ...
|
|
// if not use Default ...
|
|
ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = value;
|
|
|
|
//
|
|
if (!IsValid(value))
|
|
{
|
|
result = _Period;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Cycle ...
|
|
ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value)
|
|
{
|
|
//
|
|
ENUM_X_MARKET_CYCLES result = value;
|
|
|
|
//
|
|
if (!IsValid(result))
|
|
{
|
|
result = X_MARKET_CYCLE_SHORT;
|
|
}
|
|
|
|
//
|
|
return value;
|
|
}
|
|
|
|
//
|
|
// Normalize a give Volume ...
|
|
double NormalizeVolume(
|
|
double mVolume, // desired volume to normalize
|
|
string mSymbol = NULL, // Trading Symbol
|
|
int mLength = 2 // Length of Digits
|
|
)
|
|
{
|
|
//
|
|
double result = mVolume;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
// Normalize Digits ...
|
|
int digits = GetDigits(mSymbol);
|
|
|
|
//
|
|
mLength =
|
|
mLength == 0 || mLength > digits
|
|
? digits
|
|
: MathMin(mLength, digits);
|
|
|
|
//
|
|
// Normalize Volume ...
|
|
result = NormalizeDouble(result, mLength);
|
|
|
|
//
|
|
double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX);
|
|
double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN);
|
|
|
|
//
|
|
// Validate Result ...
|
|
if (result > maxAvailableVolume)
|
|
{
|
|
result = maxAvailableVolume;
|
|
}
|
|
else if (result < minAvailableVolume)
|
|
{
|
|
result = minAvailableVolume;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normallize Price ...
|
|
double NormalizePrice(
|
|
double mPrice, // desired Price for normalization
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double tickSize = 0;
|
|
result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize);
|
|
|
|
//
|
|
int digits = GetDigits(mSymbol);
|
|
result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prices ...
|
|
|
|
//
|
|
// Retrieve Ask Price ...
|
|
double GetAsk(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Bid Price ...
|
|
double GetBid(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double result = SymbolInfoDouble(mSymbol, SYMBOL_BID);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Spread Price ...
|
|
double GetSpread(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double ask = GetAsk(mSymbol);
|
|
double bid = GetBid(mSymbol);
|
|
|
|
//
|
|
double result = MathAbs(ask - bid);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Point Value ...
|
|
double GetPoints(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Point Digits ...
|
|
int GetDigits(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Entry Price ...
|
|
double GetEntry(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
result =
|
|
IsLong(type)
|
|
? GetAsk(mSymbol)
|
|
: GetBid(mSymbol);
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Exit Price ...
|
|
double GetExit(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
result =
|
|
IsLong(type)
|
|
? GetBid(mSymbol)
|
|
: GetAsk(mSymbol);
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get 1 Pip in Price Value ...
|
|
double GetPipPrice(
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double symbolPoint = GetPoints(mSymbol);
|
|
int symbolDigits = GetDigits(mSymbol);
|
|
|
|
//
|
|
double result = symbolPoint;
|
|
if (symbolDigits == 3 || symbolDigits == 5)
|
|
{
|
|
result *= 10;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Pips To Price ...
|
|
double PipsToPrice(
|
|
double mPips, // pips amount
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
int digits = GetDigits(mSymbol);
|
|
double pipValue = GetPipPrice(mSymbol);
|
|
double result = mPips * pipValue;
|
|
|
|
//
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Price to Pips ...
|
|
double PriceToPips(
|
|
double mPrice, // the price amount which required to calculate
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPrice = NormalizePrice(mPrice, mSymbol);
|
|
|
|
//
|
|
int digits = GetDigits(mSymbol);
|
|
double pipPrice = GetPipPrice(mSymbol);
|
|
|
|
//
|
|
double result = mPrice / pipPrice;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Convert Price to Point ...
|
|
double PriceToPoint(
|
|
double price, // the price amount which required to calculate
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
price = NormalizePrice(price, mSymbol);
|
|
|
|
//
|
|
double point = GetPoints(mSymbol);
|
|
result = price / point;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Point to Price ...
|
|
double PointToPrice(
|
|
double points, // Points Amount
|
|
string mSymbol = NULL // Trading Symbol
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
double point = GetPoints(mSymbol);
|
|
result = points * point;
|
|
|
|
//
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Series Mode to XPRICE ...
|
|
ENUM_X_PRICE ToPrice(
|
|
ENUM_SERIESMODE mode // Specified Series Mode ...
|
|
)
|
|
{
|
|
//
|
|
ENUM_X_PRICE result = X_PRICE_CLOSE;
|
|
|
|
//
|
|
switch (mode)
|
|
{
|
|
//
|
|
// High ...
|
|
case MODE_HIGH:
|
|
result = X_PRICE_HIGH;
|
|
break;
|
|
|
|
//
|
|
// Open ...
|
|
case MODE_OPEN:
|
|
result = X_PRICE_OPEN;
|
|
break;
|
|
|
|
//
|
|
// Low ...
|
|
case MODE_LOW:
|
|
result = X_PRICE_LOW;
|
|
break;
|
|
|
|
//
|
|
// Close ...
|
|
// Default ...
|
|
case MODE_CLOSE:
|
|
default:
|
|
result = X_PRICE_CLOSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Applied Price ...
|
|
template <typename T>
|
|
double GetAppliedPrice(
|
|
ENUM_APPLIED_PRICE tprice, // Type of Price Selection
|
|
T &open[], // Open Prices
|
|
T &high[], // High Preices
|
|
T &low[], // Low Prices
|
|
T &close[], // Close Prices
|
|
int i // Bar Index
|
|
)
|
|
{
|
|
switch (tprice)
|
|
{
|
|
case PRICE_CLOSE:
|
|
return (close[i]);
|
|
case PRICE_OPEN:
|
|
return (open[i]);
|
|
case PRICE_HIGH:
|
|
return (high[i]);
|
|
case PRICE_LOW:
|
|
return (low[i]);
|
|
case PRICE_MEDIAN:
|
|
return ((high[i] + low[i]) / 2.0);
|
|
case PRICE_TYPICAL:
|
|
return ((high[i] + low[i] + close[i]) / 3.0);
|
|
case PRICE_WEIGHTED:
|
|
return ((high[i] + low[i] + close[i] + close[i]) / 4.0);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Time / Date ...
|
|
|
|
//
|
|
// Representation of Time Struct ...
|
|
// struct MqlDateTime
|
|
// {
|
|
// int year; // Year
|
|
// int mon; // Month
|
|
// int day; // Day
|
|
// int hour; // Hour
|
|
// int min; // Minutes
|
|
// int sec; // Seconds
|
|
// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday)
|
|
// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero)
|
|
// };
|
|
|
|
//
|
|
// Converts Time to Seconds ...
|
|
ulong TimeToSeconds(
|
|
datetime time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong result = (ulong)time;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ulong TimeToSeconds(
|
|
MqlDateTime &time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = StructToTime(time);
|
|
|
|
//
|
|
ulong result = TimeToSeconds(dTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Seconds To Time ...
|
|
datetime SecondsToTime(
|
|
ulong seconds // Specify Seconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime result = (datetime)seconds;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
MqlDateTime SecondsToStruct(
|
|
ulong seconds // Specify Seconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = SecondsToTime(seconds);
|
|
|
|
//
|
|
MqlDateTime result = {};
|
|
TimeToStruct(
|
|
dTime,
|
|
result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Time to MilliSeconds ...
|
|
ulong TimeToMilliSeconds(
|
|
datetime time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong result = TimeToSeconds(time) * 1000;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ulong TimeToMilliSeconds(
|
|
MqlDateTime &time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = StructToTime(time);
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(dTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts MillisSeconds to Time ...
|
|
datetime MilliSecondsToTiem(
|
|
ulong milliSeconds // Specify MilliSeconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong seconds = milliSeconds / 1000;
|
|
|
|
//
|
|
datetime result = SecondsToTime(seconds);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
MqlDateTime MilliSecondsToStruct(
|
|
ulong milliSeconds // Specify MilliSeconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = MilliSecondsToTiem(milliSeconds);
|
|
|
|
//
|
|
MqlDateTime result = {};
|
|
TimeToStruct(
|
|
dTime,
|
|
result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve DateTime Structure ...
|
|
MqlDateTime GetCurrentTime()
|
|
{
|
|
//
|
|
MqlDateTime result = {};
|
|
|
|
//
|
|
TimeCurrent(result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Time as Seconds ...
|
|
ulong GetCurrentTimeAsSeconds()
|
|
{
|
|
//
|
|
datetime time = TimeCurrent();
|
|
|
|
//
|
|
ulong result = TimeToSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Time as MilliSeconds ...
|
|
ulong GetCurrentTimeAsMilliSeconds()
|
|
{
|
|
//
|
|
datetime time = TimeCurrent();
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Bar Times ...
|
|
|
|
//
|
|
// Retrieve Specified Bar Time ...
|
|
datetime GetBarTime(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Validate and Normalize Args ...
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime result = iTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Bar Time ...
|
|
ulong GetBarTimeAsSeconds(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
ulong result = TimeToSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Bar Time ...
|
|
ulong GetBarTimeAsMilliSeconds(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Bar Time Structure ...
|
|
MqlDateTime GetBarTimeStruct(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
MqlDateTime result = {};
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime barTime = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
// Convert to Structure ...
|
|
TimeToStruct(barTime, result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Other Tools ...
|
|
|
|
//
|
|
// Check first Cross Over second at index ...
|
|
bool IsCrossedOver(
|
|
const double &first[], // the buffer which check crossing over second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int index = 0 // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[index] > second[index] &&
|
|
!(first[index + 1] > second[index + 1]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first is Over second at index ...
|
|
bool IsOver(
|
|
const double &first[], // the buffer which check over second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int index = 0 // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[index] > second[index] &&
|
|
first[index + 1] > second[index + 1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first Cross Under second at index ...
|
|
bool IsCrossedUnder(
|
|
const double &first[], // the buffer which check crossing under second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int index = 0 // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[index] < second[index] &&
|
|
!(first[index + 1] < second[index + 1]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first is Under second at index ...
|
|
bool IsUnder(
|
|
const double &first[], // the buffer which check under second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int index = 0 // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[index] < second[index] &&
|
|
first[index + 1] < second[index + 1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Slope of Specified Buffer at Specified Index ...
|
|
double GetSlope(
|
|
const double &buffer[], // Buffer
|
|
int from, // In Past Index ...
|
|
int to // In Past Index ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (from > ArraySize(buffer) || to > ArraySize(buffer))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
double deltaValue = toValue - fromValue;
|
|
double deltaTime = from - to;
|
|
|
|
//
|
|
result = deltaValue / deltaTime;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Fib Level ...
|
|
double GetFibonacciLevel(
|
|
double upPrice, // Upper Bound
|
|
double downPrice, // Downer Bound
|
|
double level, // Level Multiplier Factor
|
|
int direction // From Down to Up < 0, other wise Vice Versa
|
|
//
|
|
)
|
|
{
|
|
//
|
|
double ling = upPrice - downPrice;
|
|
double pLevel = (ling / 100) * (level * 100);
|
|
|
|
//
|
|
double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Templates ...
|
|
|
|
//
|
|
// Retrieve Specific Object Types Name ...
|
|
template <typename T>
|
|
string GetTypeName(const T &t)
|
|
{
|
|
return typename(T);
|
|
}
|
|
|
|
//
|
|
// Generate Unique Tags ...
|
|
template <typename T>
|
|
string GenerateTag(T &model)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string tag = model.ToString();
|
|
if (StringLen(tag) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static XSCMD5 md5;
|
|
|
|
//
|
|
result = md5.Hash(tag);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Hash Specified Content ...
|
|
template <typename T>
|
|
string ToMD5(T content)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string strContent = ToString(content);
|
|
if (StringLen(strContent) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static XSCMD5 md5;
|
|
|
|
//
|
|
result = md5.Hash(strContent);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Value Not Empty ...
|
|
template <typename T>
|
|
bool NotEmpty(T value)
|
|
{
|
|
return value != EMPTY_VALUE;
|
|
}
|
|
|
|
//
|
|
// Add Specified Item to Array ...
|
|
template <typename T>
|
|
int Add(
|
|
T item, // item want to add
|
|
T &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
|
|
//
|
|
result = ArraySize(buffer);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
int AddRef(
|
|
T &item, // item want to add
|
|
T &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
|
|
//
|
|
result = ArraySize(buffer);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Remove Specified Item from an Array ...
|
|
template <typename T>
|
|
bool Remove(
|
|
T item,
|
|
T &buffer[])
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int itemIndex = FindIndex(
|
|
item,
|
|
buffer);
|
|
if (itemIndex < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArrayRemove(
|
|
buffer,
|
|
itemIndex,
|
|
1);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Clean Specified Array ...
|
|
template <typename T>
|
|
void Clean(T &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
|
|
//
|
|
// Copy Whole Content of Source to Dest array ...
|
|
template <typename T>
|
|
void Copy(
|
|
T &source[], // Source Buffer ...
|
|
T &dest[], // Dest Buffer ...
|
|
bool cleanDest = true // Force Clen Dest Buffer ...
|
|
)
|
|
{
|
|
//
|
|
if (cleanDest)
|
|
{
|
|
Clean(dest);
|
|
}
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (sourceCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iSource = source[i];
|
|
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy Items from a Buffer ...
|
|
template <typename T>
|
|
int Copy(
|
|
int start, // Start
|
|
int count, // Number of Items for read
|
|
T &source[], // Source Buffer
|
|
T &dest[], // Dest Buffer
|
|
bool forceClean = true // Force To Clean buffer
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (forceClean)
|
|
{
|
|
Clean(dest);
|
|
}
|
|
|
|
//
|
|
if (start < 0)
|
|
{
|
|
start = 0;
|
|
}
|
|
|
|
//
|
|
if (start >= ArraySize(source))
|
|
{
|
|
start = ArraySize(source) - 1;
|
|
}
|
|
|
|
//
|
|
int beforeSize = ArraySize(dest);
|
|
|
|
//
|
|
bool asSeriesDest = ArrayGetAsSeries(dest);
|
|
bool asSeriesSource = ArrayGetAsSeries(source);
|
|
|
|
//
|
|
ArraySetAsSeries(dest, true);
|
|
ArraySetAsSeries(source, true);
|
|
|
|
//
|
|
ArrayCopy(
|
|
dest,
|
|
source,
|
|
0,
|
|
start,
|
|
count
|
|
//
|
|
);
|
|
|
|
//
|
|
int afterSize = ArraySize(dest);
|
|
|
|
//
|
|
result = afterSize - beforeSize;
|
|
|
|
//
|
|
ArraySetAsSeries(dest, asSeriesDest);
|
|
ArraySetAsSeries(source, asSeriesSource);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrive Last Item of Specified Buffer ...
|
|
template <typename T>
|
|
bool GetLastItem(
|
|
T &item, // Holds Result
|
|
T &buffer[] // Specified Buffer
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
item = buffer[bufferSize - 1];
|
|
|
|
//
|
|
result = true;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Search Array For Specific Item ...
|
|
template <typename T>
|
|
int FindIndex(
|
|
T item, // What is Search ...
|
|
T &buffer[] // Search in ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(buffer);
|
|
if (count <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
T iT = buffer[i];
|
|
|
|
//
|
|
if (iT == item)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check an Array Contains Specified Value ...
|
|
template <typename T>
|
|
bool Contains(
|
|
T item, // What is Search ...
|
|
T &buffer[] // Search in ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindIndex(
|
|
item,
|
|
buffer);
|
|
result = idx > -1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate a Buffer's Average ...
|
|
template <typename T>
|
|
double GetAverage(
|
|
T &buffer[], // the Buffer which required to search
|
|
int start = 0, // Start Index
|
|
int count = 0 // Count for Search
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
T tmp[];
|
|
int tmpCount = Copy(
|
|
start,
|
|
count,
|
|
buffer,
|
|
tmp
|
|
//
|
|
);
|
|
if (tmpCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Summary ...
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
result += buffer[i];
|
|
}
|
|
|
|
//
|
|
// Calculate Average ...
|
|
result = result / tmpCount;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Max of Specific Loopback of a Buffer ...
|
|
template <typename T>
|
|
double GetMax(
|
|
T &buffer[], // the Buffer which required to search
|
|
int start = 0, // Start Index
|
|
int count = 0 // Count for Search
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
T tmp[];
|
|
int tmpCount = Copy(
|
|
start,
|
|
count,
|
|
buffer,
|
|
tmp
|
|
//
|
|
);
|
|
if (tmpCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through LoopBack ...
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
double iValue = tmp[i];
|
|
|
|
//
|
|
result =
|
|
//
|
|
result == 0 || result < iValue
|
|
//
|
|
? iValue
|
|
//
|
|
: result
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Min of Specific Loopback of a Buffer ...
|
|
template <typename T>
|
|
double GetMinValue(
|
|
T &buffer[], // the Buffer which required to search
|
|
int start = 0, // Start Index
|
|
int count = 0 // Count for Search
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
T tmp[];
|
|
int tmpCount = Copy(
|
|
start,
|
|
count,
|
|
buffer,
|
|
tmp
|
|
//
|
|
);
|
|
if (tmpCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through LoopBack ...
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
double iValue = tmp[i];
|
|
|
|
//
|
|
result =
|
|
//
|
|
result == 0 || result > iValue
|
|
//
|
|
? iValue
|
|
//
|
|
: result
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find a Value less than Specified ...
|
|
template <typename T>
|
|
T FindLesserThanValue(
|
|
T value, // Specified Value ...
|
|
const T &source[], // Source ...
|
|
bool isDescend = false // Find Biggest Lesser Value ...
|
|
)
|
|
{
|
|
//
|
|
T result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(source);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of source ...
|
|
T tmp[];
|
|
|
|
//
|
|
ArrayResize(
|
|
tmp,
|
|
ArraySize(source));
|
|
|
|
//
|
|
ArrayCopy(
|
|
tmp,
|
|
source);
|
|
|
|
//
|
|
// Sort Temp Buffer ...
|
|
ArraySort(tmp);
|
|
if (isDescend)
|
|
{
|
|
ArrayReverse(tmp);
|
|
}
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
T iValue = tmp[i];
|
|
|
|
//
|
|
if (iValue < value)
|
|
{
|
|
//
|
|
result = iValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find a Value less than Specified ...
|
|
template <typename T>
|
|
T FindBiggerThanValue(
|
|
T value, // Specified Value ...
|
|
const T &source[], // Source ...
|
|
bool isDescend = false // Find Smallest Bigger Value ...
|
|
)
|
|
{
|
|
//
|
|
T result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(source);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of source ...
|
|
T tmp[];
|
|
|
|
//
|
|
ArrayResize(
|
|
tmp,
|
|
ArraySize(source));
|
|
|
|
//
|
|
ArrayCopy(
|
|
tmp,
|
|
source);
|
|
|
|
//
|
|
// Sort Temp Buffer ...
|
|
ArraySort(tmp);
|
|
if (!isDescend)
|
|
{
|
|
ArrayReverse(tmp);
|
|
}
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
T iValue = tmp[i];
|
|
|
|
//
|
|
if (iValue > value)
|
|
{
|
|
//
|
|
result = iValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Same Values in Array ...
|
|
template <typename T>
|
|
void FindSameValues(
|
|
T &result[], // Holds Result ...
|
|
T &source[], // Source ...
|
|
int verifications = 3 // Number of Consequence Repeat ...
|
|
)
|
|
{
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
// TenkanSen Flats ...
|
|
int sourceCount = ArraySize(source);
|
|
if (sourceCount > verifications)
|
|
{
|
|
//
|
|
T mLast = 0;
|
|
int mVerified = 0;
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iVal = source[i];
|
|
if (mLast == 0)
|
|
{
|
|
mLast = iVal;
|
|
}
|
|
else if (mLast == iVal)
|
|
{
|
|
mVerified++;
|
|
}
|
|
else
|
|
{
|
|
mLast = iVal;
|
|
mVerified = 0;
|
|
}
|
|
|
|
//
|
|
if (iVal == mLast && mVerified >= verifications)
|
|
{
|
|
//
|
|
Add(
|
|
iVal,
|
|
result);
|
|
|
|
//
|
|
mLast = 0;
|
|
mVerified = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add an Item to a Buffer if not Exists ...
|
|
void AddIfNotExists(
|
|
double value,
|
|
double &values[],
|
|
double smoothingPoint = 3)
|
|
{
|
|
//
|
|
double smoothingValue = smoothingPoint * GetPoints(_Symbol);
|
|
|
|
//
|
|
int valuesCount = ArraySize(values);
|
|
if (valuesCount <= 0)
|
|
{
|
|
//
|
|
Add(value,
|
|
values);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
bool isExists = false;
|
|
for (int i = 0; i < valuesCount; i++)
|
|
{
|
|
//
|
|
double iVal = values[i];
|
|
|
|
//
|
|
double diff = MathAbs(iVal - value);
|
|
|
|
//
|
|
if (iVal == value || diff < smoothingValue)
|
|
{
|
|
//
|
|
isExists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!isExists)
|
|
{
|
|
//
|
|
Add(value,
|
|
values);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add a Buffers Child to another Buffer
|
|
// if it's not Contains them ...
|
|
void AddsIfNotExists(
|
|
double &source[],
|
|
double &dest[],
|
|
double smoothingPoint = 3)
|
|
{
|
|
//
|
|
double smoothingValue = smoothingPoint * GetPoints(_Symbol);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (sourceCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
double iSource = source[i];
|
|
|
|
//
|
|
AddIfNotExists(
|
|
iSource,
|
|
dest,
|
|
smoothingPoint);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bar XOHCL ...
|
|
|
|
//
|
|
// Extract Specific Range of Bars ...
|
|
// using Start Bar Index ...
|
|
int GetBars(
|
|
XOHCL &result[], // Hold Result
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame
|
|
int from = 0, // Start Bar Index
|
|
int count = 1, // Number of Bars
|
|
bool forceClean = true // Clean Result Array
|
|
)
|
|
{
|
|
//
|
|
int mResult = 0;
|
|
|
|
//
|
|
if (from < 0)
|
|
{
|
|
from = 0;
|
|
}
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
int total = Bars(
|
|
mSymbol,
|
|
mPeriod);
|
|
if (from > total - 2)
|
|
{
|
|
from = total - 2;
|
|
}
|
|
|
|
//
|
|
if (count < 0)
|
|
{
|
|
count = 1;
|
|
}
|
|
|
|
//
|
|
int start = from;
|
|
int end = start + count;
|
|
if (end > total - 1)
|
|
{
|
|
end = total - 1;
|
|
}
|
|
|
|
//
|
|
if (forceClean)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
int beforeSize = ArraySize(result);
|
|
|
|
//
|
|
for (int i = start; i < end; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isValid = iBar.Init(
|
|
mSymbol,
|
|
mPeriod,
|
|
i
|
|
//
|
|
);
|
|
|
|
//
|
|
if (isValid)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBar,
|
|
result
|
|
//
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
int afterSize = ArraySize(result);
|
|
|
|
//
|
|
mResult = afterSize - beforeSize;
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Extract Specific Range of Bars ...
|
|
// using Start Bar Time ...
|
|
int GetBars(
|
|
XOHCL &result[], // Hold Result
|
|
string mSymbol = NULL, // Trading Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame
|
|
datetime from = NULL, // Start Bar Time
|
|
int count = 1, // Number of Bars
|
|
bool forceClean = true // Clean Result Array
|
|
)
|
|
{
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
from = NormalizeTime(from);
|
|
|
|
//
|
|
int barIndex = iBarShift(
|
|
mSymbol,
|
|
mPeriod,
|
|
from,
|
|
false
|
|
//
|
|
);
|
|
|
|
//
|
|
return GetBars(
|
|
result,
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex,
|
|
count,
|
|
forceClean
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// String ...
|
|
|
|
//
|
|
// Convert From String ...
|
|
template <typename T>
|
|
T FromString(string value)
|
|
{
|
|
//
|
|
T result = NULL;
|
|
|
|
//
|
|
if (!IsValid(value))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (T)value;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts an item to String ...
|
|
template <typename T>
|
|
string ToString(T value)
|
|
{
|
|
return (string)value;
|
|
}
|
|
|
|
//
|
|
// Converts a Buffer to String Representation ...
|
|
template <typename T>
|
|
string ToString(
|
|
const T &buffer[], // Specified Buffer
|
|
string separator = ",", // Specified Separator
|
|
bool addIndex = false, // Specified Add Items Indexes or Not
|
|
string indexLabel = "i:", // Specified Index Label
|
|
string indexSeparator = ">" // Specified Index Separator
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < bufferSize; i++)
|
|
{
|
|
//
|
|
if (addIndex)
|
|
{
|
|
//
|
|
if (StringLen(indexLabel) > 0)
|
|
{
|
|
result += indexLabel + " ";
|
|
}
|
|
|
|
//
|
|
result += (string)i + " ";
|
|
|
|
//
|
|
if (StringLen(indexSeparator) > 0)
|
|
{
|
|
result += indexSeparator + " ";
|
|
}
|
|
}
|
|
|
|
//
|
|
string iItemString = (string)buffer[i];
|
|
|
|
//
|
|
result += iItemString;
|
|
|
|
//
|
|
if (i < bufferSize - 1)
|
|
{
|
|
result += separator;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts String to boolean ...
|
|
bool ToBoolean(string value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (StringLen(value) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
StringToLower(value);
|
|
result = value == "true";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Split an String Representation of an Array ...
|
|
int SplitContent(
|
|
string &result[], // Hold Result ...
|
|
string content, // Source ...
|
|
string separator = ",", // Separator ...
|
|
bool forceCleanResult = true // Clean Result ...
|
|
)
|
|
{
|
|
//
|
|
int mResult = 0;
|
|
|
|
//
|
|
if (forceCleanResult)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(result);
|
|
|
|
//
|
|
if (separator == NULL || StringLen(separator) == 0)
|
|
{
|
|
separator = ",";
|
|
}
|
|
|
|
//
|
|
if (StringLen(content) == 0)
|
|
{
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
StringSplit(
|
|
content,
|
|
StringGetCharacter(
|
|
separator,
|
|
0),
|
|
result);
|
|
|
|
//
|
|
int after = ArraySize(result);
|
|
|
|
//
|
|
mResult = after - before;
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Extract Data from String ...
|
|
string ExtractString(
|
|
const string source, // Source String used for Extracting
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
// Validate String ...
|
|
if (
|
|
StringLen(source) == 0 ||
|
|
StringLen(endString) == 0 ||
|
|
StringLen(startString) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Start String Position ...
|
|
int sPos = StringFind(
|
|
source,
|
|
startString);
|
|
if (sPos < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find End String Position after Start String ...
|
|
int searchEndFromPos = sPos + StringLen(startString);
|
|
int ePos = StringFind(
|
|
source,
|
|
endString,
|
|
searchEndFromPos);
|
|
if (ePos < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Data from Source ...
|
|
int dLength = ePos - searchEndFromPos;
|
|
result = StringSubstr(
|
|
source,
|
|
searchEndFromPos,
|
|
dLength);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract an Array of Contents ...
|
|
int ExtractStrings(
|
|
string &result[], // Hold Result
|
|
const string source, // Source String used for Extracting
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
int mResult = 0;
|
|
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
// Validate Args ...
|
|
int sourceLength = StringLen(source);
|
|
int startLength = StringLen(startString);
|
|
int endLength = StringLen(endString);
|
|
|
|
//
|
|
int minRequiredLength = startLength + endLength;
|
|
|
|
//
|
|
if (
|
|
endLength <= 0 ||
|
|
startLength <= 0 ||
|
|
sourceLength <= 0 ||
|
|
sourceLength < minRequiredLength)
|
|
{
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of Source for Manipulating ...
|
|
string workStr = source;
|
|
|
|
//
|
|
// Define a Loop ...
|
|
while (StringLen(workStr) > minRequiredLength)
|
|
{
|
|
//
|
|
// Find Item ...
|
|
string item = ExtractString(
|
|
workStr,
|
|
startString,
|
|
endString);
|
|
|
|
//
|
|
// Breakout when couldn't find anymore item ...
|
|
int itemLength = StringLen(item);
|
|
if (itemLength <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Prepare Item Source String for Replacing in Work String ...
|
|
string itemSource = startString + item + endString;
|
|
|
|
//
|
|
// Add Item to Result Array ...
|
|
Add(
|
|
item,
|
|
result);
|
|
|
|
//
|
|
// Replace Item Soure in Work String ...
|
|
StringReplace(
|
|
workStr,
|
|
itemSource,
|
|
"");
|
|
}
|
|
|
|
//
|
|
// Calculate Size of Array ...
|
|
mResult = ArraySize(result);
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
string ExtractSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
return ExtractString(
|
|
surrounded,
|
|
mToken + startString,
|
|
endString
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
int ParseIntSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
int result = NULL;
|
|
|
|
//
|
|
string strContent = ExtractSurrounded(
|
|
surrounded,
|
|
mToken,
|
|
startString,
|
|
endString
|
|
//
|
|
);
|
|
if (!IsValid(strContent))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (int)strContent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
long ParseLongSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
long result = NULL;
|
|
|
|
//
|
|
string strContent = ExtractSurrounded(
|
|
surrounded,
|
|
mToken,
|
|
startString,
|
|
endString
|
|
//
|
|
);
|
|
if (!IsValid(strContent))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (long)strContent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
string ParseStringSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
string strContent = ExtractSurrounded(
|
|
surrounded,
|
|
mToken,
|
|
startString,
|
|
endString
|
|
//
|
|
);
|
|
if (!IsValid(strContent))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (string)strContent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double ParseDoubleSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
double result = NULL;
|
|
|
|
//
|
|
string strContent = ExtractSurrounded(
|
|
surrounded,
|
|
mToken,
|
|
startString,
|
|
endString
|
|
//
|
|
);
|
|
if (!IsValid(strContent))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (double)strContent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
datetime ParseTimeSurrounded(
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")" // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
string strContent = ExtractSurrounded(
|
|
surrounded,
|
|
mToken,
|
|
startString,
|
|
endString
|
|
//
|
|
);
|
|
if (!IsValid(strContent))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (datetime)strContent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ParseIntArraySurrounded(
|
|
int &result[], // Holds Result
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
string separator = ",", // Separator ...
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")", // Where to End Extraction, usually a Sign
|
|
bool forceClean = true // Clean Result ...
|
|
)
|
|
{
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
if (forceClean)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(result);
|
|
|
|
//
|
|
string contentStr = ParseStringSurrounded(surrounded, mToken);
|
|
if (!IsValid(contentStr))
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
string tmps[];
|
|
int tmpsCount = SplitContent(
|
|
tmps,
|
|
contentStr
|
|
//
|
|
);
|
|
if (tmpsCount <= 0)
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < tmpsCount; i++)
|
|
{
|
|
//
|
|
string iTMP = tmps[i];
|
|
if (!IsValid(iTMP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
int iValue = (int)iTMP;
|
|
|
|
//
|
|
Add(
|
|
iValue,
|
|
result
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = ArraySize(result);
|
|
|
|
//
|
|
count = after - before;
|
|
|
|
//
|
|
return count;
|
|
}
|
|
int ParseLongArraySurrounded(
|
|
long &result[], // Holds Result
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
string separator = ",", // Separator ...
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")", // Where to End Extraction, usually a Sign
|
|
bool forceClean = true // Clean Result ...
|
|
)
|
|
{
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
if (forceClean)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(result);
|
|
|
|
//
|
|
string contentStr = ParseStringSurrounded(surrounded, mToken);
|
|
if (!IsValid(contentStr))
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
string tmps[];
|
|
int tmpsCount = SplitContent(
|
|
tmps,
|
|
contentStr
|
|
//
|
|
);
|
|
if (tmpsCount <= 0)
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < tmpsCount; i++)
|
|
{
|
|
//
|
|
string iTMP = tmps[i];
|
|
if (!IsValid(iTMP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
long iValue = (long)iTMP;
|
|
|
|
//
|
|
Add(
|
|
iValue,
|
|
result
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = ArraySize(result);
|
|
|
|
//
|
|
count = after - before;
|
|
|
|
//
|
|
return count;
|
|
}
|
|
int ParseDoubleArraySurrounded(
|
|
double &result[], // Holds Result
|
|
const string surrounded, // Surrounded Content
|
|
const string mToken, // Specified Token
|
|
string separator = ",", // Separator ...
|
|
const string startString = "(", // Expression Start String must be Unique
|
|
const string endString = ")", // Where to End Extraction, usually a Sign
|
|
bool forceClean = true // Clean Result ...
|
|
)
|
|
{
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
if (forceClean)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(result);
|
|
|
|
//
|
|
string contentStr = ParseStringSurrounded(surrounded, mToken);
|
|
if (!IsValid(contentStr))
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
string tmps[];
|
|
int tmpsCount = SplitContent(
|
|
tmps,
|
|
contentStr
|
|
//
|
|
);
|
|
if (tmpsCount <= 0)
|
|
{
|
|
return count;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < tmpsCount; i++)
|
|
{
|
|
//
|
|
string iTMP = tmps[i];
|
|
if (!IsValid(iTMP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
double iValue = (double)iTMP;
|
|
|
|
//
|
|
Add(
|
|
iValue,
|
|
result
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = ArraySize(result);
|
|
|
|
//
|
|
count = after - before;
|
|
|
|
//
|
|
return count;
|
|
}
|
|
|
|
//
|
|
// Surround an String by Specific Token ...
|
|
template <typename T>
|
|
string Surround(
|
|
string mToken, // an String which used to Tokenize
|
|
T &value, // a Value for Tokenize it
|
|
string startString = "(", // Token Start Content
|
|
string endString = ")" // Token End Content
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
string strValue = ToString(value);
|
|
if (!IsValid(strValue))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
(IsValid(mToken)
|
|
? mToken
|
|
: "") +
|
|
//
|
|
startString +
|
|
strValue +
|
|
endString
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Periods / Cycles ...
|
|
|
|
//
|
|
// Converts an String to TimeFrame ...
|
|
ENUM_TIMEFRAMES ToPeriod(string value)
|
|
{
|
|
//
|
|
if (StringLen(value) == 0)
|
|
{
|
|
return _Period;
|
|
}
|
|
|
|
//
|
|
StringTrimLeft(value);
|
|
StringTrimRight(value);
|
|
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
if (value == "M1")
|
|
{
|
|
result = PERIOD_M1;
|
|
}
|
|
else if (value == "M2")
|
|
{
|
|
result = PERIOD_M2;
|
|
}
|
|
else if (value == "M3")
|
|
{
|
|
result = PERIOD_M3;
|
|
}
|
|
else if (value == "M4")
|
|
{
|
|
result = PERIOD_M4;
|
|
}
|
|
else if (value == "M5")
|
|
{
|
|
result = PERIOD_M5;
|
|
}
|
|
else if (value == "M6")
|
|
{
|
|
result = PERIOD_M6;
|
|
}
|
|
else if (value == "M10")
|
|
{
|
|
result = PERIOD_M10;
|
|
}
|
|
else if (value == "M12")
|
|
{
|
|
result = PERIOD_M12;
|
|
}
|
|
else if (value == "M15")
|
|
{
|
|
result = PERIOD_M15;
|
|
}
|
|
else if (value == "M20")
|
|
{
|
|
result = PERIOD_M20;
|
|
}
|
|
else if (value == "M30")
|
|
{
|
|
result = PERIOD_M30;
|
|
}
|
|
else if (value == "H1")
|
|
{
|
|
result = PERIOD_H1;
|
|
}
|
|
else if (value == "H2")
|
|
{
|
|
result = PERIOD_H2;
|
|
}
|
|
else if (value == "H3")
|
|
{
|
|
result = PERIOD_H3;
|
|
}
|
|
else if (value == "H4")
|
|
{
|
|
result = PERIOD_H4;
|
|
}
|
|
else if (value == "H6")
|
|
{
|
|
result = PERIOD_H6;
|
|
}
|
|
else if (value == "H8")
|
|
{
|
|
result = PERIOD_H8;
|
|
}
|
|
else if (value == "H12")
|
|
{
|
|
result = PERIOD_H12;
|
|
}
|
|
else if (value == "D1")
|
|
{
|
|
result = PERIOD_D1;
|
|
}
|
|
else if (value == "W1")
|
|
{
|
|
result = PERIOD_W1;
|
|
}
|
|
else if (value == "MN1")
|
|
{
|
|
result = PERIOD_MN1;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Period to String ...
|
|
string ToString(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string mPStr = EnumToString(mPeriod);
|
|
|
|
string mPStrParts[];
|
|
int partsCount = StringSplit(
|
|
mPStr,
|
|
StringGetCharacter("_", 0),
|
|
mPStrParts);
|
|
if (partsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mPStrParts[1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve All Available Period as an Array ...s
|
|
int GetAllAvailablePeriods(
|
|
ENUM_TIMEFRAMES &result[] // Holds Result ...
|
|
)
|
|
{
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M1,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M2,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M3,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M4,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M5,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M6,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M10,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M12,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M15,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M20,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_M30,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H1,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H2,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H3,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H4,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H6,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H8,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_H12,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_D1,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_W1,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
Add(
|
|
PERIOD_MN1,
|
|
result
|
|
//
|
|
);
|
|
|
|
//
|
|
int mResult = ArraySize(result);
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Get Specific Time Frame Start Candle Time ...
|
|
datetime GetPeriodStartTime(
|
|
string mSymbol = NULL, // Specified Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ...
|
|
datetime mTime = NULL // Specified Bar Time of Host Period ...
|
|
)
|
|
{
|
|
//
|
|
// Normalize Arg ...
|
|
mTime = NormalizeTime(mTime);
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
int barIndex = iBarShift(
|
|
mSymbol,
|
|
mPeriod,
|
|
mTime,
|
|
false
|
|
//
|
|
);
|
|
|
|
//
|
|
datetime result = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts an String to it's related Market Cycle ...
|
|
ENUM_X_MARKET_CYCLES ToCycle(string value)
|
|
{
|
|
//
|
|
ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN;
|
|
|
|
//
|
|
ENUM_X_MARKET_CYCLES cycles[];
|
|
int count = GetAllMarketCycles(cycles);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
ENUM_X_MARKET_CYCLES iCycle = cycles[i];
|
|
string iStr = ToString(iCycle);
|
|
|
|
//
|
|
if (value == iStr)
|
|
{
|
|
//
|
|
result = iCycle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts a Cycle to it's String Representation ...
|
|
string ToString(ENUM_X_MARKET_CYCLES cycle)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string mPStr = EnumToString(cycle);
|
|
|
|
string mPStrParts[];
|
|
int partsCount = StringSplit(
|
|
mPStr,
|
|
StringGetCharacter("_", 0),
|
|
mPStrParts);
|
|
if (partsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mPStrParts[3];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve all Available Cycles ...
|
|
int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[])
|
|
{
|
|
//
|
|
int mResult = 0;
|
|
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
ENUM_X_MARKET_CYCLES tmp[] = {
|
|
X_MARKET_CYCLE_UNKNOWN,
|
|
X_MARKET_CYCLE_SHORT,
|
|
X_MARKET_CYCLE_MEDIUM,
|
|
X_MARKET_CYCLE_LONG,
|
|
X_MARKET_CYCLE_HIND};
|
|
|
|
//
|
|
Copy(
|
|
tmp,
|
|
result);
|
|
|
|
//
|
|
Clean(tmp);
|
|
|
|
//
|
|
mResult = ArraySize(result);
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Retrieve Nearest Period base on Given Period ...
|
|
ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
result = PERIOD_M4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_M6;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_M15;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_M30;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_H12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Mediest Period base on Given Period ...
|
|
ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
result = PERIOD_M15;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_M30;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H2;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H8;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Longest Period base on Given Period ...
|
|
ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
result = PERIOD_M30;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_H2;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Hindmost Period base on Given Period ...
|
|
ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_H2;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H8;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Cycles Period related to Host Period ...
|
|
ENUM_TIMEFRAMES GetCyclePeriod(
|
|
ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle
|
|
ENUM_TIMEFRAMES mPeriod = NULL // Host Period
|
|
)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
mPeriod = NormalizePeriod(mPeriod);
|
|
mCycle = NormalizeCycle(mCycle);
|
|
|
|
//
|
|
switch (mCycle)
|
|
{
|
|
//
|
|
// Short ...
|
|
case X_MARKET_CYCLE_SHORT:
|
|
result = GetNearestPeriod(mPeriod);
|
|
break;
|
|
|
|
//
|
|
// Medium ...
|
|
case X_MARKET_CYCLE_MEDIUM:
|
|
result = GetMediestPeriod(mPeriod);
|
|
break;
|
|
|
|
//
|
|
// Long ...
|
|
case X_MARKET_CYCLE_LONG:
|
|
result = GetLongestPeriod(mPeriod);
|
|
break;
|
|
|
|
//
|
|
// Hind ...
|
|
case X_MARKET_CYCLE_HIND:
|
|
result = GetHindMostPeriod(mPeriod);
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
} |