MultiSymbolSignals/Indicators/MultiSymbol/MultiSymbolPriceDivergence.mq5

798 lines
71 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:10:44 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| MultiSymbolPriceDivergence.mq5 |
//| Copyright 2013, https://login.mql5.com/ru/users/tol64 |
//| Site, http://tol64.blogspot.com |
//+------------------------------------------------------------------+
//--- !2>9AB20 8=48:0B>@0
#property copyright "Copyright 2013, http://tol64.blogspot.com"
#property link "http://tol64.blogspot.com/2013/06/218.html"
#property description "email: hello.tol64@gmail.com"
#property version "1.0"
//---
#property indicator_chart_window // K2>48BL 8=48:0B>@ 2 >:=> 3@0D8:0
#property indicator_buffers 25 // >;8G5AB2> 1CD5@>2 4;O @0AGQB0 8=48:0B>@0
#property indicator_plots 5 // >;8G5AB2> 3@0D8G5A:8E A5@89
//--- &25B0 F25B>2KE 1CD5@>2
#property indicator_color1 clrDodgerBlue,C'0,50,100'
#property indicator_color2 clrMagenta,C'130,0,130'
#property indicator_color3 clrGold,C'160,140,0'
#property indicator_color4 clrAqua,C'0,140,140'
#property indicator_color5 clrLimeGreen,C'20,80,20'
//--- >=AB0=B0 4;O 2>72@0B0 B5@<8=0;C :><0=4K =0 ?5@5AGQB 8=48:0B>@0
#define RESET 0
//--- >;8G5AB2> A8<2>;>2
#define SYMBOLS 5
//--- <O ?@>3@0<<K
#define PROGRAM_NAME MQL5InfoString(MQL5_PROGRAM_NAME)
//--- >4:;NG8< :;0AA 4;O @01>BK A :0=2>9
#include <Canvas\Canvas.mqh>
//--- >4:;NG05< A2>8 181;8>B5:8
#include <MultiSymbol/Checks.mqh>
#include <MultiSymbol/SettingChart.mqh>
#include <MultiSymbol/SetDeleteObjects.mqh>
//--- "8? @8A>20=8O 40==KE
enum ENUM_DRAWTYPE
{
LINES =0, // Lines
BARS =1, // Bars
CANDLES =2 // Candles
};
//--- 568< =0G0;L=>9 B>G:8 @0AE>645=8O F5=
enum ENUM_START_POINT
{
VERT_LINE =0, // Vertical Line
MONTH =1, // Month
WEEK =2, // Week
DAY =3, // Day
HOUR =4 // Hour
};
//--- =5H=85 ?0@0<5B@K
input ENUM_DRAWTYPE DrawType =CANDLES; // Draw Type
input ENUM_START_POINT StartPriceDivergence =VERT_LINE; // Start Price Divergence
input bool TwoColor =false; // Two Colored Bars/Candles
sinput string dlm01=""; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
input string Symbol02 ="EURUSD"; // Symbol 02
input bool Inverse02 =false; // Inverse Symbol 02
input string Symbol03 ="GBPUSD"; // Symbol 03
input bool Inverse03 =false; // Inverse Symbol 03
input string Symbol04 ="EURGBP"; // Symbol 04
input bool Inverse04 =false; // Inverse Symbol 04
input string Symbol05 ="USDCAD"; // Symbol 05
input bool Inverse05 =false; // Inverse Symbol 05
input string Symbol06 ="USDCHF"; // Symbol 06
input bool Inverse06 =false; // Inverse Symbol 06
//--- !B@C:BC@0 <0AA82>2 8=48:0B>@=KE 1CD5@>2
struct buffers
{
double open[]; // CD5@ 4;O F5= >B:@KB8O
double high[]; // CD5@ 4;O F5= <0:A8<C<>2
double low[]; // CD5@ 4;O F5= <8=8<C<>2
double close[]; // CD5@ 4;O F5= 70:@KB8O
double icolor[]; // CD5@ 4;O >?@545;5=8O F25B0 M;5<5=B0
};
buffers buffer_data[SYMBOLS];
//--- 03@C7:0 :;0AA0
CCanvas canvas;
//--- 5@5<5==K5/<0AA82K 4;O :>?8@>20=8O 40==KE 87 OnCalculate()
int on_calc_rates_total =0; // 07<5@ 2E>4=KE B09<A5@89
int on_calc_prev_calculated =0; // 1@01>B0=> 10@>2 =0 ?@54K4CI5< 2K7>25
datetime on_calc_time[]; // @5<O >B:@KB8O
double on_calc_open[]; // &5=K >B:@KB8O
double on_calc_high[]; // 0:A8<0;L=K5 F5=K
double on_calc_low[]; // 8=8<0;L=K5 F5=K
double on_calc_close[]; // &5=K 70:@KB8O
long on_calc_tick_volume[]; // "8:>2K5 >1JQ<K
long on_calc_volume[]; // 50;L=K5 >1JQ<K
int on_calc_spread[]; // !?@54
//--- ;O E@0=5=8O 8 ?@>25@:8 2@5<5=8 ?5@2>3> 10@0 2 B5@<8=0;5
datetime series_first_date[SYMBOLS];
datetime series_first_date_last[SYMBOLS];
//--- 0AA82 2@5<5=8 10@0, >B :>B>@>3> =0G8=0BL >B@8A>2:C
datetime limit_time[SYMBOLS];
//--- 0AA82 =0720=89 A8<2>;>2
string symbols_names[SYMBOLS];
//--- 0AA82 =0720=89 A8<2>;>2
bool inverse[SYMBOLS];
//--- &25B0 ;8=89 8=48:0B>@0
color line_color[SYMBOLS]=
{clrDodgerBlue,clrLimeGreen,clrGold,clrAqua,clrMagenta};
//--- !B@>:0 A8<2>;878@CNI0O >BACBAB285 A8<2>;0
string empty_symbol="EMPTY";
//--- !2>9AB20 3@0D8:0
int number_window =WRONG_VALUE; // ><5@ >:=0 8=48:0B>@0
int chart_width =0; // (8@8=0 3@0D8:0
int chart_height =0; // KA>B0 3@0D8:0
int last_chart_width =0; // >A;54=OO 2 ?0<OB8 H8@8=0 3@0D8:0
int last_chart_height =0; // >A;54=OO 2 ?0<OB8 2KA>B0 3@0D8:0
int chart_wcenter =0; // &5=B@ 3@0D8:0 ?> 3>@87>=B0;8
int chart_vcenter =0; // &5=B@ 3@0D8:0 ?> 25@B8:0;8
color color_bar_up =clrRed; // &25B 10@0 225@E
color color_bar_down =C'100,0,0'; // &25B 10@0 2=87
string shortname_indicator ="MS_PriceDivergence"; // >@>B:>5 8<O 8=48:0B>@0
string prefix =shortname_indicator+"_"; // @5D8:A 4;O >1J5:B>2
//--- <O 25@B8:0;L=>9 ;8=88 =0G0;L=>9 B>G:8 @0AE>645=8O F5=
string start_price_divergence=prefix+"start_price_divergence";
//--- !2>9AB20 :0=2K
string canvas_name =prefix+"canvas"; // 0720=85 :0=2K
color canvas_bg_color =clrBlack; // &25B D>=0 :0=2K
uchar canvas_opacity =190; // !B5?5=L ?@>7@0G=>AB8
int font_size =16; // 07<5@ H@8DB0
string font_name ="Calibri"; // (@8DB
ENUM_COLOR_FORMAT clr_format =COLOR_FORMAT_ARGB_RAW; // ><?>=5=BK F25B0 =5 >1@010BK20NBAO B5@<8=0;><
//--- !>>1I5=8O :0=2K
string message_data_available =">43>B>2:0 40==KE! >4>648B5 ?>60;C9AB0...";
string message_is_synchronized ="0==K5 =5 A8=E@>=878@>20=K! >4>648B5 ?>60;C9AB0...";
string message_formation_data ="";
string message_data_update ="";
string message_last ="";
//---
ENUM_TIMEFRAMES timeframe_start_point =Period(); // "09<D@59< 4;O B>G:8 @0AE>645=8O F5=
datetime first_period_time =NULL; // @5<O ?5@2>3> C:070==>3> ?5@8>40 40==KE =0 3@0D8:5
double level_divergence =0.0; // &5=0 =0G0;L=>9 B>G:8 @0AE>645=8O F5=
datetime time_divergence =NULL; // @5<O =0G0;L=>9 B>G:8 @0AE>645=8O F5=
double symbol_difference[SYMBOLS]; // 07=8F0 2 F5=5 >B=>A8B5;L=> B5:CI53> A8<2>;0
double inverse_difference[SYMBOLS]; // 07=8F0, :>B>@0O >1@07C5BAO ?@8 @0AGQB5 8=25@A88
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- @>25@8<, =5 8A?>;L7C5BAO ;8 A59G0A 8=48:0B>@ 2 B5AB5@5
if(!CheckTesterMode())
return(INIT_FAILED);
//--- #AB0=>28< F25B 10@0</A25G0<
SetBarColors();
//--- ?@545;8< ?5@8>4 4;O =0G0;L=>9 B>G:8 @0AE>645=8O F5=
// Define the period for the starting point of price divergence.
InitModeStartPriceDivergence();
//--- @>25@8< :>@@5:B=>ABL 2E>4=KE ?0@0<5B@>2
// Check the correctness of the input parameters
if(!CheckInputParameters())
return(INIT_PARAMETERS_INCORRECT);
//--- :;NG8< B09<5@ A 8=B5@20;>< 1 A5:C=40
EventSetMillisecondTimer(1000);
//--- #AB0=>28< H@8DB 4;O >B>1@065=8O 2 :0=25
canvas.FontSet(font_name,font_size,FW_NORMAL);
//--- =8F80;870F8O <0AA82>2
InitArrays();
//--- =8F80;878@C5< <0AA82 A8<2>;>2
InitSymbolsNames();
//--- =8F80;878@C5< <0AA82 8=25@A89
InitInverse();
//--- #AB0=>28< A2>9AB20 8=48:0B>@0
SetPropertiesIndicator();
//--- #AB0=>28< 25@B8:0;L=CN ;8=8N =0G0;0 @0AE>645=8O F5=
SetLineStartPricesDivergence();
//--- G8AB8< :><<5=B0@89
Comment("");
//--- 1=>28< 3@0D8:
ChartRedraw();
//--- =8F80;870F8O ?@>H;0 CA?5H=>
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 58=8F80;870F8O |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(reason==REASON_REMOVE || // A;8 8=48:0B>@ C40;Q= A 3@0D8:0 8;8
reason==REASON_CHARTCHANGE || // A8<2>; 8;8 ?5@8>4 1K; 87<5=Q= 8;8
reason==REASON_RECOMPILE || // ?@>3@0<<0 1K;0 ?5@5:><?8;8@>20=0 8;8
reason==REASON_CHARTCLOSE || // 3@0D8: 1K; 70:@KB 8;8
reason==REASON_CLOSE || // B5@<8=0; 1K; 70:@KB 8;8
reason==REASON_PARAMETERS) // ?0@0<5B@K 1K;8 87<5=5=K
{
//--- B:;NG8< B09<5@
EventKillTimer();
//--- #40;8< 25@B8:0;L=K5 ;8=88
DeleteVerticalLines();
//--- #40;8< :0=2C
DeleteCanvas();
//--- B:;NG8< <0AHB018@>20=85
ChartSetInteger(0,CHART_SCALEFIX,false);
//--- G8AB8< :><<5=B0@89
Comment("");
}
//--- 1=>28< 3@0D8:
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, // @07<5@ 2E>4=KE B09<A5@89
const int prev_calculated, // >1@01>B0=> 10@>2 =0 ?@54K4CI5< 2K7>25
const datetime &time[], // @5<O >B:@KB8O
const double &open[], // &5=K >B:@KB8O
const double &high[], // 0:A8<0;L=K5 F5=K
const double &low[], // 8=8<0;L=K5 F5=K
const double &close[], // &5=K 70:@KB8O
const long &tick_volume[], // "8:>2K5 >1JQ<K
const long &volume[], // 50;L=K5 >1JQ<K
const int &spread[]) // !?@54
{
//--- ;O >?@545;5=8O, A :0:>3> 10@0 ?@>872>48BL @0AGQB
int limit=0;
//--- !45;05< :>?8N ?0@0<5B@>2 OnCalculate()
CopyDataOnCalculate(rates_total,prev_calculated,
time,open,high,low,close,
tick_volume,volume,spread);
//--- A;8 MB> ?5@2K9 @0AGQB 8;8 703@C65=0 1>;55 3;C1>:0O 8AB>@8O 8;8 1K;8 70?>;=5=K ?@>?CA:8 8AB>@88
// If this is the first calculation or a deeper history has been loaded or the history gaps have been filled
if(prev_calculated==0)
{
//--- 1=C;8< 8=48:0B>@=K5 1CD5@K - Zero indicator buffers
ZeroIndicatorBuffers();
//--- >;CG8< A2>9AB20 ?>4>:=0 - Get the properties of the subwindow
SetSubwindowProperties();
//--- #AB0=>28< :0=2C - Install the canvas
SetCanvas();
//--- 03@C78< 8 AD>@<8@C5< =5>1E>48<>5/8<5NI55AO :>;8G5AB2> 40==KE
// Load and generate the necessary / available amount of data.
LoadFormationData();
LoadFormationDataHighTF();
//--- @>25@O5B :>;8G5AB2> 4>ABC?=KE 40==KE C 2A5E A8<2>;>2
// Checks the amount of data available for all symbols.
if(!CheckAvailableData())
return(RESET);
//--- A;8 703@C65=0 1>;55 3;C1>:0O 8AB>@8O
// If a deeper hisstory is loaded
if(!CheckEventLoadHistory())
return(RESET);
//--- @>25@8< A8=E@>=878@>20==>ABL 40==KE ?> A8<2>;C/?5@8>4C =0 40==K9 <><5=B
// Check the synchronization of data on the symbol / period at the moment
if(!CheckSymbolIsSynchronized())
return(RESET);
//--- ?@545;8< 4;O :064>3> A8<2>;0, A :0:>3> 10@0 =0G8=0BL >B@8A>2:C
// For each symbol find the bar at which to start drawing
if(!DetermineBeginForCalculate())
return(RESET);
//--- A;8 4>H;8 4> MB>3> <><5=B0, B> 7=0G8B OnCalculate() 25@=QB =5=C;52>5 7=0G5=85
// 8 MB> =C6=> 70?><=8BL. Reaching this point means OnCalculate() returned nonzero.
on_calc_prev_calculated=rates_total;
}
//--- A;8 =C6=> ?5@5AG8B0BL B>;L:> ?>A;54=85 7=0G5=8O
// If you only need to recalculate the last
else
limit=prev_calculated-1;
//--- 0?>;=8< 8=48:0B>@=K5 1CD5@K - Fill indicator buffers
for(int s=0; s<SYMBOLS; s++)
{
//--- A;8 B0:>9 A8<2>; 5ABL, B> - If this symbol exists then
if(symbols_names[s]!=empty_symbol)
{
//--- !D>@<8@C5< 8 2K2545< A>>1I5=85 - Form and display a message
message_last=message_data_update="1=>2;5=85 40==KE 8=48:0B>@0: "+
symbols_names[s]+"("+IntegerToString(s+1)+"/"+IntegerToString(SYMBOLS)+") ... ";
ShowCanvasMessage(message_data_update);
//--- 0?>;=8< 8=48:0B>@=K5 1CD5@K 7=0G5=8O<8 - Fill indicator buffers with values
for(int i=limit; i<rates_total; i++)
{
FillIndicatorBuffers(i,s,time);
//--- 064K5 2000 10@>2 ?@>25@O5< @07<5@K >:=0 8 5A;8 @07<5@ 87<5=8;AO
// ?>43>=8< ?>4 =53> @07<5@ :0=2K
// Every 2000 bars we check the size of the window and if the size has changed
// we will adapt the size of the canvas
if(!(i%2000))
EventChartChange();
}
}
}
//--- !>@@5:B8@C5< <0:A8<C< 8 <8=8<C< 3@0D8:0
CorrectMaximumMinimumChart();
//--- #40;8< :0=2C
DeleteCanvas();
//--- 1=C;8< ?5@5<5==K5 A>>1I5=89
message_last="";
message_data_update="";
//--- 1=>28< 3@0D8:
ChartRedraw();
//--- 5@=Q< @07<5@ <0AA820 40==KE B5:CI53> A8<2>;0
return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//--- !>1KB85 ?5@5B0A:820=8O 3@0D8G5A:>3> >1J5:B0
if(id==CHARTEVENT_OBJECT_DRAG)
{
//--- A;8 A59G0A @568< 25@B8:0;L=>9 ;8=88 4;O =0G0;L=>9 B>G:8 @0AE>645=8O F5=,
// >1=>28< 8=48:0B>@=K5 1CD5@K
if(StartPriceDivergence==VERT_LINE)
OnCalculate(on_calc_rates_total,0,
on_calc_time,on_calc_open,on_calc_high,on_calc_low,on_calc_close,
on_calc_tick_volume,on_calc_volume,on_calc_spread);
}
//--- 7<5=5=85 @07<5@>2 3@0D8:0 8;8 87<5=5=85 A2>9AB2 3@0D8:0 G5@57 480;>3 A2>9AB2
if(id==CHARTEVENT_CHART_CHANGE)
//--- !:>@@5:B8@C5< <0:A8<C< 8 <8=8<C< 3@0D8:0
// >B=>A8B5;L=> 7=0G5=89 2 8=48:0B>@=KE 1CD5@0E
CorrectMaximumMinimumChart();
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//--- @>25@:0 ?CABKE 7=0G5=89
if(!CheckEmptyValues())
on_calc_prev_calculated=0;
//--- A;8 1K;0 703@C65=0 1>;55 3;C1>:0O 8AB>@8O
if(!CheckEventLoadHistory())
on_calc_prev_calculated=0;
//--- 1=>2;O5< 7=0G5=8O 8=48:0B>@0 :064CN A5:C=4C
OnCalculate(on_calc_rates_total,on_calc_prev_calculated,
on_calc_time,on_calc_open,on_calc_high,on_calc_low,on_calc_close,
on_calc_tick_volume,on_calc_volume,on_calc_spread);
//--- @>25@:0 7=0G5=89 2 8=48:0B>@=KE 1CD5@0E
//CheckLastEmptyValues(10);
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B A2>9AB20 8=48:0B>@0 |
//+------------------------------------------------------------------+
void SetPropertiesIndicator()
{
//--- #AB0=>28< :>@>B:>5 8<O
IndicatorSetString(INDICATOR_SHORTNAME,shortname_indicator);
//--- #AB0=>28< :>;8G5AB2> 7=0:>2
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- ?@545;8< 1CD5@K 4;O >B@8A>2:8
//  @568<5 ;8=8O =C65= B>;L:> >48= 1CD5@ >B>1@060NI89 F5=C >B:@KB8O
if(DrawType==LINES)
{
for(int s=0; s<SYMBOLS; s++)
SetIndexBuffer(s,buffer_data[s].close,INDICATOR_DATA);
}
//---  4@C38E @568<0E 8A?>;L7C5< 2A5 F5=K 4;O ?>AB@>5=8O
// 10@>2/A25G 8 4>?>;=8B5;L=K9 1CD5@ 4;O 42CEF25B=>3> @568<0
else if(DrawType==BARS || DrawType==CANDLES)
{
for(int s=0; s<SYMBOLS; s++)
{
static int number_buffer=0;
SetIndexBuffer(number_buffer,buffer_data[s].open,INDICATOR_DATA);
number_buffer++;
SetIndexBuffer(number_buffer,buffer_data[s].high,INDICATOR_DATA);
number_buffer++;
SetIndexBuffer(number_buffer,buffer_data[s].low,INDICATOR_DATA);
number_buffer++;
SetIndexBuffer(number_buffer,buffer_data[s].close,INDICATOR_DATA);
number_buffer++;
SetIndexBuffer(number_buffer,buffer_data[s].icolor,INDICATOR_COLOR_INDEX);
number_buffer++;
}
}
//--- #AB0=>28< <5B:8 4;O B5:CI53> B09<D@59<0
//  @568<5 ;8=8O B>;L:> F5=0 >B:@KB8O
if(DrawType==LINES)
{
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetString(s,PLOT_LABEL,symbols_names[s]+",Close");
}
//---  4@C38E @568<0E 2A5 F5=K 10@>2/A25G
//  :0G5AB25 @0745;8B5;O 8A?>;L7C5BAO ";"
else if(DrawType==BARS || DrawType==CANDLES)
{
for(int s=0; s<SYMBOLS; s++)
{
PlotIndexSetString(s,PLOT_LABEL,
symbols_names[s]+",Open;"+
symbols_names[s]+",High;"+
symbols_names[s]+",Low;"+
symbols_names[s]+",Close");
}
}
//--- #AB0=>28< B8? ;8=89 4;O 8=48:0B>@=KE 1CD5@>2
// 8=8O
if(DrawType==LINES)
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_LINE);
//--- 0@K
if(DrawType==BARS)
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_BARS);
//--- !25G8
if(DrawType==CANDLES)
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_CANDLES);
//--- #AB0=>28< B8? ;8=89 4;O 40==KE B5:CI53> A8<2>;0
// 8=8O
if(DrawType==LINES)
ChartSetInteger(0,CHART_MODE,CHART_LINE);
//--- 0@K
if(DrawType==BARS)
ChartSetInteger(0,CHART_MODE,CHART_BARS);
//--- !25G8
if(DrawType==CANDLES)
ChartSetInteger(0,CHART_MODE,CHART_CANDLES);
//--- #AB0=>28< B>;I8=C ;8=89
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetInteger(s,PLOT_LINE_WIDTH,1);
//--- #AB0=>28< F25B ;8=89 4;O @568<0 8=8O
if(DrawType==LINES)
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetInteger(s,PLOT_LINE_COLOR,line_color[s]);
//--- #AB0=>28< ?>:07 40==KE 2 :=5 0==KE B>;L:> ACI5AB2CNI8E A8<2>;>2
for(int s=0; s<SYMBOLS; s++)
{
if(symbols_names[s]!=empty_symbol)
PlotIndexSetInteger(s,PLOT_SHOW_DATA,true);
else
PlotIndexSetInteger(s,PLOT_SHOW_DATA,false);
}
//--- CAB>5 7=0G5=85 4;O ?>AB@>5=8O, 4;O :>B>@>3> =5B >B@8A>2:8
for(int s=0; s<SYMBOLS; s++)
PlotIndexSetDouble(s,PLOT_EMPTY_VALUE,EMPTY_VALUE);
}
//+------------------------------------------------------------------+
//| 5@20O 8=8F80;870F8O <0AA82>2 |
//+------------------------------------------------------------------+
void InitArrays()
{
ArrayInitialize(limit_time,NULL);
ArrayInitialize(symbol_difference,0.0);
ArrayInitialize(inverse_difference,0.0);
ArrayInitialize(series_first_date,NULL);
ArrayInitialize(series_first_date_last,NULL);
//---
for(int s=0; s<SYMBOLS; s++)
{
ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].high,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].low,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].close,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].icolor,EMPTY_VALUE);
}
}
//+------------------------------------------------------------------+
//| =8F80;878@C5B <0AA82 A8<2>;>2 |
//+------------------------------------------------------------------+
void InitSymbolsNames()
{
symbols_names[0]=CheckGetSymbol(Symbol02);
symbols_names[1]=CheckGetSymbol(Symbol03);
symbols_names[2]=CheckGetSymbol(Symbol04);
symbols_names[3]=CheckGetSymbol(Symbol05);
symbols_names[4]=CheckGetSymbol(Symbol06);
}
//+------------------------------------------------------------------+
//| =8F80;878@C5B <0AA82 8=25@A89 |
//+------------------------------------------------------------------+
void InitInverse()
{
inverse[0]=Inverse02;
inverse[1]=Inverse03;
inverse[2]=Inverse04;
inverse[3]=Inverse05;
inverse[4]=Inverse06;
}
//+------------------------------------------------------------------+
//| ?@545;O5B B09<D@59< 4;O @568<0 =0G0;L=>9 B>G:8 F5= |
//+------------------------------------------------------------------+
void InitModeStartPriceDivergence()
{
//--- A;8 @568< 25@B8:0;L=>9 ;8=88, 2K945<
if(StartPriceDivergence==VERT_LINE)
return;
//--- =0G5 >?@545;8< ?5@8>4
switch(StartPriceDivergence)
{
case MONTH : timeframe_start_point=PERIOD_MN1; break;
case WEEK : timeframe_start_point=PERIOD_W1; break;
case DAY : timeframe_start_point=PERIOD_D1; break;
case HOUR : timeframe_start_point=PERIOD_H1; break;
}
}
//+------------------------------------------------------------------+
//| 0?>;=O5B 8=48:0B>@=K5 1CD5@K |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(int i,int s,datetime const &time[])
{
MqlRates rates[]; // !B@C:BC@0 40==KE
double period_open[]; // &5=0 >B:@KB8O 10@0 2 =0G0;5 ?5@8>40 @0AE>645=8O F5=
datetime period_time[]; // @5<O =0G0;0 ?5@8>40 @0AE>645=8O F5=
int try =100; // >;8G5AB2> ?>?KB>: :>?8@>20=8O
datetime high_tf_time =NULL; // @5<O 10@0 AB0@H53> B09<D@59<0
//--- A;8 =0E>48<AO 2=5 7>=K "8AB8==KE" 10@>2 A8<2>;0, 2K945<
// When we find ourselves outside the zone of "true" bars of the symbol, we'll exit
if(time[i]<limit_time[s])
return;
//--- !1@>A8< ?>A;54=NN >H81:C
ResetLastError();
//--- >;CG8< 40==K5 B5:CI53> 10@0 C:070==>3> A8<2>;0
// Get the data of the current bar of the specified symbol
for(int j=0; j<try; j++)
if(CopyRates(symbols_names[s],Period(),time[i],1,rates)==1)
{ ResetLastError(); break; }
//--- A;8 =5C40;>AL ?>;CG8BL 40==K5, 2K945<
// When failing to get the data, we ll exit
if(ArraySize(rates)<1 || GetLastError()!=0)
return;
//--- A;8 2@5<O 10@0 B5:CI53> A8<2>;0 =0 3@0D8:5 =5@02=> 2@5<5=8 10@0 C:070==>3> A8<2>;0, 2K945<
// If the bar time of the current symbol on the chart is not equal to the bar time of the specified symbol,
// we ll exit
if(time[i]!=rates[0].time)
return;
//--- A;8 2 @568<5 25@B8:0;L=>9 ;8=88 4;O =0G0;L=>9 B>G:8 @0AE>645=8O F5=
// When in vertical line mode for the starting point of the divergence of prices
if(StartPriceDivergence==VERT_LINE)
{
//--- >;CG8< 2@5<O ;8=88
time_divergence=(datetime)ObjectGetInteger(0,start_price_divergence,OBJPROP_TIME);
//--- >;CG8< 2@5<O ?5@2>3> 10@0
first_period_time=time[0];
}
//--- A;8 2 4@C38E @568<0E, B> 1C45< >BA;56820BL =0G0;> ?5@8>40
// When in friend mode, then we will retrace the start of the period
else
{
//--- A;8 70H;8 AN40 2 ?5@2K9 @07, B> 70?><=8< 40==K5 ?5@2>3> 10@0 AB0@H53> B09<D@59<0
// If we passed this part for the first time then we will remember the data of the first bar
// of the higher timeframe
if(time_divergence==NULL)
{
ResetLastError();
//--- >;CG8< 2@5<O >B:@KB8O ?5@2>3> 10@0 AB0@H53> B09<D@59<0
// Get the opening time of the first bar of the higher timeframe
for(int j=0; j<try; j++)
if(CopyTime(Symbol(),timeframe_start_point,time[0]+PeriodSeconds(timeframe_start_point),1,period_time)==1)
{ ResetLastError(); break; }
//--- A;8 =5 C40;>AL ?>;CG8BL F5=C/2@5<O, 2K945<
// If you did not succeed getting the price / time, we will leave
if(ArraySize(period_time)<1 || GetLastError()!=0)
return;
//--- =0G5 70?><=8< 2@5<O ?5@2>3> 10@0 AB0@H53> B09<D@59<0
// Otherwise we remember the time of the first bar of the higher timeframe
else
first_period_time=period_time[0];
}
//--- A;8 2@5<O B5:CI53> 10@0 =0 B5:CI5< B09<D@59<5
// @0=LH5, G5< 2@5<O ?5@2>3> 10@0 AB0@H53> B09<D@59<0
if(time[i]<first_period_time)
high_tf_time=first_period_time;
//--- =0G5 1C45< ?>;CG0BL 40==K5 ?>A;54=53> 10@0 AB0@H53> B09<D@59<0
// >B=>A8B5;L=> B5:CI53> 10@0 B5:CI53> B09<D@59<0
else
high_tf_time=time[i];
//--- 1=C;8< ?>A;54=NN >H81:C
ResetLastError();
//--- >;CG8< F5=C >B:@KB8O ?5@2>3> 10@0 AB0@H53> B09<D@59<0
for(int j=0; j<try; j++)
if(CopyOpen(Symbol(),timeframe_start_point,high_tf_time,1,period_open)==1)
{ ResetLastError(); break; }
//--- >;CG8< 2@5<O >B:@KB8O ?5@2>3> 10@0 AB0@H53> B09<D@59<0
for(int j=0; j<try; j++)
if(CopyTime(Symbol(),timeframe_start_point,high_tf_time,1,period_time)==1)
{ ResetLastError(); break; }
//--- A;8 =5 C40;>AL ?>;CG8BL F5=C/2@5<O, 2K945<
if(ArraySize(period_open)<1 || ArraySize(period_time)<1 || GetLastError()!=0)
return;
//--- A;8 2@5<O B5:CI53> B09<D@59<0 @0=LH5, G5< 2@5<O =0G0;0 ?5@2>3> ?5@8>40 8;8
// 2@5<O C:070==>3> ?5@8>40 =5@02=> B><C, GB> 2 ?0<OB8
if(time[i]<first_period_time || time_divergence!=period_time[0])
{
symbol_difference[s] =0.0; // 1=C;8< @07=8FC F5= A8<2>;>2
inverse_difference[s] =0.0; // 1=C;8< @07=8FC 8=25@A88
//--- 0?><=8< 2@5<O =0G0;0 @0AE>645=8O F5=
time_divergence=period_time[0];
//--- 0?><=8< C@>25=L =0G0;0 @0AE>645=8O F5=
level_divergence=period_open[0];
//--- #AB0=>28< 25@B8:0;L=CN ;8=8N 2 =0G0;5 ?5@8>40 @0AE>645=8O F5=
CreateVerticalLines(0,0,period_time[0],start_price_divergence+"_"+TimeToString(time_divergence),
2,STYLE_SOLID,clrWhite,false,false,true,TimeToString(time_divergence),"\n");
}
}
//--- A;8 2 @568<5 25@B8:0;L=>9 ;8=88 8
// 2@5<O 10@0 @0=LH5, G5< 2@5<O ;8=88
if(StartPriceDivergence==VERT_LINE && time[i]<time_divergence)
{
//--- 5@68< =C;52K5 7=0G5=8O @07=8FK
symbol_difference[s] =0.0;
inverse_difference[s] =0.0;
//--- A?>;L7C5< @50;L=K5 7=0G5=8O A8<2>;0
buffer_data[s].low[i] =rates[0].low;
buffer_data[s].open[i] =rates[0].open;
buffer_data[s].high[i] =rates[0].high;
buffer_data[s].close[i] =rates[0].close;
//--- #AB0=>28< F25B B5:CI5<C M;5<5=BC 8=48:0B>@=>3> 1CD5@0
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
}
//--- A;8 2 4@C38E @568<0E
else
{
//--- A;8 =C6=0 8=25@A8O 40==KE A8<2>;0
if(inverse[s])
{
//--- A;8 =0G0;AO =>2K9 ?5@8>4, ?5@5AG8B05< ?5@5<5==K5 4;O @0AGQB0
if(symbol_difference[s]==0.0)
{
//--- A;8 @568< 25@B8:0;L=>9 ;8=88
if(StartPriceDivergence==VERT_LINE)
{
//--- 0AAG8B05< @07=8FC
symbol_difference[s] =rates[0].open-on_calc_open[i];
inverse_difference[s] =on_calc_open[i]-(-on_calc_open[i]);
}
//--- ;O 4@C38E @568<>2
else
{
//--- 0AAG8B05< @07=8FC
symbol_difference[s] =rates[0].open-level_divergence;
inverse_difference[s] =level_divergence-(-level_divergence);
}
}
//--- ;O @568<0 8=8O B>;L:> F5=0 70:@KB8O
if(DrawType==LINES)
buffer_data[s].close[i]=-(rates[0].close-symbol_difference[s])+inverse_difference[s];
//--- ;O 4@C38E @568<>2 2A5 F5=K
else
{
buffer_data[s].low[i] =-(rates[0].low-symbol_difference[s])+inverse_difference[s];
buffer_data[s].open[i] =-(rates[0].open-symbol_difference[s])+inverse_difference[s];
buffer_data[s].high[i] =-(rates[0].high-symbol_difference[s])+inverse_difference[s];
buffer_data[s].close[i] =-(rates[0].close-symbol_difference[s])+inverse_difference[s];
//--- #AB0=>28< F25B B5:CI5<C M;5<5=BC 8=48:0B>@=>3> 1CD5@0
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
}
}
//--- A;8 157 8=25@A88, B> 2 =0G0;5 ?5@8>40
// =C6=> 2KG8B0BL B>;L:> @07=8FC <564C F5=0<8 A8<2>;>2
else
{
//--- A;8 =0G0;AO =>2K9 ?5@8>4
if(symbol_difference[s]==0.0)
{
//--- A;8 @568< 25@B8:0;L=>9 ;8=88
if(StartPriceDivergence==VERT_LINE)
symbol_difference[s]=rates[0].open-on_calc_open[i];
//--- ;O 4@C38E @568<>2
else
symbol_difference[s]=rates[0].open-level_divergence;
}
//--- ;O @568<0 >B@8A>2:8 8=8O B>;L:> F5=0 >B:@KB8O
if(DrawType==LINES)
buffer_data[s].close[i]=rates[0].close-symbol_difference[s];
//--- ;O 4@C38E @568<>2 >B@8A>2:8 2A5 F5=K
else
{
buffer_data[s].low[i] =rates[0].low-symbol_difference[s];
buffer_data[s].open[i] =rates[0].open-symbol_difference[s];
buffer_data[s].high[i] =rates[0].high-symbol_difference[s];
buffer_data[s].close[i] =rates[0].close-symbol_difference[s];
//--- #AB0=>28< F25B B5:CI5<C M;5<5=BC 8=48:0B>@=>3> 1CD5@0
SetColorsIndicatorSeries(i,s,rates[0].close,rates[0].open);
}
}
}
//--- >=B@>;L=0O ?@>25@:0 @0AAG8B0==KE 7=0G5=89
// ;O @568<0 8=8O B>;L:> F5=0 >B:@KB8O
if(DrawType==LINES)
{
//--- A;8 B5:CI55 2@5<O @0=LH5, G5< 2@5<O ?5@2>3> ?5@8>40 8;8
// 2@5<O 10@0 =5@02=> 2@5<5=8 10@0 B5:CI53> A8<2>;0, 70?8H5< ?CAB>5 7=0G5=85
if(time[i]!=rates[0].time || time[i]<first_period_time)
buffer_data[s].close[i]=EMPTY_VALUE;
}
//--- ;O 4@C38E @568<>2 2A5 F5=K
else
{
//--- A;8 B5:CI55 2@5<O @0=LH5, G5< 2@5<O ?5@2>3> ?5@8>40 8;8
// 2@5<O 10@0 =5@02=> 2@5<5=8 10@0 B5:CI53> A8<2>;0
if(time[i]!=rates[0].time || time[i]<first_period_time)
{
//--- 0?8H5< ?CAB>5 7=0G5=85
buffer_data[s].low[i] =EMPTY_VALUE;
buffer_data[s].open[i] =EMPTY_VALUE;
buffer_data[s].high[i] =EMPTY_VALUE;
buffer_data[s].close[i] =EMPTY_VALUE;
}
}
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B F25B M;5<5=BC 1CD5@0 ?> CA;>28N |
//+------------------------------------------------------------------+
void SetColorsIndicatorSeries(int i,int symbol_number,double close,double open)
{
//--- A;8 2:;NG5= 42CEF25B=K9 @568<, ?@>25@8< CA;>285
if(TwoColor)
{
//--- A;8 F5=0 70:@KB8O 1>;LH5 F5=K >B:@KB8O, B>
// MB> 10@ 225@E 8 8A?>;L7C5< ?5@2K9 F25B
if(close>open)
buffer_data[symbol_number].icolor[i]=0;
//--- 8=0G5 MB> 10@ 2=87 8 8A?>;L7C5< 2B>@>9 F25B
else
buffer_data[symbol_number].icolor[i]=1;
}
//--- A;8 >4=>F25B=K9 @568<, B> 8A?>;L7C5< 4;O 2A5E 10@>2/A25G59 ?5@2K9 F25B
else
buffer_data[symbol_number].icolor[i]=0;
}
//+------------------------------------------------------------------+
//| >?8@C5B 40==K5 87 OnCalculate |
//+------------------------------------------------------------------+
void CopyDataOnCalculate(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[])
{
on_calc_rates_total=rates_total;
on_calc_prev_calculated=prev_calculated;
ArrayCopy(on_calc_time,time);
ArrayCopy(on_calc_open,open);
ArrayCopy(on_calc_high,high);
ArrayCopy(on_calc_low,low);
ArrayCopy(on_calc_close,close);
ArrayCopy(on_calc_tick_volume,tick_volume);
ArrayCopy(on_calc_volume,volume);
ArrayCopy(on_calc_spread,spread);
}
//+------------------------------------------------------------------+
//| 1=C;5=85 8=48:0B>@=KE 1CD5@>2 |
//+------------------------------------------------------------------+
void ZeroIndicatorBuffers()
{
for(int s=0; s<SYMBOLS; s++)
{
ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].high,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].low,EMPTY_VALUE);
ArrayInitialize(buffer_data[s].close,EMPTY_VALUE);
}
}
//+------------------------------------------------------------------+
//| @5>1@07C5B B09<D@59< 2 AB@>:C |
//+------------------------------------------------------------------+
string TimeframeToString(ENUM_TIMEFRAMES timeframe)
{
string str="";
//--- A;8 ?5@540==>5 7=0G5=85 =5:>@@5:B=>, 15@5< B09<D@59< B5:CI53> 3@0D8:0
if(timeframe==WRONG_VALUE || timeframe==NULL)
timeframe=Period();
switch(timeframe)
{
case PERIOD_M1 : str="M1"; break;
case PERIOD_M2 : str="M2"; break;
case PERIOD_M3 : str="M3"; break;
case PERIOD_M4 : str="M4"; break;
case PERIOD_M5 : str="M5"; break;
case PERIOD_M6 : str="M6"; break;
case PERIOD_M10 : str="M10"; break;
case PERIOD_M12 : str="M12"; break;
case PERIOD_M15 : str="M15"; break;
case PERIOD_M20 : str="M20"; break;
case PERIOD_M30 : str="M30"; break;
case PERIOD_H1 : str="H1"; break;
case PERIOD_H2 : str="H2"; break;
case PERIOD_H3 : str="H3"; break;
case PERIOD_H4 : str="H4"; break;
case PERIOD_H6 : str="H6"; break;
case PERIOD_H8 : str="H8"; break;
case PERIOD_H12 : str="H12"; break;
case PERIOD_D1 : str="D1"; break;
case PERIOD_W1 : str="W1"; break;
case PERIOD_MN1 : str="MN1"; break;
}
//---
return(str);
}
//+------------------------------------------------------------------+