Seems these patterns are not fully described, so it is not possible to code them correctly. Ok, let us try with pattern#1.
The conditions used for pattern(what seems reasonable from the picture):
1. check at start of the new bar(bar#0).
2. bar 1(which is bar#3 in MQL4 if we compute 0 as the current) must be bullish.
3. bar 2(bar#2) is bearish. (or N bars in case of pattern#2, N can be 2 or more)
4. bar 3(bar#1 in MT4) is bullish.
5. its high=close.
6. its high>high of bar#3.
enum EnmDir
{
LONG = 1,
SHORT=-1,
NONE = 0,
};
int getCandleDirection(const int shift)
{
const double open=iOpen(_Symbol,0,shift), close=iClose(_Symbol,0,shift);
if(close-open>_Point/2.)
return LONG; //bullish
if(open-close>_Point/2.)
return SHORT; //bearish
return NONE; //doji
}
bool isPattern1Detected(const EnmDir dir)
{
if(dir==0)return(false);
if(getCandleDirection(3)!=dir)
return false; //rule#2
if(getCandleDirection(2)+dir!=0)
return false; //rule#3
if(getCandleDirection(1)!=dir)
return false; //rule#4
if(dir>0)
{
if(iHigh(_Symbol,0,1)-iClose(_Symbol,0,1)>_Point/2.)
return false; //rule#5 for long
if(iHigh(_Symbol,0,1)-iHigh(_Symbol,0,3)>_Point/2.)
return true; //rule#6 for long
return false; //if rule#6 is not hold
}
else
{
if(iClose(_Symbol,0,1)-iLow(_Symbol,0,1)>_Point/2.)
return false; //rule#5 for short
if(iLow(_Symbol,0,3)-iLow(_Symbol,0,1)>_Point/2.)
return true; //rule#6 for short
return false; //if rule#6 is not hold
}
}
bool isPattern2Detected(const EnmDir dir,const int numCandlesAgainst=1)
{
if(dir==NONE)return(false);
if(getCandleDirection(1)!=dir)
return false; //rule#4
for(int i=1;i<=numCandlesAgainst;i++)
{
if(getCandleDirection(1+i)!=dir)
return(false); //rule#3 - checking that all numCandlesAgainst must be bearish
}
if(getCandleDirection(2+numCandlesAgainst)!=dir)
return false; //rule#2
if(dir>0)
{
if(iHigh(_Symbol,0,1)-iClose(_Symbol,0,1)>_Point/2.)
return false; //rule#5 for long
if(iHigh(_Symbol,0,1)-iHigh(_Symbol,0,2+numCandlesAgainst)>_Point/2.)
return true; //rule#6 for long
return false; //if rule#6 is not hold
}
else
{
if(iClose(_Symbol,0,1)-iLow(_Symbol,0,1)>_Point/2.)
return false; //rule#5 for short
if(iLow(_Symbol,0,2+numCandlesAgainst)-iLow(_Symbol,0,1)>_Point/2.)
return true; //rule#6 for short
return false; //if rule#6 is not hold
}
}
What else you need here? To detect HL of the rectangle? That is simple, is rules are clear. Let us assume they are: for LONG, up=Open of bar#2, down=low of that bar. Then,
void detectRangeOfZone(double &top,double &bottom,const EnmDir dir)
{
if(dir>0)
{
top=iOpen(_Symbol,0,2);
bottom=iLow(_Symbol,0,2);
}
else if(dir<0)
{
top=iClose(_Symbol,0,2);
bottom=iHigh(_Symbol,0,2);
}
}
Do you need to draw a rectangle? Ok but how would you decide what is the time to stop drawing? Let us assume N bars to the right is enough, and let us ignore weekends for now(a bit more complicated if keeping in mind weekends when the market is closed).
bool drawRectangle(const int dir,const double top,const double bottom)
{
const datetime starts=iTime(_Symbol,0,2), ends=starts+PeriodSeconds()*N_bars;//time of start and end of the rectangle
const string name=prefix+"_"+(dir>0?"DEMAND":"SUPPLY")+"_"+TimeToString(starts);//name would be unique sinse we use time of start of the range. DO NOT FORGET about prefix - it should be declared globally, you would be able to delete all the objects with 'ObjectsDeleteAll()' function that accepts prefix in one of its implementations.
if(!ObjectCreate(0,name,OBJ_RECTANGLE,0,0,0,0,0))
{
printf("%i %s: failed to create %s. error=%d",__LINE__,__FILE__,name,_LastError);
return false;
}
ObjectSetInteger(0,name,OBJPROP_TIME1,starts);
ObjectSetInteger(0,name,OBJPROP_TIME2,ends);
ObjectSetDouble(0,name,OBJPROP_PRICE1,top);
ObjectSetDouble(0,name,OBJPROP_PRICE2,bottom);
//add color, width, filling color, access modifiers etc, example is here https://docs.mql4.com/ru/constants/objectconstants/enum_object/obj_rectangle
return true;
}
here is the main block, do not forget to add a new bar check, otherwise the tool would check for objects every tick which is waste of time.
string prefix=""; //add some unique prefix for all your objects
const int N_bars = 15; //15 bars in this example
void OnDeinit(const int reason){ObjectsDeleteAll(0,prefix);}
void OnTick()
{
if(!isNewBar())
return; //not necessary but waste of time to check every second
const bool pattern1Up=isPattern1Detected(1), pattern1Dn=isPattern1Detected(-1);
if(pattern1Up)
{
double top,bottom;
detectRangeOfZone(top,bottom,1);
drawRectangle(1,top,bottom);
PlacePendingOrder(1,top,bottom);
}
if(pattern1Dn)
{
double top,bottom;
detectRangeOfZone(top,bottom,-1);
drawRectangle(-1,top,bottom);
PlacePendingOrder(-1,top,bottom);
}
}
int PlacePendingOrder(const EnmDir dir,const double oop,const double suggestedSl)
{
const double lot=0.10; //FOR EXAMPLE, PUT YOUR DATA HERE
const string comment="example for SOF";
const int magicNumber=123456789;
int cmd=dir>0 ? OP_BUY : OP_SELL;
double price=(dir>0 ? Ask : Bid), spread=(Ask-Bid);
if(dir*(oop-price)>spread)
cmd+=(OP_BUYSTOP-OP_BUY);
else if(dir*(price-oop)>spread)
cmd+=(OP_BUYLIMIT-OP_BUY);
int attempt=0, ATTEMPTS=5, SLEEP=25, SLIPPAGE=10, result=-1, error=-1;
while(attempt<ATTEMPTS)
{
attempt++;
RefreshRates();
if(cmd<=OP_SELL)
{
price=dir>0 ? Ask : Bid;
result=OrderSend(_Symbol,cmd,lot,price,SLIPPAGE,0,0,comment,magicNumber);
}
else
{
result=OrderSend(_Symbol,cmd,lot,oop,SLIPPAGE,0,0,comment,magicNumber);
}
if(result>0)
break;
error=_LastError;
Sleep(SLEEP);
}
if(result>0)
{
if(OrderSelect(result,SELECT_BY_TICKET))
{
price=OrderOpenPrice();
if(!OrderModify(result,price,suggestedSl,0,OrderExpiration()))
printf("%i %s: failed to modify %d. error=%d",__LINE__,__FILE__,result,_LastError);
//tp is zero, sl is suggested SL, put yours when needed
}
return result;
}
printf("%i %s: failed to place %s at %.5f. error=%d",__LINE__,__FILE__,EnumToString((ENUM_ORDER_TYPE)cmd),(cmd>OP_SELL ? oop : price),error);
return -1;
}