SymbolsInformer/SymbolsInformer.mq5

541 lines
40 KiB
MQL5
Raw Permalink Normal View History

2025-06-01 14:18:42 +03:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| SymbolsInformer.mq5 |
//| Copyright 2025, Yuriy Bykov |
//| https://www.mql5.com/ru/users/antekov |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Yuriy Bykov"
#property link "https://www.mql5.com/ru/articles/17883"
#property description "=D>@<0F8O > ?>2545=88 F5=."
#property version "1.01"
// >;8G5AB2> ACI5AB2CNI8E B09<D@59<>2
#define TFN (21)
// 81;8>B5:0 >1=0@C65=8O 2>7=8:=>25=8O =>2>3> 10@0
#include "Include/Adwizard/Utils/NewBarEvent.mqh"
#include "ConsoleDialog.mqh"
//+------------------------------------------------------------------+
//| E>4=K5 ?0@0<5B@K |
//+------------------------------------------------------------------+
input group "::: 5@8>4 4;O @0AGQB>2"
sinput ENUM_TIMEFRAMES mainTimeframe_ = PERIOD_D1; // A=>2=>9 B09<D@59<
input int mainLength_ = 30; // >;8G5AB2> A25G59 >A=>2=>3> B09<D@59<0
input group "::: !8<2>;K 8 B09<D@59<K"
sinput string symbols_ = "EURUSD,GBPUSD,EURGBP"; // !8<2>;K (G5@57 70?OBCN)
sinput string timeframes_ = "M5,M15,M30,H1,H4"; // "09<D@59<K (=0?@. M5,H1,H4)
// ;>10;L=K5 ?5@5<5==K5
string g_symbols[]; // 0AA82 2A5E 8A?>;L7C5<KE A8<2>;>2
ENUM_TIMEFRAMES g_timeframes[]; // 0AA82 2A5E 8A?>;L7C5<KE B09<D@59<>2
// 0AA82K @0AGQB=KE 7=0G5=89.
// 5@2K9 8=45:A - A8<2>;, 2B>@>9 8=45:A - B09<D@59<
double symbolAvrCandleSizes[][TFN]; // 0AA82 A@54=8E @07<5@>2 2A5E A25G59
double symbolAvrBuyCandleSizes[][TFN]; // 0AA82 A@54=8E @07<5@>2 A25G59 225@E
double symbolAvrSellCandleSizes[][TFN]; // 0AA82 A@54=8E @07<5@>2 A25G59 2=87
double symbolAvrSeriesLength[][TFN]; // 0AA82 A@54=8E 4;8= A5@89
int symbolCountSeries2[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 2
int symbolCountSeries3[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 3
int symbolCountSeries4[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 4
int symbolCountSeries5[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 5
int symbolCountSeries6[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 6
int symbolCountSeries7[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 7
int symbolCountSeries8[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 8
int symbolCountSeries9[][TFN]; // 0AA82 :>;8G5AB20 A5@89 4;8=K 9
CConsoleDialog *dialog; // 80;>3 4;O 2K2>40 B5:AB0 A @57C;LB0B0<8
// 0AA82 2A5E B09<D@59<>2
ENUM_TIMEFRAMES tfValues[] = {
PERIOD_M1, PERIOD_M2, PERIOD_M3, PERIOD_M4, PERIOD_M5, PERIOD_M6,
PERIOD_M10, PERIOD_M12, PERIOD_M15, PERIOD_M20, PERIOD_M30,
PERIOD_H1, PERIOD_H2, PERIOD_H3, PERIOD_H4, PERIOD_H6,
PERIOD_H8, PERIOD_H12, PERIOD_D1, PERIOD_W1, PERIOD_MN1
};
//+------------------------------------------------------------------+
//| @5>1@07>20=85 AB@>:>2>3> =0720=8O 2 B09<D@59< |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES StringToTimeframe(string s) {
// A;8 2 AB@>:5 5ABL A8<2>; "_", B> >AB02;O5< B>;L:> A8<2>;K, 84CI85 ?>A;5 =53>
int pos = StringFind(s, "_");
if(pos != -1) {
s = StringSubstr(s, pos + 1);
}
// 5@52>48< 2 25@E=89 @538AB@
StringToUpper(s);
// 0AA82K A>>B25BAB2CNI8E AB@>:>2KE =0720=89 B09<D@59<>2
string keys[] = {"M1", "M2", "M3", "M4", "M5", "M6", "M10", "M12", "M15", "M20", "M30",
"H1", "H2", "H3", "H4", "H6", "H8", "H12", "D1", "W1", "MN1"
};
// I5< A>>B25BAB285 8 2>72@0I05<, 5A;8 =0H;8
FOREACH(keys) {
if(keys[i] == s)
return tfValues[i];
}
return PERIOD_CURRENT;
}
//+------------------------------------------------------------------+
//| @5>1@07>20=85 B09<D@59<0 2 AB@>:>2>5 =0720=85 |
//+------------------------------------------------------------------+
string TimeframeToString(ENUM_TIMEFRAMES tf) {
// >;CG05< =0720=85 B09<D@59<0 2840 'PERIOD_*'
string s = EnumToString(tf);
// >72@0I05< G0ABL =0720=8O ?>A;5 A8<2>;0 '_'
return StringSubstr(s, StringFind(s, "_") + 1);
}
//+------------------------------------------------------------------+
//| @5>1@07>20=85 B09<D@59<0 2 8=45:A 2 <0AA825 2A5E B09<D@59<>2 |
//+------------------------------------------------------------------+
int TimeframeToIndex(ENUM_TIMEFRAMES tf) {
// I5< A>>B25BAB285 8 2>72@0I05<, 5A;8 =0H;8
FOREACH(tfValues) {
if(tfValues[i] == tf)
return i;
}
return WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| =8F80;870F8O A>25B=8:0 |
//+------------------------------------------------------------------+
int OnInit(void) {
// 0?>;=O5< <0AA82 A8<2>;>2 4;O @0AGQB>2 87 2E>4=KE ?0@0<5B@>2
SPLIT(symbols_, g_symbols);
// A;8 A8<2>;K =5 C:070=K, 8A?>;L7C5< >48= B5:CI89 A8<2>;
if(ArraySize(g_symbols) == 0) {
APPEND(g_symbols, Symbol());
}
// >;8G5AB2> A8<2>;>2 4;O @0AGQB>2
int nSymbols = ArraySize(g_symbols);
// =8F80;878@C5< <0AA82K 4;O @0AGQB=KE 7=0G5=89
Initialize(nSymbols);
// 0?>;=O5< <0AA82 =0720=89 B09<D@59<>2 87 2E>4=KE ?0@0<5B@>2
string strTimeframes[];
SPLIT(timeframes_, strTimeframes);
ArrayResize(g_timeframes, 0);
// A;8 B09<D@59<K =5 C:070=K, 8A?>;L7C5< >48= B5:CI89 B09<D@59<
if(ArraySize(strTimeframes) == 0) {
APPEND(strTimeframes, TimeframeToString(Period()));
}
// 0?>;=O5< <0AA82 B09<D@59<>2 87 <0AA820 =0720=89 B09<D@59<>2
FOREACH(strTimeframes) {
ENUM_TIMEFRAMES tf = StringToTimeframe(strTimeframes[i]);
if(tf != PERIOD_CURRENT) {
APPEND(g_timeframes, tf);
}
}
// !>740Q< 8 70?CA:05< 480;>3 4;O 2K2>40 @57C;LB0B>2
dialog = new CConsoleDialog();
dialog.Create("Symbols Informer");
dialog.Run();
// K?>;=O5< ?@8=C48B5;L=K9 ?5@5@0AGQB
Calculate(true);
// >:07K205< @57C;LB0BK
Show();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
if(!!dialog) {
dialog.Destroy();
delete dialog;
}
ChartRedraw();
DestroyNewBar(); // 5=8F80;870F8O >1J5:B>2 >BA;56820=8O =>2>3> 10@0
}
//+------------------------------------------------------------------+
//| 1@01>B:0 A>1KB89 |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // event ID
const long & lparam, // event parameter of the long type
const double & dparam, // event parameter of the double type
const string & sparam) { // event parameter of the string type
if(!!dialog) {
dialog.ChartEvent(id, lparam, dparam, sparam);
}
}
//+------------------------------------------------------------------+
//| Expert OnTick function |
//+------------------------------------------------------------------+
void OnTick(void) {
// ?@545;O5< =>2K9 10@ ?> 2A5< =C6=K< A8<2>;0< 8 B09<D@59<0<
bool isNewBar = UpdateNewBar();
// A;8 =>2>3> 10@0 =8345 =5B, B> =8G53> =5 45;05<
if(!isNewBar) return;
// =0G5 2K?>;=O5< ?5@5@0AGQB 8 ?>:07K205< @57C;LB0BK
Calculate();
Show();
}
//+------------------------------------------------------------------+
//| =8=F80;870F8O <0AA82>2 4;O @0AGQB=KE 7=0G5=89 |
//+------------------------------------------------------------------+
void Initialize(int nSymbols) {
// #AB0=02;8205< @07<5@K 2A5E <0AA82>2
ArrayResize(symbolAvrCandleSizes, nSymbols);
ArrayResize(symbolAvrBuyCandleSizes, nSymbols);
ArrayResize(symbolAvrSellCandleSizes, nSymbols);
ArrayResize(symbolAvrSeriesLength, nSymbols);
ArrayResize(symbolCountSeries2, nSymbols);
ArrayResize(symbolCountSeries3, nSymbols);
ArrayResize(symbolCountSeries4, nSymbols);
ArrayResize(symbolCountSeries5, nSymbols);
ArrayResize(symbolCountSeries6, nSymbols);
ArrayResize(symbolCountSeries7, nSymbols);
ArrayResize(symbolCountSeries8, nSymbols);
ArrayResize(symbolCountSeries9, nSymbols);
// 0?>;=O5< =0G0;L=K<8 7=0G5=8O<8 2A5 M;5<5=BK 2A5E <0AA82>2
FOREACH(symbolAvrCandleSizes) {
ArrayInitialize(symbolAvrCandleSizes, 0);
ArrayInitialize(symbolAvrBuyCandleSizes, 0);
ArrayInitialize(symbolAvrSellCandleSizes, 0);
ArrayInitialize(symbolAvrSeriesLength, 0);
ArrayInitialize(symbolCountSeries2, 0);
ArrayInitialize(symbolCountSeries3, 0);
ArrayInitialize(symbolCountSeries4, 0);
ArrayInitialize(symbolCountSeries5, 0);
ArrayInitialize(symbolCountSeries6, 0);
ArrayInitialize(symbolCountSeries7, 0);
ArrayInitialize(symbolCountSeries8, 0);
ArrayInitialize(symbolCountSeries9, 0);
}
}
//+------------------------------------------------------------------+
//| 0AGQB 2A5E 25;8G8= |
//+------------------------------------------------------------------+
void Calculate(bool force = false) {
string symbol;
ENUM_TIMEFRAMES tf;
// ;O :064>3> A8<2>;0 8 B09<D@59<0
FOREACH_AS(g_symbols, symbol) {
FOREACH_AS(g_timeframes, tf) {
// A;8 4;O 40==>3> A8<2>;0 8 B09<D@59<0 =0ABC?8; =>2K9 10@, B>
if(IsNewBar(symbol, tf) || force) {
// 0E>48< :>;8G5AB2> A25G59 4;O @0AGQB0
int n = PeriodSeconds(mainTimeframe_) * mainLength_ / PeriodSeconds(tf);
// 0AAG8BK205< A@54=85 @07<5@K A25G59
CalculateAvrSizes(symbol, tf, n);
// 0AAG8BK205< 4;8=K A5@89 A25G59
CalculateSeries(symbol, tf, n);
}
}
}
}
//+------------------------------------------------------------------+
//| !25G0 225@E? |
//+------------------------------------------------------------------+
bool IsBuyRate(const MqlRates &rate) {
return rate.open <= rate.close;
}
//+------------------------------------------------------------------+
//| !25G0 2=87? |
//+------------------------------------------------------------------+
bool IsSellRate(const MqlRates &rate) {
return rate.open >= rate.close;
}
//+------------------------------------------------------------------+
//| 0AGQB A@54=8E @07<5@>2 A25G59 |
//+------------------------------------------------------------------+
void CalculateAvrSizes(string symbol, ENUM_TIMEFRAMES tf, int n) {
// 0E>48< 8=45:A, :>B>@K9 8A?>;L7C5BAO 4;O =C6=>3> A8<2>;0
int s;
FIND(g_symbols, symbol, s);
// 0E>48< 8=45:A, :>B>@K9 8A?>;L7C5BAO 4;O =C6=>3> B09<D@59<0
int t = TimeframeToIndex(tf);
// 0AA82 4;O A25G59
MqlRates rates[];
// >?8@C5< =C6=>5 :>;8G5AB2> A25G59 2 <0AA82
int res = CopyRates(symbol, tf, 1, n, rates);
// A;8 2AQ A:>?8@>20;>AL, B>
if(res == n) {
// >;8G5AB2> A25G59 225@E 8 2=87
int nBuy = 0, nSell = 0;
// 1=C;O5< M;5<5=BK 4;O @0AGQB=KE A@54=8E 7=0G5=89
symbolAvrCandleSizes[s][t] = 0;
symbolAvrBuyCandleSizes[s][t] = 0;
symbolAvrSellCandleSizes[s][t] = 0;
// ;O 2A5E A25G59
FOREACH(rates) {
// 0E>48< @07<5@ A25G8
double size = rates[i].high - rates[i].low;
// >102;O5< 53> 2 AC<<0@=K9 @07<5@ 2A5E A25G59
symbolAvrCandleSizes[s][t] += size;
// A;8 MB> A25G0 225@E, B> CG8BK205< 5Q
if(IsBuyRate(rates[i])) {
symbolAvrBuyCandleSizes[s][t] += size;
nBuy++;
}
// A;8 MB> A25G0 2=87, B> CG8BK205< 5Q
if(IsSellRate(rates[i])) {
symbolAvrSellCandleSizes[s][t] += size;
nSell++;
}
}
// >;CG05< @07<5@ >4=>3> ?C=:B0 4;O A8<2>;0
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// 0E>48< A@54=85 7=0G5=8O 2 ?C=:B0E
symbolAvrCandleSizes[s][t] /= n * point;
symbolAvrBuyCandleSizes[s][t] /= nBuy * point;
symbolAvrSellCandleSizes[s][t] /= nSell * point;
// :@C3;O5< 8E 4> F5;KE ?C=:B>2
symbolAvrCandleSizes[s][t] = MathRound(symbolAvrCandleSizes[s][t]);
symbolAvrBuyCandleSizes[s][t] = MathRound(symbolAvrBuyCandleSizes[s][t]);
symbolAvrSellCandleSizes[s][t] = MathRound(symbolAvrSellCandleSizes[s][t]);
}
}
//+------------------------------------------------------------------+
//| 0AGQB 4;8= A5@89 A25G59 |
//+------------------------------------------------------------------+
void CalculateSeries(string symbol, ENUM_TIMEFRAMES tf, int n) {
// 0E>48< 8=45:A, :>B>@K9 8A?>;L7C5BAO 4;O =C6=>3> A8<2>;0
int s;
FIND(g_symbols, symbol, s);
// 0E>48< 8=45:A, :>B>@K9 8A?>;L7C5BAO 4;O =C6=>3> B09<D@59<0
int t = TimeframeToIndex(tf);
// 0AA82 4;O A25G59
MqlRates rates[];
// >?8@C5< =C6=>5 :>;8G5AB2> A25G59 2 <0AA82
int res = CopyRates(symbol, tf, 1, n, rates);
// A;8 2AQ A:>?8@>20;>AL, B>
if(res == n) {
// "5:CI0O 4;8=0 A5@88
int curLen = 0;
// 0?@02;5=85 ?@54K4CI59 A25G8
bool prevIsBuy = false;
bool prevIsSell = false;
// 0AA82 :>;8G5AB2 A5@89 @07=>9 4;8=K (8=45:A = 4;8=0 A5@88)
int seriesLens[];
// #AB0=02;8205< @07<5@ 8 8=8F80;878@C5<
ArrayResize(seriesLens, 100);
ArrayInitialize(seriesLens, 0);
// ;O 2A5E A25G59
FOREACH(rates) {
// ?@545;O5< =0?@02;5=85 A25G8
bool isBuy = IsBuyRate(rates[i]);
bool isSell = IsSellRate(rates[i]);
// A;8 =0?@02;5=85 A>2?0405B A ?@54K4CI8<, B>
if((isBuy && prevIsBuy) || (isSell && prevIsSell)) {
// #25;8G8205< 4;8=C A5@88
curLen++;
} else {
// =0G5 5A;8 4;8=0 ?>?0405B 2 B@51C5<K9 480?07>=, B>
if(curLen > 1 && curLen < 100) {
// #25;8G825< AGQBG8: A5@89 MB>9 4;8=K
seriesLens[curLen]++;
}
// !1@0AK205< B5:CICN 4;8=C A5@88
curLen = 1;
}
// 0?><8=05< =0?@02;5=85 B5:CI59 A25G8 :0: ?@54K4CI55
prevIsBuy = isBuy;
prevIsSell = isSell;
}
// =8F80;878@C5< M;5<5=B <0AA820 4;O A@54=59 4;8=K A5@88
symbolAvrSeriesLength[s][t] = 0;
int count = 0;
// ;O 2A5E 4;8= A5@89 =0E>48< AC<<C 8 :>;8G5AB2>
FOREACH(seriesLens) {
symbolAvrSeriesLength[s][t] += seriesLens[i] * i;
count += seriesLens[i];
}
// KG8A;O5< A@54=NN 4;8=C A5@89 A25G59
symbolAvrSeriesLength[s][t] /= (count > 0 ? count : 1);
// >?8@C5< 7=0G5=8O 4;8= A5@89 2 8B>3>2K5 <0AA82K
symbolCountSeries2[s][t] = seriesLens[2];
symbolCountSeries3[s][t] = seriesLens[3];
symbolCountSeries4[s][t] = seriesLens[4];
symbolCountSeries5[s][t] = seriesLens[5];
symbolCountSeries6[s][t] = seriesLens[6];
symbolCountSeries7[s][t] = seriesLens[7];
symbolCountSeries8[s][t] = seriesLens[8];
symbolCountSeries9[s][t] = seriesLens[9];
}
}
//+------------------------------------------------------------------+
//| >;CG5=85 2A5E @57C;LB0B>2 2 2845 B5:AB0 |
//+------------------------------------------------------------------+
string TextComment() {
string text = "";
text += StringFormat("%-20s |", ""09<D@59<K");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10s |", TimeframeToString(g_timeframes[i]));
}
text += StringFormat("\n%20s |", ">;-2> A25G59");
FOREACH(g_timeframes) {
int n = PeriodSeconds(mainTimeframe_) * mainLength_ / PeriodSeconds(g_timeframes[i]);
text += StringFormat("%10.0f |", n);
}
FOREACH(g_symbols) {
int s = i;
text += StringFormat("\n======================================================================", g_symbols[i]);
text += StringFormat("\n%-20s |", g_symbols[i]);
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10s |", TimeframeToString(g_timeframes[i]));
}
text += StringFormat("\n%20s", "!@54=89 @07<5@ A25G59 2 ?C=:B0E");
text += StringFormat("\n%20s |", "A5");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolAvrCandleSizes[s][t]);
}
text += StringFormat("\n%20s |", "Buy");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolAvrBuyCandleSizes[s][t]);
}
text += StringFormat("\n%20s |", "Sell");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolAvrSellCandleSizes[s][t]);
}
text += StringFormat("\n%-20s |", "!@54=OO 4;8=0 A5@88");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.2f |", symbolAvrSeriesLength[s][t]);
}
text += StringFormat("\n--------------------------------------------------------------------", g_symbols[i]);
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 2");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries2[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 3");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries3[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 4");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries4[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 5");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries5[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 6");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries6[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 7");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries7[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 8");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries8[s][t]);
}
text += StringFormat("\n%-20s |", ">;-2> A5@89 4;8=K 9");
FOREACH(g_timeframes) {
int t = TimeframeToIndex(g_timeframes[i]);
text += StringFormat("%10.0f |", symbolCountSeries9[s][t]);
}
}
text = StringFormat("A=>2=>9 B09<D@59<: %s (%d A25G59)\n%s",
TimeframeToString(mainTimeframe_), mainLength_,
text);
return text;
}
//+------------------------------------------------------------------+
//| >:07 @57C;LB0B>2 |
//+------------------------------------------------------------------+
void Show() {
// >;CG05< @57C;LB0BK 2 2845 B5:AB0
string text = TextComment();
// >:07K205< 53> =0 3@0D8:5 2 480;>3>2>< >:=5
dialog.Text(text);
}
//+------------------------------------------------------------------+