ictCore/Experts/core/orderflow.mqh

182 lines
6.1 KiB
MQL5
Raw Permalink Normal View History

2026-05-03 01:00:28 +03:00
//#include<Generic/Queue.mqh>
extern MqlRates rates[];
input group "Orderflow configurations"
input ENUM_TIMEFRAMES inpOrderflowtf=PERIOD_CURRENT;
class COrderflow /*:public CCore*/{
protected:
int orderflowCurrent; //latest orderflow flag -1 for BEARISH, 1 for BULLISH
double latestBullishRoot, latestBearishRoot;
enum CISDOrderblocks{BEARISHORDERBLOCK=-1, ORDERBLOCKNONE=0, BULLISHORDERBLOCK=1};
//CQueue<CISDOrderblocks> orderblocks;
//array
//latest cisd
bool isCISD;
public:
//getters
int getOrderflow(){return orderflowCurrent;};
bool whatWasOrderflow(int index, int &orderflowFlag, double &bearishRoot, double &bullishRoot); //asking for orderflow from the history
bool whenWasCISD(int &index, int &flag, int bias=0); //asking when was the last CISD
bool isCISDBySwings(int &flag);
bool isGap();
bool wasGap(double &range, double &lowerBand, double &upperBand);
bool initialize();
void update();
};
bool COrderflow::initialize(void){
if(latestBearishRoot!=0 && latestBullishRoot!=0){ //already initialized
Print("roots already loaded!");
return true;
}
int bullishRootIdx=0, bearishRootIdx=0;
for(int i=1; i<Bars(_Symbol,PERIOD_CURRENT)-1; i++){
bool currBullish = rates[i].close > rates[i].open;
bool currBearish = rates[i].close < rates[i].open;
bool prevBullish = rates[i+1].close > rates[i+1].open;
bool prevBearish = rates[i+1].close < rates[i+1].open;
// Bullish candle after bearish → start of bullish move → bullish root
if(currBullish && prevBearish && latestBullishRoot==0){
rates[i].open < rates[i+1].close ? latestBullishRoot=rates[i].open : latestBullishRoot=rates[i+1].close; //avoiding the gap trap
bullishRootIdx=i;
}
// Bearish candle after bullish → start of bearish move → bearish root
if(currBearish && prevBullish && latestBearishRoot==0){
rates[i].open > rates[i+1].close ? latestBearishRoot=rates[i].open : latestBearishRoot=rates[i+1].close; //avoiding the gap trap
bearishRootIdx=i;
}
if(latestBullishRoot!=0 && latestBearishRoot!=0){
Print("roots successfully loaded");
break;
}
}
if(latestBullishRoot==0 || latestBearishRoot==0){
Print("failed to load one of roots");
return false;
}
if(rates[1].close > latestBearishRoot){
orderflowCurrent=1;
}
else if(rates[1].close < latestBullishRoot){
orderflowCurrent=-1;
}
else{ // closing in between — the most recently formed root decides
orderflowCurrent = (bullishRootIdx < bearishRootIdx) ? 1 : -1;
}
return true;
}
bool COrderflow::whatWasOrderflow(const int index,int &orderflowFlag, double &bearishRoot, double &bullishRoot){
if(bearishRoot!=0||bullishRoot!=0)
{
Print("Reference provided is already loaded, reset it before proceeding");
Sleep(200);
bullishRoot=0;
bearishRoot=0;
}
int bullishRootIdx=0, bearishRootIdx=0;
for(int i=index; i<Bars(_Symbol,PERIOD_CURRENT)-1; i++){
bool currBullish = rates[i].close > rates[i].open;
bool currBearish = rates[i].close < rates[i].open;
bool prevBullish = rates[i+1].close > rates[i+1].open;
bool prevBearish = rates[i+1].close < rates[i+1].open;
// Bullish candle after bearish → start of bullish move → bullish root
if(currBullish && prevBearish && bullishRoot==0){
rates[i].open < rates[i+1].close ? bullishRoot=rates[i].open : bullishRoot=rates[i+1].close; //avoiding the gap trap
bullishRootIdx=i;
}
// Bearish candle after bullish → start of bearish move → bearish root
if(currBearish && prevBullish && bearishRoot==0){
rates[i].open > rates[i+1].close ? bearishRoot=rates[i].open : bearishRoot=rates[i+1].close; //avoiding the gap trap
bearishRootIdx=i;
}
if(bullishRoot!=0 && bearishRoot!=0)
break;
}
if(bullishRoot==0 || bearishRoot==0)
return false;
if(rates[index].close > bearishRoot){
orderflowFlag=1;
}
else if(rates[index].close < bullishRoot){
orderflowFlag=-1;
}
else{ // closing in between — the most recently formed root decides
orderflowFlag = (bullishRootIdx < bearishRootIdx) ? 1 : -1;
}
return true;
}
void COrderflow::update(void){
if(orderflowCurrent==0){
Print("There was NULL Orderflow, trying to initialize right now.. ");
COrderflow::initialize();
}
if(orderflowCurrent==1){ //the current orderflow is bullish
if(rates[1].close<latestBullishRoot){
//cisd
isCISD=true;
orderflowCurrent=-1;
}
if(rates[1].close<rates[1].open //
&& rates[2].close>rates[2].open){ //receiving first-time opposing candle
//
rates[1].open>rates[2].close ? latestBearishRoot=rates[1].open : latestBearishRoot=rates[2].close;
}
if(rates[1].close>rates[1].open //
&& rates[2].close<rates[2].open){ //receiving first-time opposing candle
//
rates[1].open>rates[2].close ? latestBullishRoot=rates[2].close : latestBullishRoot=rates[1].open;
}
}
if(orderflowCurrent==-1){ //the current orderflow is bearish
if(rates[1].close>latestBearishRoot){
//cisd
isCISD=true;
orderflowCurrent=1;
}
if(rates[1].close>rates[1].open //
&& rates[2].close<rates[2].open){ //receiving first-time opposing candle
//
rates[1].open>rates[2].close ? latestBullishRoot=rates[2].close : latestBullishRoot=rates[1].open;
}
if(rates[1].close<rates[1].open //
&& rates[2].close>rates[2].open){ //receiving first-time opposing candle
//
rates[1].open>rates[2].close ? latestBearishRoot=rates[1].open : latestBearishRoot=rates[2].close;
}
}
}