I am quite new to writing mql4
code and would be grateful if I could get some help drawing rectangles when the following candlestick patterns occur:
FIG1:
Run code snippet
<blockquote class="imgur-embed-pub" lang="en" data-id="a/fRoPzsm"><a href="//imgur.com/a/fRoPzsm">Demand Zone 1</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
FIG2:
Run code snippet
<blockquote class="imgur-embed-pub" lang="en" data-id="a/4E8KE1R" data-context="false"><a href="//imgur.com/a/4E8KE1R">Demand Zone 2</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
and
FIG3:
Run code snippet
<blockquote class="imgur-embed-pub" lang="en" data-id="a/h6D6o6R"><a href="//imgur.com/a/h6D6o6R">Hidden Demand Zone</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
and respective Supply Zones
and opening a pending order with specified pips Stop Loss and Take Profit.
Pardon me for not including the images directly. I don't I have enough upvotes to do that.
Here is an explanation of the candlestick patterns in the linked images:
The general candlestick pattern
(Demand Zone) occurs when at least two or more consecutive bullish candles (with the last bullish candle high being the high of the time period) are followed by one or more bearish candles whose high and low are lower than the last bullish candle. Then finally followed by a bullish candle that forms the new high. The rectangle area which is the Demand Zone is taken from the Open to the Low of the last last bearish candle.
When a series of consecutive bullish candles has a candle with its low, lower than the previous candle and its High coinciding with its Close, then the Hidden Demand Zone is taken from the low to the open of the bullish candle.
The full explanation is available here for both demand and supply zones.
I am aware that bullish
and bearish
candles can be determined by
if ( ( Open[1] - Close[1] ) > 0)
{
// candle is bearish
}
else
{
// candle is bullish
}
I would really appreciate some help.
I'm late :'( Work kept me from StackOverflow :'( Anyway, I won't be able to provide a full program as per the Bounty, nor can I provide the full code to solve this Demand Zone question.
However, I still would like to provide some "starting ground" for everyone to build their own Pattern Recognizer on MT4 (MQL4).
To keep the text short, I've recorded a YouTube video to describe it. https://youtu.be/WSiyY52QyBI
Anyway, here are the codes:
//+------------------------------------------------------------------+
//| SO56854700.mq4 |
//| Copyright 2019, Joseph Lee, TELEGRAM JosephLee74 |
//| https://stackoverflow.com/users/1245195/joseph-lee |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Joseph Lee, TELEGRAM JosephLee74"
#property link "https://stackoverflow.com/users/1245195/joseph-lee"
#property version "1.00"
#property strict
#include <clsBar.mqh>
#include <stderror.mqh>
#include <stdlib.mqh>
//==========================================================================
//-------------------------------------------------------------------
// System Variables
//-------------------------------------------------------------------
double viPipsToPrice = 0.0001;
double viPipsToPoint = 1;
string vsDisplay = "";
//-------------------------------------------------------------------
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
ObjectsDeleteAll(); Comment("");
// Caclulate PipsToPrice & PipsToPoints (old sytle, but works)
if((Digits == 2) || (Digits == 3)) {viPipsToPrice=0.01;}
if((Digits == 3) || (Digits == 5)) {viPipsToPoint=10;}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
ObjectsDeleteAll();
return(0);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
if(!isNewBar())
return;
clsCandlestickPattern voPatterns[];
clsPatternRecognizer voRec(Symbol(), true), PERIOD_CURRENT, 0);
voRec.sbRecognizePatterns(voPatterns);
for(...
Display the content with Comment() ...
}
//+------------------------------------------------------------------+
More importantly, is the clsBar.mqh. Note that this is an "include file", and should be located in the include folder. Include file helps us to make our program less clutter, and help us to be able to write re-usable codes. Very useful when writing OOP classes.
clsBar.mqh: Download (OneDrive) https://1drv.ms/u/s!AoLFy6fRYNsvjTU-xSzAADCwGjPQ
Unfortunately, the file is too large to be included in this post. So I have to upload it the OneDrive.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With