1214 lines
21 KiB
Plaintext
1214 lines
21 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Common Library
|
|
// --------------------------------------
|
|
// Name: X121SMCLib
|
|
// 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 ...
|
|
#include "../../Classes/x-saherelm.base.class.mq5"
|
|
#include "../../Helpers/x-saherelm.x3ma.helper.mq5"
|
|
#include "../../Helpers/x-saherelm.x3vwap.helper.mq5"
|
|
#include "../../Helpers/x-saherelm.xpv.helper.mq5"
|
|
#include "../../Libraries/x-saherelm.common.lib.mq5"
|
|
#include "../../Libraries/x-saherelm.x-poi.lib.mq5"
|
|
#include "../../Libraries/x-saherelm.x-trade.lib.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
const string X121SMCStrategyToken = "X121SMC";
|
|
|
|
enum ENUM_XPV_PIVOTS
|
|
{
|
|
XPV_NONE,
|
|
XPV_PEAK,
|
|
XPV_VALE,
|
|
};
|
|
|
|
struct XPVPivot
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double upper;
|
|
double lower;
|
|
|
|
//
|
|
datetime from;
|
|
datetime to;
|
|
|
|
//
|
|
int repetition;
|
|
|
|
//
|
|
ENUM_XPV_PIVOTS type;
|
|
|
|
//
|
|
XPVPivot()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
|
|
//
|
|
to = NULL;
|
|
from = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
repetition = 0;
|
|
|
|
//
|
|
type = XPV_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(to) &&
|
|
IsValid(from) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
repetition > 0 &&
|
|
type != XPV_NONE &&
|
|
(upper > 0 || lower > 0)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Pivot is Peak ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPeak()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_PEAK;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Pivot is Vale ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsVale()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_VALE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Lower for Peaks ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateLower()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsPeak())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
from //
|
|
);
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
to //
|
|
);
|
|
|
|
//
|
|
int count =
|
|
fromIndex - toIndex;
|
|
|
|
//
|
|
int llIDX = iLowest(
|
|
symbol,
|
|
period,
|
|
MODE_LOW,
|
|
count,
|
|
toIndex //
|
|
);
|
|
|
|
//
|
|
result =
|
|
iLow(
|
|
symbol,
|
|
period,
|
|
llIDX //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Upper for Vales ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateUpper()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsVale())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
from //
|
|
);
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
to //
|
|
);
|
|
|
|
//
|
|
int count =
|
|
fromIndex - toIndex;
|
|
|
|
//
|
|
int hhIDX = iHighest(
|
|
symbol,
|
|
period,
|
|
MODE_HIGH,
|
|
count,
|
|
toIndex //
|
|
);
|
|
|
|
//
|
|
result =
|
|
iHigh(
|
|
symbol,
|
|
period,
|
|
hhIDX //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Range of Pivot ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateRange()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
upper <= 0 ||
|
|
lower <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = upper - lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Middle of Pivot ...
|
|
* Used for
|
|
* @return ( double )
|
|
*/
|
|
double CalculateMid()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double range = CalculateRange();
|
|
if (range <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = lower + (range / 2);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
|
|
/**
|
|
* Get Unique Identifier ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetTag()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = symbol + "_" +
|
|
ToString(period) + "_" +
|
|
ToString(upper) + "," +
|
|
ToString(lower) + "_" +
|
|
ToString(from) + "," +
|
|
ToString(to);
|
|
hash = ToMD5(hash);
|
|
|
|
//
|
|
string typeStr =
|
|
type == XPV_PEAK
|
|
? "Peak"
|
|
: "Vale";
|
|
|
|
//
|
|
result =
|
|
//
|
|
"XPV_" +
|
|
typeStr + "_" +
|
|
symbol + "_" +
|
|
ToString(period) +
|
|
"_" + hash
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Model Signalling Conditions ...
|
|
struct X121SMCStrategyConditions
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
datetime time;
|
|
|
|
//
|
|
XPVPivot orderFlow[];
|
|
|
|
//
|
|
XPVConditions xpvConditions;
|
|
X3MAConditions x3maConditions;
|
|
X3VWAPConditions x3vwapConditions;
|
|
|
|
//
|
|
// D1 ...
|
|
|
|
//
|
|
XPOIState d1State;
|
|
ENUM_X_DIRECTION d1MarketDirection;
|
|
XCSupportZone *d1SupportZones[];
|
|
XCResistanceZone *d1ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *d1SwingHigh;
|
|
XCSwing *d1SwingLow;
|
|
|
|
//
|
|
// H4 ...
|
|
|
|
//
|
|
XPOIState h4State;
|
|
ENUM_X_DIRECTION h4MarketDirection;
|
|
XCSupportZone *h4SupportZones[];
|
|
XCResistanceZone *h4ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *h4SwingHigh;
|
|
XCSwing *h4SwingLow;
|
|
|
|
//
|
|
// H2 ...
|
|
|
|
//
|
|
XPOIState h2State;
|
|
ENUM_X_DIRECTION h2MarketDirection;
|
|
XCSupportZone *h2SupportZones[];
|
|
XCResistanceZone *h2ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *h2SwingHigh;
|
|
XCSwing *h2SwingLow;
|
|
|
|
//
|
|
// H1 ...
|
|
|
|
//
|
|
XPOIState h1State;
|
|
ENUM_X_DIRECTION h1MarketDirection;
|
|
XCSupportZone *h1SupportZones[];
|
|
XCResistanceZone *h1ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *h1SwingHigh;
|
|
XCSwing *h1SwingLow;
|
|
|
|
//
|
|
// M15 ...
|
|
|
|
//
|
|
XPOIState m15State;
|
|
ENUM_X_DIRECTION m15MarketDirection;
|
|
XCSupportZone *m15SupportZones[];
|
|
XCResistanceZone *m15ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *m15SwingHigh;
|
|
XCSwing *m15SwingLow;
|
|
|
|
//
|
|
// M5 ...
|
|
|
|
//
|
|
XPOIState m5State;
|
|
ENUM_X_DIRECTION m5MarketDirection;
|
|
XCSupportZone *m5SupportZones[];
|
|
XCResistanceZone *m5ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *m5SwingHigh;
|
|
XCSwing *m5SwingLow;
|
|
|
|
//
|
|
// M1 ...
|
|
|
|
//
|
|
XPOIState m1State;
|
|
ENUM_X_DIRECTION m1MarketDirection;
|
|
XCSupportZone *m1SupportZones[];
|
|
XCResistanceZone *m1ResistanceZones[];
|
|
|
|
//
|
|
XCSwing *m1SwingHigh;
|
|
XCSwing *m1SwingLow;
|
|
|
|
//
|
|
void X121SMCStrategyConditions()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
time = NULL;
|
|
|
|
//
|
|
xpvConditions.Clean();
|
|
x3maConditions.Clean();
|
|
x3vwapConditions.Clean();
|
|
|
|
//
|
|
Clean(orderFlow);
|
|
|
|
//
|
|
// D1 ...
|
|
|
|
//
|
|
d1State.Clean();
|
|
d1MarketDirection = X_DIRECTION_NONE;
|
|
Clean(d1SupportZones);
|
|
Clean(d1ResistanceZones);
|
|
|
|
//
|
|
d1SwingHigh = NULL;
|
|
d1SwingLow = NULL;
|
|
|
|
//
|
|
// H4 ...
|
|
|
|
//
|
|
h4State.Clean();
|
|
h4MarketDirection = X_DIRECTION_NONE;
|
|
Clean(h4SupportZones);
|
|
Clean(h4ResistanceZones);
|
|
|
|
//
|
|
h4SwingHigh = NULL;
|
|
h4SwingLow = NULL;
|
|
|
|
//
|
|
// H2 ...
|
|
|
|
//
|
|
h2State.Clean();
|
|
h2MarketDirection = X_DIRECTION_NONE;
|
|
Clean(h2SupportZones);
|
|
Clean(h2ResistanceZones);
|
|
|
|
//
|
|
h2SwingHigh = NULL;
|
|
h2SwingLow = NULL;
|
|
|
|
//
|
|
// H1 ...
|
|
|
|
//
|
|
h1State.Clean();
|
|
h1MarketDirection = X_DIRECTION_NONE;
|
|
Clean(h1SupportZones);
|
|
Clean(h1ResistanceZones);
|
|
|
|
//
|
|
h1SwingHigh = NULL;
|
|
h1SwingLow = NULL;
|
|
|
|
//
|
|
// M15 ...
|
|
|
|
//
|
|
m15State.Clean();
|
|
m15MarketDirection = X_DIRECTION_NONE;
|
|
Clean(m15SupportZones);
|
|
Clean(m15ResistanceZones);
|
|
|
|
//
|
|
m15SwingHigh = NULL;
|
|
m15SwingLow = NULL;
|
|
|
|
//
|
|
// M5 ...
|
|
|
|
//
|
|
m5State.Clean();
|
|
m5MarketDirection = X_DIRECTION_NONE;
|
|
Clean(m5SupportZones);
|
|
Clean(m5ResistanceZones);
|
|
|
|
//
|
|
m5SwingHigh = NULL;
|
|
m5SwingLow = NULL;
|
|
|
|
//
|
|
// M1 ...
|
|
|
|
//
|
|
m1State.Clean();
|
|
m1MarketDirection = X_DIRECTION_NONE;
|
|
Clean(m1SupportZones);
|
|
Clean(m1ResistanceZones);
|
|
|
|
//
|
|
m1SwingHigh = NULL;
|
|
m1SwingLow = NULL;
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsSpecifiedValid(symbol) &&
|
|
IsSpecifiedValid(period) &&
|
|
IsSpecifiedValid(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Custom Tools ...
|
|
|
|
/**
|
|
* Check Conditions for Detect Market Structure ...
|
|
*
|
|
* @param structure: ENUM_X_DIRECTION member, Market Structure Direction reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasMarketStructure(
|
|
ENUM_X_DIRECTION &structure //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
structure = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool is1DBullish = IsBullish(d1MarketDirection);
|
|
bool is1DBearish = IsBearish(d1MarketDirection);
|
|
|
|
//
|
|
bool is4HBullish = IsBullish(h4MarketDirection);
|
|
bool is4HBearish = IsBearish(h4MarketDirection);
|
|
|
|
//
|
|
bool is2HBullish = IsBullish(h2MarketDirection);
|
|
bool is2HBearish = IsBearish(h2MarketDirection);
|
|
|
|
//
|
|
bool is1HBullish = IsBullish(h1MarketDirection);
|
|
bool is1HBearish = IsBearish(h1MarketDirection);
|
|
|
|
//
|
|
bool is15MBullish = IsBullish(m15MarketDirection);
|
|
bool is15MBearish = IsBearish(m15MarketDirection);
|
|
|
|
//
|
|
bool is5MBullish = IsBullish(m5MarketDirection);
|
|
bool is5MBearish = IsBearish(m5MarketDirection);
|
|
|
|
//
|
|
bool is1MBullish = IsBullish(m1MarketDirection);
|
|
bool is1MBearish = IsBearish(m1MarketDirection);
|
|
|
|
//
|
|
bool isStructuresBullish =
|
|
//
|
|
is1HBullish &&
|
|
is15MBullish &&
|
|
is5MBullish
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isStructuresBearish =
|
|
//
|
|
is1HBearish &&
|
|
is15MBearish &&
|
|
is5MBearish
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasMarketStructure =
|
|
isStructuresBullish ||
|
|
isStructuresBearish;
|
|
result = hasMarketStructure;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
structure =
|
|
isStructuresBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reporter Functions ...
|
|
|
|
/**
|
|
* Generate Provided Scores ...
|
|
*
|
|
* @param bullishScore: Integer, reference ...
|
|
* @param bearishScore: Integer, referenceF ...
|
|
*/
|
|
void GenerateScore(
|
|
double &bullishScore,
|
|
double &bearishScore //
|
|
)
|
|
{
|
|
//
|
|
bullishScore = 0;
|
|
bearishScore = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double bullScore = 0;
|
|
double bearScore = 0;
|
|
|
|
// //
|
|
// // XPV ...
|
|
// pvConditions.GenerateScore(
|
|
// bullScore,
|
|
// bearScore //
|
|
// );
|
|
// bullishScore += bullScore;
|
|
// bearishScore += bearScore;
|
|
}
|
|
|
|
/**
|
|
* Generate Summary ...
|
|
*
|
|
* @param onlyCommons: Boolean ...
|
|
* @param onlyConditions: Boolean ...
|
|
* @param includeScores: Boolean ...
|
|
* @param ignoreFalseConditions: Boolean ...
|
|
* @param separator: String ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GenerateSummary(
|
|
bool onlyCommons = false,
|
|
bool onlyConditions = false,
|
|
bool includeScores = true,
|
|
bool ignoreFalseConditions = true,
|
|
string separator = "\n" //
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
double bullishScore = 0;
|
|
double bearishScore = 0;
|
|
GenerateScore(
|
|
bullishScore,
|
|
bearishScore //
|
|
);
|
|
|
|
//
|
|
string commonStr = GenerateSpecifiedCommonSummary(
|
|
this,
|
|
separator,
|
|
includeScores,
|
|
true //
|
|
);
|
|
|
|
// //
|
|
// // XPV ...
|
|
// string pvStr = pvConditions.GenerateSummary(
|
|
// false,
|
|
// true,
|
|
// false,
|
|
// ignoreFalseConditions //
|
|
// );
|
|
|
|
//
|
|
string conditionsStr =
|
|
//
|
|
// pvStr + separator +
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
result =
|
|
//
|
|
"[" + GetTag() + "]" + separator +
|
|
"----------" + separator +
|
|
(onlyConditions
|
|
? ""
|
|
: commonStr) +
|
|
" " + separator +
|
|
(onlyCommons
|
|
? ""
|
|
: conditionsStr) +
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Unique Identifier ...
|
|
*
|
|
* @param forObject: Boolean ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetTag(
|
|
bool forObject = false //
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!forObject)
|
|
{
|
|
result = X121SMCStrategyToken;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = X121SMCStrategyToken + "_" +
|
|
symbol + "_" + ToString(period) + "_" +
|
|
ToMD5(time);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
typedef void (*TOnX121SMCSignal)(
|
|
XSignal &signal,
|
|
X121SMCStrategyConditions &conditions //
|
|
);
|
|
|
|
//
|
|
// Extentions ...
|
|
|
|
/**
|
|
* Find Oldest Pivot Index ...
|
|
*
|
|
* @param pivots: XPVPivot instance ...
|
|
* @return ( int )
|
|
*/
|
|
int FindOldestPivotIndex(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(pivots);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = pivots[i];
|
|
|
|
//
|
|
bool isOldest = true;
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
//
|
|
XPVPivot jPivot = pivots[j];
|
|
|
|
//
|
|
isOldest = iPivot.from <= jPivot.from;
|
|
if (!isOldest)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (isOldest)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Sort Pivots Based On From Date ...
|
|
*
|
|
* @param pivots: XPVPivot instance Collection reference ...
|
|
*/
|
|
void SortPivots(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
pivots,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
while (ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
if (ArraySize(tmp) == 1)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[0],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
int idx = FindOldestPivotIndex(tmp);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[idx],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
bool IsPivotBreaked(
|
|
XPVPivot &pivot,
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = pivot.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(pivots);
|
|
result = IsValidSize(pivots);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// For Peaks Highs Must not Broked ...
|
|
// For Vales Lows Must not Broked ...
|
|
bool isPeak = pivot.IsPeak();
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = pivots[i];
|
|
|
|
//
|
|
result = isPeak
|
|
? iPivot.upper > pivot.upper
|
|
: iPivot.lower < pivot.lower;
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Filter Broken Pivots for Detect Order Flow ...
|
|
*
|
|
* @param pivots: XPVPivot instance Collection reference ...
|
|
*/
|
|
void FilterBrokenPivots(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
pivots,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
while (ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
if (ArraySize(tmp) == 1)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[0],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
XPVPivot pivot = tmp[0];
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
bool isBreaked = IsPivotBreaked(
|
|
pivot,
|
|
tmp //
|
|
);
|
|
if (!isBreaked)
|
|
{
|
|
//
|
|
AddRef(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
/**
|
|
* Calculate Order Flow Direction ...
|
|
*
|
|
* @param orderFlow: XPVPivot instance Collection reference ...
|
|
* @param dir: ENUM_X_DIRECTION member reference, Hold's Calculated Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectPivotDirection(
|
|
XPVPivot &orderFlow[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
int count = ArraySize(orderFlow);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// For Bullish Direction all Exists lowers must be Greater or Equal Prev ...
|
|
bool isBullish = false;
|
|
bool canLookupForBullish = true;
|
|
|
|
//
|
|
// For Bearish Direction all Exists uppers must be Lesser or Equal Prev ...
|
|
bool isBearish = false;
|
|
bool canLookupForBearish = true;
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = orderFlow[i];
|
|
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
orderFlow,
|
|
tmp //
|
|
);
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
i + 1 //
|
|
);
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
if (IsValidSize(tmpCount))
|
|
{
|
|
//
|
|
for (int j = 0; j < tmpCount; j++)
|
|
{
|
|
//
|
|
XPVPivot jPivot = tmp[j];
|
|
|
|
//
|
|
// Check Bullish Direction ...
|
|
isBullish =
|
|
canLookupForBullish &&
|
|
jPivot.lower >= iPivot.lower;
|
|
if (!isBullish)
|
|
{
|
|
canLookupForBullish = false;
|
|
}
|
|
|
|
//
|
|
// Check Bearish Direction ...
|
|
isBearish =
|
|
canLookupForBearish &&
|
|
jPivot.upper <= iPivot.upper;
|
|
if (!isBearish)
|
|
{
|
|
canLookupForBearish = false;
|
|
}
|
|
|
|
//
|
|
if (!canLookupForBullish &&
|
|
!canLookupForBearish)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
if (isBullish &&
|
|
!isBearish)
|
|
{
|
|
dir = X_DIRECTION_BULLISH;
|
|
}
|
|
else if (isBearish &&
|
|
!isBullish)
|
|
{
|
|
dir = X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
result = dir != X_DIRECTION_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
// |