ictCore/Experts/core/candlesticks.mqh
2026-05-03 01:00:28 +03:00

194 lignes
Pas d'EOL
5,8 Kio
MQL5

//what we simply do right here is
// read candlestick momentum by
// #1 comparing upper vs lower wick
// #2 closure beyond prev candle
//--REQUIREMENTS
extern MqlRates rates[];
#include <Generic/Queue.mqh>
//Cqueue<int>candlesticksCollection;
class CCandlestick{
protected:
enum closure {CLOSEDBELOW=-1, CLOSEDNONE=0, CLOSEDABOVE=1};
CQueue<closure> candleClosureCollection;
enum relativeMomentum {MOMENTUMDOWN=-1,MOMENTUMEQUAL=0, MOMENTUMUP=1};
CQueue<relativeMomentum> candleRelMomentumCollection;//array of rel momentum (up vs down)
int m_latestCandleBias;
void coreLogic();
public:
//methods of accessing the protected
int getLatestCandleBias(){return m_latestCandleBias;};
bool getCandleCollection(int &dstArray[], bool modeClosure=false);
//array of closure DSA
//array of relative momentum DSA
//updating the data
bool wasWhat(int candleIndex, int &bias); //returning the bias of the specific candle
bool wasWhat(int startIndex, int count,/*&dsa, */bool asSeries=true); //try to fill the array with history data
void update(void); //run this inside OnTick()
double getUpperSize(int candleIndex=1);
double getLowerSize(int candleIndex=1);
bool isBull(int candleIndex=1);
bool isBear(int candleIndex=1);
bool isOpposingCandle(int &flag, const int index=1); //checks whether
bool isEngulfing(int &flag, const int index);
bool isInsideBar(int &flag, const int index);
};
void CCandlestick::coreLogic(void){
}
bool CCandlestick::isBull(int candleIndex=1){
return rates[candleIndex].close>rates[candleIndex].open;
}
bool CCandlestick::isBear(int candleIndex=1){
return rates[candleIndex].close<rates[candleIndex].open;
}
double CCandlestick::getUpperSize(int candleIndex=1){
double upperSize = MathAbs(rates[candleIndex].high-MathMax(rates[candleIndex].close,rates[candleIndex].open));
return upperSize;
}
double CCandlestick::getLowerSize(int candleIndex=1){
double lowerSize = MathAbs(rates[1].high-MathMax(rates[1].close,rates[1].open));
return lowerSize;
}
bool CCandlestick::wasWhat(int candleIndex,int &bias){
//validating the index
if(candleIndex>ArraySize(rates)){
Print("ATTENTION: candleIndex requested is far from reach, wait while fetching some data");
}
else //if the Index is reachable
double lowerSize = MathAbs(rates[candleIndex].low-MathMin(rates[candleIndex].close,rates[candleIndex].open));
double upperSize = MathAbs(rates[candleIndex].high-MathMax(rates[candleIndex].close,rates[candleIndex].open));
return false;
}
void CCandlestick::update(void){
//fill the array
//run the core logic here
double lowerSize = MathAbs(rates[1].low-MathMin(rates[1].close,rates[1].open));
double upperSize = MathAbs(rates[1].high-MathMax(rates[1].close,rates[1].open));
//Momentum check
if(lowerSize>upperSize){
if(!candleRelMomentumCollection.Enqueue(MOMENTUMUP)){
Print("Failed to register a candles parameter, retrying..");
candleRelMomentumCollection.Enqueue(MOMENTUMUP);
}
}
else if(lowerSize<upperSize){
if(!candleRelMomentumCollection.Enqueue(MOMENTUMDOWN)){
Print("Failed to register a candles parameter, retrying..");
candleRelMomentumCollection.Enqueue(MOMENTUMDOWN);
}
}
else candleRelMomentumCollection.Enqueue(MOMENTUMEQUAL);
//run the core closure logic
bool closedBeyond = rates[1].close>rates[2].high || rates[1].close<rates[2].low;
bool isCRT = !closedBeyond && (rates[1].high>rates[2].high || rates[1].low<rates[2].low);
//bias by candle closure
if(closedBeyond && CCandlestick::isBull()){
candleClosureCollection.Enqueue(CLOSEDABOVE);
//log success/failure
}
else if(closedBeyond && CCandlestick::isBear()){
candleClosureCollection.Enqueue(CLOSEDBELOW);
// Log
}
else candleClosureCollection.Enqueue(CLOSEDNONE);
}
//bool CCandlestick::getCandleCollection(int &dstArray[], bool modeClosure=false){
// if(!modeClosure){ //default to rel momentum
// if(candleRelMomentumCollection.CopyTo(dstArray)>0){return true;}
// else {//failed to copy
// //log failure to copy
// return false;
// }
// }
//
// else{ //chose to copy closure
// if(candleClosureCollection.CopyTo(dstArray)>0){return true;}
// else {//failed to copy
// //log failure to copy
// return false;
// }
// }
//}
bool CCandlestick::isOpposingCandle(int &flag, const int index=1){
if(rates[index].close>rates[index].open //bull
&& rates[index+1].close<rates[index+1].open){ //pred by bear
flag=1;
return true;
}
if(rates[index].close<rates[index].open //bear
&& rates[index+1].close>rates[index+1].open){ //pred by bull
flag=-1;
return true;
}
return false;
}
bool CCandlestick::isEngulfing(int &flag,const int index=1){
if(rates[index].high>rates[index+1].high
&& rates[index].low<rates[index+1].low){ //taking both prev candle extremes
if(CCandlestick::isBull(index)){ // assigning flag to bullish engulfing
flag=1;
return true;
}
else if(CCandlestick::isBear(index)){ //bearish engulfing
flag=-1;
return true;
}
}
//else
return false;
}
//
bool CCandlestick::isInsideBar(int &flag,const int index){
if(rates[index].high<rates[index+1].high
&& rates[index].low>rates[index+1].low){ //not breaking any of prev candle' extremes
if(CCandlestick::isBull(index)){ // assigning flag to bullish engulfing
flag=1;
return true;
}
else if(CCandlestick::isBear(index)){ //bearish engulfing
flag=-1;
return true;
}
}
//else
return false;
}