342 lines
12 KiB
MQL5
342 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| SandR.mq5 |
|
|
//| BP |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "BP"
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
#property indicator_chart_window
|
|
#property indicator_buffers 10
|
|
#property indicator_plots 10
|
|
//--- plot R1
|
|
#property indicator_label1 "R1"
|
|
#property indicator_type1 DRAW_ARROW
|
|
#property indicator_color1 clrBeige
|
|
#property indicator_style1 STYLE_SOLID
|
|
#property indicator_width1 2
|
|
//--- plot S1
|
|
#property indicator_label2 "S1"
|
|
#property indicator_type2 DRAW_ARROW
|
|
#property indicator_color2 clrPowderBlue
|
|
#property indicator_style2 STYLE_SOLID
|
|
#property indicator_width2 2
|
|
//--- plot R2
|
|
#property indicator_label3 "R2"
|
|
#property indicator_type3 DRAW_ARROW
|
|
#property indicator_color3 clrBeige
|
|
#property indicator_style3 STYLE_SOLID
|
|
#property indicator_width3 1
|
|
//--- plot S2
|
|
#property indicator_label4 "S2"
|
|
#property indicator_type4 DRAW_ARROW
|
|
#property indicator_color4 clrPowderBlue
|
|
#property indicator_style4 STYLE_SOLID
|
|
#property indicator_width4 1
|
|
//--- plot R3
|
|
#property indicator_label5 "R3"
|
|
#property indicator_type5 DRAW_ARROW
|
|
#property indicator_color5 clrBeige
|
|
#property indicator_style5 STYLE_SOLID
|
|
#property indicator_width5 1
|
|
//--- plot S3
|
|
#property indicator_label6 "S3"
|
|
#property indicator_type6 DRAW_ARROW
|
|
#property indicator_color6 clrPowderBlue
|
|
#property indicator_style6 STYLE_SOLID
|
|
#property indicator_width6 1
|
|
//--- plot R4
|
|
#property indicator_label7 "R4"
|
|
#property indicator_type7 DRAW_ARROW
|
|
#property indicator_color7 clrBeige
|
|
#property indicator_style7 STYLE_SOLID
|
|
#property indicator_width7 1
|
|
//--- plot S4
|
|
#property indicator_label8 "S4"
|
|
#property indicator_type8 DRAW_ARROW
|
|
#property indicator_color8 clrPowderBlue
|
|
#property indicator_style8 STYLE_SOLID
|
|
#property indicator_width8 1
|
|
//--- plot R5
|
|
#property indicator_label9 "R5"
|
|
#property indicator_type9 DRAW_ARROW
|
|
#property indicator_color9 clrBeige
|
|
#property indicator_style9 STYLE_SOLID
|
|
#property indicator_width9 1
|
|
//--- plot S5
|
|
#property indicator_label10 "S5"
|
|
#property indicator_type10 DRAW_ARROW
|
|
#property indicator_color10 clrPowderBlue
|
|
#property indicator_style10 STYLE_SOLID
|
|
#property indicator_width10 1
|
|
|
|
//--- input parameters
|
|
input int SRnumber=2; //Number of line (max 5)
|
|
input int BarNumber=50; //Number of bars to analyse high and low
|
|
input int HistBarNumber=200; //Number of bars to create the score
|
|
input double Tolerence=30; //Tolerence in detection of cluster
|
|
input int ScoreMinMax = 2; //Bonus for high or low
|
|
input int ScoreReverse = 100; //Bonus for reversal bars
|
|
input int CrossingPenalty = -100; //Penalty for crossing
|
|
input int ScoreLimit = -10000;
|
|
|
|
//--- indicator buffers
|
|
double R1Buffer[];
|
|
double R2Buffer[];
|
|
double R3Buffer[];
|
|
double R4Buffer[];
|
|
double R5Buffer[];
|
|
double S1Buffer[];
|
|
double S2Buffer[];
|
|
double S3Buffer[];
|
|
double S4Buffer[];
|
|
double S5Buffer[];
|
|
|
|
//-- global variables
|
|
double lastOpen;
|
|
int sr_number;
|
|
double tol;
|
|
int maxInd = BarNumber-1;
|
|
struct simpleSR{
|
|
int score;
|
|
double value;
|
|
};
|
|
|
|
struct SR{
|
|
bool state;
|
|
int rScore;
|
|
int histBar_rScore[];
|
|
int sScore;
|
|
int histBar_sScore[];
|
|
double rValue;
|
|
double sValue;
|
|
};
|
|
SR srs[];
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- indicator buffers mapping
|
|
SetIndexBuffer(0,R1Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(1,S1Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(2,R2Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(3,S2Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(4,R3Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(5,S3Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(6,R4Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(7,S4Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(8,R5Buffer,INDICATOR_DATA);
|
|
SetIndexBuffer(9,S5Buffer,INDICATOR_DATA);
|
|
lastOpen = 0;
|
|
if(SRnumber>5){
|
|
sr_number = 5;
|
|
}
|
|
else{
|
|
sr_number = SRnumber;
|
|
}
|
|
ArrayResize(srs,BarNumber);
|
|
for(int i=0; i<BarNumber; i++){
|
|
srs[i].state = false;
|
|
srs[i].rScore = 0;
|
|
srs[i].rValue = 0;
|
|
ArrayResize(srs[i].histBar_rScore,HistBarNumber);
|
|
ArrayFill(srs[i].histBar_rScore,0,HistBarNumber,0);
|
|
srs[i].sScore = 0;
|
|
srs[i].sValue = 0;
|
|
ArrayResize(srs[i].histBar_sScore,HistBarNumber);
|
|
ArrayFill(srs[i].histBar_sScore,0,HistBarNumber,0);
|
|
}
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total,
|
|
const int prev_calculated,
|
|
const datetime &time[],
|
|
const double &open[],
|
|
const double &high[],
|
|
const double &low[],
|
|
const double &close[],
|
|
const long &tick_volume[],
|
|
const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
//---
|
|
//--- check for rates count
|
|
if(rates_total<HistBarNumber){
|
|
return(0);
|
|
}
|
|
int pos;
|
|
//PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,rates_total-DrawBar);
|
|
pos=prev_calculated-1;
|
|
/*if(pos < rates_total - DrawBar){
|
|
pos = rates_total - DrawBar;
|
|
}*/
|
|
if(pos < HistBarNumber){
|
|
pos = HistBarNumber+1;
|
|
}
|
|
for(int t=pos; t < rates_total; t++){
|
|
//skip calculation if tick is in the same bar
|
|
if(lastOpen == open[t]){
|
|
continue;
|
|
}
|
|
|
|
int lastHistBar = t-HistBarNumber;
|
|
int firstHistBar = t-1;
|
|
|
|
//set the tolerence
|
|
double max = high[t-BarNumber];
|
|
double min = low[t-BarNumber];
|
|
for(int i=t-BarNumber; i> t; i++){
|
|
if(high[i]>max){
|
|
max = high[i];
|
|
}
|
|
if(low[i]<min){
|
|
min = low[i];
|
|
}
|
|
}
|
|
tol = (max-min)/Tolerence;
|
|
|
|
//slide the array forward
|
|
ArrayRemove(srs,0,1);
|
|
ArrayResize(srs,BarNumber);
|
|
srs[maxInd].state = false;
|
|
srs[maxInd].rScore = 0;
|
|
srs[maxInd].rValue = 0;
|
|
ArrayResize(srs[maxInd].histBar_rScore,HistBarNumber);
|
|
ArrayFill(srs[maxInd].histBar_rScore,0,HistBarNumber,0);
|
|
srs[maxInd].sScore = 0;
|
|
srs[maxInd].sValue = 0;
|
|
ArrayResize(srs[maxInd].histBar_sScore,HistBarNumber);
|
|
ArrayFill(srs[maxInd].histBar_sScore,0,HistBarNumber,0);
|
|
|
|
for(int b=0; b<BarNumber; b++){
|
|
//slide hist arrays forward
|
|
ArrayRemove(srs[b].histBar_rScore,0,1);
|
|
ArrayRemove(srs[b].histBar_sScore,0,1);
|
|
ArrayResize(srs[b].histBar_rScore,HistBarNumber);
|
|
ArrayResize(srs[b].histBar_sScore,HistBarNumber);
|
|
srs[b].histBar_rScore[HistBarNumber-1] = 0;
|
|
srs[b].histBar_sScore[HistBarNumber-1] = 0;
|
|
|
|
//update score or create score
|
|
int start = lastHistBar;
|
|
if(srs[b].state == true) start = firstHistBar;
|
|
int i = t-(BarNumber-b);
|
|
|
|
srs[b].rValue = high[i];
|
|
srs[b].sValue = low[i];
|
|
for(int j= start; j < t; j++){
|
|
int hb = HistBarNumber - (t-j);
|
|
if(i!=j){
|
|
//test high of bar[i] against all other high
|
|
if(high[j]<high[i]+tol && high[j]>high[i]-tol){
|
|
srs[b].histBar_rScore[hb] += ScoreMinMax;
|
|
if(high[j]>srs[b].rValue) srs[b].rValue = high[j];
|
|
}
|
|
|
|
//test high of bar[i] against close of bar that are going up and followed by a bar going down
|
|
if(open[j-1]<close[j-1] && open[j]>close[j] && open[j]<high[i]+tol && open[j]>high[i]-tol){
|
|
srs[b].histBar_rScore[hb] += ScoreReverse;
|
|
if(open[j]>srs[b].rValue) srs[b].rValue = open[j];
|
|
}
|
|
|
|
//test low of bar[i] against all other low
|
|
if(low[j]<low[i]+tol && low[j]>low[i]-tol){
|
|
srs[b].histBar_sScore[hb] += ScoreMinMax;
|
|
if(low[j]<srs[b].sValue) srs[b].sValue = low[j];
|
|
}
|
|
|
|
//test low of bar[i] against close of bar that are going down and followed by a bar going up
|
|
if(open[j-1]>close[j-start] && open[j]<close[j] && open[j]<low[i]+tol && open[j]>low[i]-tol){
|
|
srs[b].histBar_sScore[hb] += ScoreReverse;
|
|
if(open[j]<srs[b].sValue) srs[b].sValue = open[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
//decrease the score if resistance or support had been crossed
|
|
for(int j= start; j < t; j++){
|
|
int hb = HistBarNumber - (t-j);
|
|
if(srs[b].rValue>open[j] && srs[b].rValue<close[j]) srs[b].histBar_rScore[hb] += CrossingPenalty;
|
|
if(srs[b].sValue<open[j] && srs[b].sValue>close[j]) srs[b].histBar_sScore[hb] += CrossingPenalty;
|
|
}
|
|
|
|
//calculate final scores of the bar
|
|
for(int j=0; j<HistBarNumber; j++){
|
|
srs[b].rScore += srs[b].histBar_rScore[j];
|
|
srs[b].sScore += srs[b].histBar_sScore[j];
|
|
}
|
|
}
|
|
|
|
//create clusters
|
|
simpleSR S[];
|
|
simpleSR R[];
|
|
ArrayResize(S,BarNumber);
|
|
ArrayResize(R,BarNumber);
|
|
|
|
for(int b=0; b<BarNumber; b++){
|
|
S[b].score = srs[b].sScore;
|
|
S[b].value = srs[b].sValue;
|
|
R[b].score = srs[b].rScore;
|
|
R[b].value = srs[b].rValue;
|
|
for(int j=0; j<BarNumber; j++){
|
|
if(b!=j){
|
|
if(srs[b].sValue > srs[j].sValue-tol && srs[b].sValue < srs[j].sValue+tol){
|
|
S[b].score += srs[j].sScore;
|
|
if(srs[j].sValue < S[b].value) S[b].value = srs[j].sValue;
|
|
}
|
|
if(srs[b].rValue > srs[j].rValue-tol && srs[b].rValue < srs[j].rValue+tol){
|
|
R[b].score += srs[j].rScore;
|
|
if(srs[j].rValue > R[b].value) R[b].value = srs[j].rValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//select indexes of the 5 highest scores
|
|
uint iS[5];
|
|
uint iR[5];
|
|
ArrayFill(iS,0,5,0);
|
|
ArrayFill(iR,0,5,0);
|
|
for(int i=0; i<5; i++){
|
|
int j=i-1;
|
|
for(int b=0; b<BarNumber; b++){
|
|
if(j<0){
|
|
if(S[b].score > S[iS[i]].score || (S[b].score == S[iS[i]].score && S[b].value < S[iS[i]].value)) iS[i] = b;
|
|
if(R[b].score > R[iR[i]].score || (R[b].score == R[iR[i]].score && R[b].value > R[iR[i]].value)) iR[i] = b;
|
|
}
|
|
else{
|
|
if((S[b].score > S[iS[i]].score || (S[b].score == S[iS[i]].score && S[b].value < S[iS[i]].value)) && S[b].score < S[iS[j]].score) iS[i] = b;
|
|
if((R[b].score > R[iR[i]].score || (R[b].score == R[iR[i]].score && R[b].value > R[iR[i]].value)) && R[b].score < R[iR[j]].score) iR[i] = b;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
for(int i=0; i<5; i++){
|
|
if(S[iS[i]].score < ScoreLimit || i >= sr_number) S[iS[i]].value = 0;
|
|
if(R[iR[i]].score < ScoreLimit || i >= sr_number) R[iR[i]].value = 0;
|
|
}
|
|
|
|
//transfer values to the buffers
|
|
S1Buffer[t] = S[iS[0]].value;
|
|
S2Buffer[t] = S[iS[1]].value;
|
|
S3Buffer[t] = S[iS[2]].value;
|
|
S4Buffer[t] = S[iS[3]].value;
|
|
S5Buffer[t] = S[iS[4]].value;
|
|
R1Buffer[t] = R[iR[0]].value;
|
|
R2Buffer[t] = R[iR[1]].value;
|
|
R3Buffer[t] = R[iR[2]].value;
|
|
R4Buffer[t] = R[iR[3]].value;
|
|
R5Buffer[t] = R[iR[4]].value;
|
|
lastOpen = open[t];
|
|
}
|
|
|
|
//--- return value of prev_calculated for next call
|
|
return(rates_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|