Español Português
preview
От начального к среднему уровню: Подокна (II)

От начального к среднему уровню: Подокна (II)

MetaTrader 5 — Примеры |
63 0
CODE X
CODE X

Введение

В предыдущей статье От начального к среднему уровню: Подокна (I) мы начали говорить о подокнах. Хотя это было лишь краткое введение, то, что мы там увидели, крайне важно для понимания того, что будет дальше. Какой бы простой ни казалась эта вводная часть, не думайте, что вы уже умеете работать с подокнами только потому, что можете делать с ними несколько простых вещей. Подокна дают очень интересные возможности, и, если вы хорошо спланируете их использование в своём коде, сможете реализовать решения, которые в противном случае были бы невозможны или, по крайней мере, не так просты в реализации.

Ну что ж, не хочу слишком долго на этом останавливаться, прежде чем перейти к основной теме, так что продолжим наш обычный порядок. Пора отложить в сторону всё, что отвлекает, и сосредоточиться на том, что я собираюсь объяснить. Итак, перейдём к делу.


Подокна (II)

Одно из первых, что пытаются сделать многие начинающие программисты, — создать советник для торговли на рынке. При этом они обычно добавляют множество элементов управления. В результате график оказывается перегружен объектами, которые лучше было бы разместить в другом месте — в подокне. Тогда основной график останется незагромождённым, и мы сможем ясно видеть, что происходит на каждом его баре.

Итак, размещение элементов управления в подокне — хорошая идея. Однако есть одно условие:

ПОДОКНА МОЖНО СОЗДАВАТЬ ТОЛЬКО С ПОМОЩЬЮ ИНДИКАТОРА.

Здесь всё начинает усложняться, особенно если у вас ещё нет опыта в реализации подобных решений. Позже я ясно и просто объясню, как это сделать. Пока что прошу вас, дорогой читатель, набраться терпения, ведь мы только начинаем изучать подокна. Я хотел привести этот пример, чтобы побудить вас внимательно изучить эти статьи. Возможно, кому-то это покажется пустой тратой времени, но каждый пункт, который мы рассмотрим, будет важен для понимания последующих статей.

Давайте для начала подробнее рассмотрим вопрос, который мы затронули в предыдущей статье: как ваш индикатор рассчитывает кривую, которая будет отображаться в подокне. Опять об этом? Думаю, я уже понял, как заставить мой индикатор правильно выполнять расчёт. Ах да, дорогой читатель? Вы действительно знаете, как это делать?

Думаю, мало кто умеет это делать. Не потому, что я считаю себя гением, а потому, что видел, что делают другие программисты. Чтобы объяснить это как можно проще, мы воспользуемся одним из кодов из предыдущей статьи. На этот раз мы упростим пример до ещё более простого расчёта: чем больше элементов в коде, тем сложнее его объяснить и понять. Ниже приведён код, который мы будем использовать.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. const struct stAverange
07. {
08.     int            nPeriods;
09.     ENUM_MA_METHOD Method;
10.     color          cor;
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrBlack}
14. };
15. //+----------------+
16. #property indicator_chart_window
17. #property indicator_applied_price   PRICE_CLOSE
18. #property indicator_buffers         Averange.Size();
19. #property indicator_plots           Averange.Size();
20. //+------------------------------------------------------------------+
21. struct stInfos
22. {
23.     double  Buff[];
24. }Infos[Averange.Size()];
25. //+------------------------------------------------------------------+
26. int OnInit(void)
27. {
28.     for (uint c = 0; c < Averange.Size(); c++)
29.     {
30.         SetIndexBuffer(c, Infos[c].Buff, INDICATOR_DATA);
31.         PlotIndexSetInteger(c, PLOT_DRAW_TYPE, DRAW_LINE);
32.         PlotIndexSetInteger(c, PLOT_LINE_STYLE, STYLE_SOLID);
33.         PlotIndexSetInteger(c, PLOT_LINE_WIDTH, 2);
34.         PlotIndexSetInteger(c, PLOT_LINE_COLOR, Averange[c].cor);
35.         PlotIndexSetString(c, PLOT_LABEL, StringFormat("Arithmetic of %d", Averange[c].nPeriods));
36.     }
37. 
38.        return INIT_SUCCEEDED;
39. };
40. //+------------------------------------------------------------------+
41. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
42. {
43. 
44.     for (uint c = 0; c < Averange.Size(); c++)
45.     {
46.         if (prev_calculated == 0)
47.         {
48.             double loc = 0;
49.             for (int c1 = 0; c1 < Averange[c].nPeriods; c1++) loc += price[Averange[c].nPeriods - c1];
50.                 Infos[c].Buff[Averange[c].nPeriods] = loc / Averange[c].nPeriods;
51.         }
52.         switch (Averange[c].Method)
53.         {
54.             case MODE_SMA:
55.                 for (int i = (prev_calculated > 0 ? prev_calculated - 1 : Averange[c].nPeriods + 1); i < rates_total; i++)
56.                     Infos[c].Buff[i] = ((Infos[c].Buff[i - 1] * Averange[c].nPeriods) - price[i - Averange[c].nPeriods] + price[i]) / Averange[c].nPeriods;
57.                 break;
58.         }
59.     }
60. 
61.     return rates_total;
62. };
63. //+------------------------------------------------------------------+

Код 01

Благодаря строке 13 код 01 правильно вычисляет среднее арифметическое, которое мы хотим построить. Но знаете ли вы, в каком направлении выполняется расчёт? На следующем рисунке показаны полученная средняя и направление расчёта.

Изображение 01


Стрелка на изображении 01 указывает направление расчёта; чёрная линия представляет вычисленное среднее. Почему важно это знать? Возможно, вы думаете, что на практике это не имеет никакого значения. И, дорогой читатель, в большинстве случаев неважно, в каком направлении выполнять расчёты. Однако в программировании нельзя руководствоваться только здравым смыслом. Программисты реализуют то, что от них требуется, независимо от того, что подсказывает здравый смысл. Их код должен давать ожидаемый результат; как они этого добиваются — вторично.

Однако в программировании 2 + 3 может отличаться от 3 + 2. Как это возможно? В статьях, посвящённых перегрузке операторов, я показал, что операции не всегда работают так, как многие себе представляют. Поэтому в зависимости от того, что вы пытаетесь сделать, вычисление может работать в одном направлении, тогда как в другом код может дать сбой. Код 01 — хороший тому пример.

Чтобы приступить к его изучению, добавим индикатор объёма, как показано ниже.

Изображение 02

Теперь мы добавим индикатор из кода 01 к индикатору объёма. Таким образом, мы сможем увидеть среднее значение объёма за последние 20 периодов. Мы сделаем это так, как показано в следующей анимации.

Анимация 01


Как и следовало ожидать, всё сработало. Однако это не означает, что код 01 подходит для любой ситуации. Теперь рассмотрим случай, в котором это не даст нужного результата. Для этого мы удалим индикатор объёма и добавим индикатор другого типа. Но сначала, дорогой читатель, я хочу вам кое-что показать. На следующем изображении показаны эти параметры.

Изображение 03


Обратите внимание, что на изображении 03 есть два индикатора, использующих код 01. Имейте это в виду, потому что эта деталь очень пригодится нам позже. Теперь мы добавим ещё один индикатор, как показано в следующей анимации.

Анимация 02

Здесь неважно, почему я выбрал этот индикатор: я выбрал его наугад из доступных. Если хотите, потом можете попробовать другой. Сейчас нам нужно вычислить вторую среднюю на основе значений индикатора в подокне, чтобы сгладить зелёную среднюю, которую он строит. Для этого мы будем использовать индикатор с кодом 01. Вам нужно будет добавить его так, как мы уже знаем. После построения появится второе среднее значение: среднее арифметическое последних двадцати значений, ранее вычисленных индикатором подокна.

Давайте сделаем то, что показано в следующей анимации.

Анимация 03

Но что произошло? Где индикатор? Неужели произошёл какой-то катастрофический сбой и он исчез с графика? Ммм, не понимаю. Ну что ж, дорогой читатель, теперь вы начинаете понимать, что всё не так просто, как вам казалось, верно? Посмотрим, что произошло. Сначала проверим, нет ли в терминале сообщений, указывающих на возможный сбой.

Изображение 04

Как показано на изображении 04, ни о каких сбоях не сообщалось. Попробуем выяснить, что произошло, другим способом: обратимся к списку индикаторов. Там мы увидим то, что показано на следующем изображении.

Изображение 05

Хм, как странно. На изображении 05 видно, что индикатор есть в списке на своём месте, хотя на графике он не отображается. Ладно, сдаюсь. Думаю, займусь чем-нибудь другим. Определённо, программирование — не для меня. Не волнуйтесь, дорогой читатель. Помните, что цель этих статей — научить вас достигать своих целей. Для этого вам нужно понять, как выявлять сбои и ошибки, на которые указывает поведение вашего кода. Если вы внимательно посмотрите анимацию 03, то заметите кое-что на графике. Чтобы лучше это рассмотреть, мы остановим анимацию на одном кадре и спокойно изучим эту деталь.

Изображение 06

Обратите внимание на точку, которую я выделил на изображении. Выделенное значение должно быть другим. Означает ли это, что мы не можем вычислить среднее по значениям с помощью индикатора, подобного тому, что показан на рисунке 06? Давайте проведём ещё один эксперимент, чтобы ответить на этот вопрос. Помните, что Код 01 рассчитывает среднее арифметическое за двадцать периодов. Теперь мы воспользуемся другим индикатором, встроенным в MetaTrader 5 по умолчанию, чтобы проверить, связана ли проблема с нашим индикатором или есть другая причина, по которой он не отображается на графике. Следующая анимация показывает этот тест.

Анимация 04

Как любопытно! Оказывается, всё-таки работает. Значит, ошибка в нашем коде. Именно так, дорогой читатель. Что ж, теперь я не знаю, как это исправить: в отличие от того, что мы видели в предыдущей статье, где мы просили MetaTrader 5 выполнить расчёт, на этот раз мы делаем это сами, и всё же индикатор даёт сбой. Почему?

Причина кроется в направлении расчёта, как мы видели на рисунке 01. Код 01 выполняет расчёт от самых старых данных к самым новым. Возможно, в какой-то момент эти данные обрабатываются некорректно, из-за чего индикатор даёт сбой и среднее не строится. Это происходит потому, что индикатор содержит некорректные данные. Именно поэтому появляется значение, которое мы видели на рисунке 06.

Видите, как всё начинает складываться воедино и как эти элементы связаны между собой? Если бы я просто показал вам код, который работает безупречно, у вас не было бы возможности понять, где была ошибка, потому что на первый взгляд это неочевидно.

Как исправить код 01, чтобы средняя строилась в подокне? Мы должны изменить направление расчёта внутри процедуры OnCalculate. То есть расчёт должен начинаться с самых новых значений и идти к более старым. Для этого мы изменим код 01, как показано ниже.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. const struct stAverange
07. {
08.     int            nPeriods;
09.     ENUM_MA_METHOD Method;
10.     color          cor;
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrYellow}
14. };
15. //+----------------+
16. #property indicator_chart_window
17. #property indicator_applied_price   PRICE_CLOSE
18. #property indicator_buffers         Averange.Size();
19. #property indicator_plots           Averange.Size();
20. //+------------------------------------------------------------------+
21. struct stInfos
22. {
23.     double  Buff_iMA[],
24.             f_Expo;
25. }Infos[Averange.Size()];
26. //+------------------------------------------------------------------+
27. int OnInit(void)
28. {
29.     for (uint c = 0; c < Averange.Size(); c++)
30.     {
31.         SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
32.         Infos[c].f_Expo = (double) (2.0 / (1.0 + Averange[c].nPeriods));
33.         PlotIndexSetInteger(c, PLOT_DRAW_TYPE, DRAW_LINE);
34.         PlotIndexSetInteger(c, PLOT_LINE_STYLE, STYLE_SOLID);
35.         PlotIndexSetInteger(c, PLOT_LINE_WIDTH, 1);
36.         PlotIndexSetInteger(c, PLOT_LINE_COLOR, Averange[c].cor);
37.         PlotIndexSetString(c, PLOT_LABEL, StringFormat("%s of %d", (Averange[c].Method == MODE_EMA ? "Exponential" : "Arithmetica"), Averange[c].nPeriods));
38.     }
39. 
40.        return INIT_SUCCEEDED;
41. };
42. //+------------------------------------------------------------------+
43. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
44. {
45.     int c0 = 0;
46.     double value;
47. 
48.     for (uint c = 0; c < Averange.Size(); c++) switch (Averange[c].Method)
49.     {
50.         case MODE_SMA:
51.             for (int i = rates_total - 1; i > prev_calculated; i--)
52.             {
53.                 value = 0;
54.                 for (int j = 0; (i - j) > 0 && j < Averange[c].nPeriods; j++)
55.                     value += price[i - j];
56.                 Infos[c].Buff_iMA[i] = value / Averange[c].nPeriods;
57.             }
58.             break;
59.     }
60. 
61.     return rates_total;
62. };
63. //+------------------------------------------------------------------+

Код 02

А теперь обратите внимание, дорогой читатель. Код 02 меняет направление расчёта на противоположное. В зависимости от того, как мы выполним это изменение, нам придётся тем или иным образом адаптировать код. Поскольку цель здесь учебная, я использую среднее арифметическое, которое позволяет нам работать со значительно более простым кодом. Всё, что было рассмотрено до сих пор, относится и к коду 02. Однако есть одно отличие: когда мы применяем индикатор из кода 02 к индикатору, добавленному на график в анимации 02, мы получаем результат, сильно отличающийся от того, что видели в анимации 03. Вы можете увидеть это в следующей анимации.

Анимация 05

Обратите внимание, что я изменил цвет и толщину линии индикатора прямо в коде 02. Таким образом, добавив его, мы можем ясно увидеть, что строящаяся им кривая совпадает с кривой индикатора, показанного в анимации 04. Это показывает, что он уже правильно работает в базовом сценарии использования. Разве не чудесно видеть это и учиться этому, дорогой читатель? Без того, что вы только что узнали, вы не смогли бы обнаружить эту ошибку: почти никто не упоминает, что при программировании нужно учитывать направление расчёта.

Возможно, это объясняется тем, что многие не пытались сделать то, что я вам показываю. Именно поэтому они не знают этих подробностей и не могут объяснить причину подобных сбоев. Когда никто не даёт вам объяснений, вы можете в итоге сдаться и приписать проблему неверной причине. Многие винят платформу или даже язык MQL5, хотя на самом деле не знают того, что мы только что рассмотрели.

Что ж, это было интересно и довольно увлекательно. Теперь мы воспользуемся Кодом 02, чтобы объяснить то, что лишь вкратце затронули в предыдущей статье: как и почему следует выбирать между FIRST INDICATOR'S DATA и PREVIOUS INDICATOR'S DATA. На следующем изображении показаны эти параметры.

Изображение 07

Чтобы легче это понять, нам понадобится ещё одна информация, представленная на следующем изображении.

Изображение 08

Если вы добавляете индикатор в подокно и хотите, чтобы в его вычислениях использовались уже рассчитанные значения, имеющиеся в нём, вам следует обратить внимание на то, что показано на изображении 08.

Стрелка на изображении 08 указывает порядок, в котором были добавлены индикаторы. Бывают особые случаи, когда этот порядок отражается не совсем так, но это верно почти в 100 % случаев. В любом случае индикатор, расположенный выше всех в списке, считается первым; остальные идут один за другим. Чтобы понять FIRST INDICATOR'S DATA и PREVIOUS INDICATOR'S DATA, представьте, что индикаторы на изображении 08 организованы как очередь значений, из которой вы можете выбрать данные первого или последнего элемента.

Если вы не знаете, что такое очередь значений, ознакомьтесь со статьёй «От начального к среднему уровню: очереди, списки и деревья (II)», чтобы понять, о чём идёт речь. Видите, как со временем накапливаются знания? Поэтому может показаться, что мы не продвигаемся вперёд, хотя на самом деле летим вперёд.

Как только вы поймёте, что речь идёт об очереди, станет легко понять, какой вариант выбрать. С помощью FIRST INDICATOR'S DATA мы указываем MetaTrader 5 использовать данные первого индикатора в очереди, показанной на изображении 08. С помощью PREVIOUS INDICATOR'S DATA мы указываем MetaTrader 5 использовать данные последнего индикатора из этой очереди.

Хм, это действительно хорошо продумано. Но можно ли обойти эту систему и самостоятельно выбрать, какой индикатор мы хотим использовать? Да, дорогой читатель, это можно сделать несколькими способами. Пока что не беспокойтесь об этом: мы только начинаем изучать, что можно делать с подокнами. Помните, что мы также можем установить такую связь между индикаторами на главном графике, или в главном окне. В этом случае, однако, мы будем ограничены PREVIOUS INDICATOR'S DATA. Тем не менее результаты могут быть весьма интересными, как показывает следующая анимация.

Анимация 06

Действительно, это позволяет проводить исследования для самых разных целей. Но вернёмся к подокнам. Мы уже видели в анимации 05, что происходит при добавлении индикатора из кода 02 в подокно. Давайте теперь посмотрим, что произойдёт, если мы выберем PREVIOUS INDICATOR'S DATA, чтобы понять, как формируется очередь с каждым новым индикатором. Помните, что исходная очередь показана на изображении 08. При добавлении первого нового индикатора мы получаем результат, показанный в следующей анимации.

Анимация 07


Получившаяся очередь показана на следующем изображении.

Изображение 09

Обратите внимание, что Код 02 теперь является последним элементом очереди. Если мы добавим ещё один индикатор, то получим результат, показанный в следующей анимации.

Анимация 08

Думаю, вы уже догадываетесь, к чему это ведёт. Каждый раз, когда мы добавляем индикатор, который использует в качестве основы для расчёта данные непосредственно предыдущего индикатора, мы сглаживаем или усиливаем сигнал — в зависимости от того, как именно этот индикатор выполняет расчёты. С помощью этой простой модели можно сделать многое. Нам не нужны ни сложные вычисления, ни какая-то «волшебная» скользящая средняя, ни «волшебный» индикатор, который мог бы придумать разве что математический гений. С помощью простого, быстрого и прямого расчёта можно получить очень интересные результаты.

Хорошо, а что произойдёт, если мы уберём индикатор, от которого зависят другие? На анимации 08, например, у нас есть два связанных между собой индикатора Код 02, один из которых зависит от другого. Если убрать тот, что находится выше, что произойдёт с тем, что ниже? Займёт ли он место того, который мы только что убрали? Это интересный вопрос, дорогой читатель, потому что ответ зависит от того, как MetaTrader 5 обрабатывает такую ситуацию. Мы не можем указать ему, как он должен действовать, или, по крайней мере, я не знаю способа это сделать. Поэтому нам нужно посмотреть, что происходит в этом конкретном случае. Следующая анимация нам это покажет.

Анимация 09

Обратите внимание, что MetaTrader 5 по умолчанию удаляет индикаторы, зависящие от того, который мы удаляем. Это гораздо практичнее и проще, чем придумывать какой-то сложный механизм для сохранения остальных индикаторов на графике. Кроме того, это чистое и элегантное решение: оно не оставляет никаких сомнений в том, что именно рассчитывает каждый индикатор.

Давайте теперь рассмотрим последнюю деталь, чтобы завершить статью. Мы изменим всего одну строку в Коде 02, которая приведена в следующем фрагменте.

                   .
                   .
                   .
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrDodgerBlue}
14. };
15. //+----------------+
16. #property indicator_separate_window
17. #property indicator_applied_price   PRICE_CLOSE
18. #property indicator_buffers         Averange.Size();
                   .
                   .
                   .

Фрагмент 01

Изменение — в строке 16. Не волнуйтесь, дорогой читатель: в приложении вы найдёте все коды целиком, чтобы спокойно их изучить. На практике эта модификация даёт весьма интересный эффект, хотя теоретически можно было бы ожидать чего-то совсем иного, чем то, что вы сейчас увидите.

Когда вы задаёте в индикаторе свойство, указанное в строке 16, вы ожидаете, что он ВСЕГДА будет помещён в новое подокно, верно, дорогой читатель? Однако так происходит не всегда. Это свойство приведёт к созданию подокна ТОЛЬКО В ТОМ СЛУЧАЕ, ЕСЛИ мы добавим индикатор с настройкой источника данных по умолчанию. То есть не выбирая в качестве источника данных ни FIRST INDICATOR’S DATA, ни PREVIOUS INDICATOR’S DATA. Если выбрать один из этих вариантов, MetaTrader 5 проигнорирует свойство, заданное в строке 16, и поместит индикатор в то подокно, в которое мы его добавляем.

Но подождите минуту. Означает ли это, что мы можем разместить индикатор на основном графике, несмотря на это свойство? НЕТ, дорогой читатель, в данном случае мы не можем этого сделать. MetaTrader 5 не позволяет выбрать PREVIOUS INDICATOR’S DATA в этой конкретной ситуации. Однако если вы добавите индикатор в подокно, в котором уже находится другой индикатор, вы сможете выбрать FIRST INDICATOR’S DATA или PREVIOUS INDICATOR’S DATA. В этом случае новое подокно создано не будет.

Чтобы было понятнее, давайте посмотрим несколько анимаций, показывающих это поведение.

Анимация 10

В анимации 10 мы видим, что происходит, когда пытаемся добавить на основной график индикатор, настроенный на размещение в новом подокне. Обратите внимание, что здесь мы мало что можем изменить.

Анимация 11

В анимации 11 мы проверяем, что происходит, когда добавляем индикатор в подокно, хотя он настроен на размещение в новом подокне. Обратите внимание, что, в отличие от анимации 10, теперь мы можем выбирать варианты, которые раньше были недоступны.

Больше всего нас интересует то, что в анимации 11 строится точно такая же кривая, как и в анимации 10. Хотя свойство индикатора указывает, что он должен занимать собственное подокно, MetaTrader 5 определяет, что мы уже размещаем его в одном из подокон. Поэтому ему не нужно создавать ещё одно.

Анимация 12

В анимации 12 мы делаем так, чтобы тот же индикатор из анимаций 10 и 11 использовал уже рассчитанные данные, присутствующие в подокне. Результат очень похож на то, что мы видели в начале статьи. Это показывает, что индикатор может вести себя несколько иначе, чем указывают его свойства, если это позволяет MetaTrader 5 корректно управлять индикаторами в подокне.

Анимация 13

Чтобы завершить демонстрацию, давайте посмотрим анимацию 13. Как и в анимации 12, MetaTrader 5 определяет, что лучше всего оставить индикатор в том подокне, в которое мы его перетащили. Это решение упрощает управление всеми индикаторами на графике. Таким образом, MetaTrader 5 знает, как впоследствии удалять их с учётом существующих между ними зависимостей.


Заключительные замечания

В этой статье, которая, кстати, получилась довольно увлекательной и познавательной, я показал несколько особенностей использования индикаторов в подокнах. Помните, что мы только начинаем изучать это и разбирать, как всё работает на практике.

Мы также увидели, что при написании кода нужно быть внимательными. В зависимости от того, как мы это реализуем, всё может повести себя не так, как ожидается, и дать совершенно неверные результаты или вовсе не дать никаких. В программировании по-настоящему учишься только тогда, когда экспериментируешь и изучаешь детали каждой реализации. Именно так вы можете стать квалифицированным специалистом.

В приложении вы найдёте три основных кода из статьи, чтобы опробовать их и посмотреть, что происходит в каждой ситуации. Понять, где именно код даёт сбой, гораздо важнее и поучительнее, чем просто наблюдать, как он безупречно работает на экране. Итак, дорогой читатель, воспользуйтесь этой возможностью и спокойно изучите то, что мы рассмотрели. Это может оказаться очень полезным для вас в будущем.

Файл MQ5 Описание
Indicators\\Code 01 Базовая демонстрация
Indicators\\Code 02 Базовая демонстрация
Indicators\\Code 03 Базовая демонстрация


Перевод с португальского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/pt/articles/17113

Прикрепленные файлы |
Anexo.zip (2.78 KB)
Мультитаймфреймовый движок без утечек дескрипторов с чтением закрытых баров в MQL5 Мультитаймфреймовый движок без утечек дескрипторов с чтением закрытых баров в MQL5
В статье рассматриваются две типичные проблемы, возникающие при работе с несколькими таймфреймами в MQL5: утечки дескрипторов индикаторов, приводящие к исчерпанию ресурсов, и перерисовка в результате считывания формирующегося бара (индекс 0). В статье представлен MTFEngine.mqh — единый подключаемый файл, который создаёт и отслеживает дескрипторы в одном месте, а также по умолчанию выполняет все операции чтения из закрытых баров (индекс 1). Пример D1–H4–H1 демонстрирует, как данный подход позволяет сохранить техническую корректность сигналов и их соответствие графикам.
MQL5 Bootstrap (IV): Вспомогательные средства для трейлинг-стопов и переноса стоп-лосса в безубыток MQL5 Bootstrap (IV): Вспомогательные средства для трейлинг-стопов и переноса стоп-лосса в безубыток
В этой статье представлены переиспользуемые утилиты MQL5 для управления трейлинг-стопами и переносом стоп-лосса в безубыток. В ней рассматриваются трейлинг-стоп с фиксированным расстоянием в пунктах, трейлинг на основе скользящей средней, ATR и Parabolic SAR, трейлинг в денежном выражении и периодический трейлинг, а также перенос стоп-лосса в безубыток по пунктам и в денежном выражении. Предусмотрены пороги активации, логика пошагового переноса, защита от переноса стопа в обратном направлении и проверка ограничений брокера. Примеры кода и классы Bootstrap показывают, как интегрировать эти вспомогательные средства в советники, чтобы стандартизировать управление позициями и сократить дублирование кода.
Нейронная сеть на практике: Рождение C_Neuron Нейронная сеть на практике: Рождение C_Neuron
В статье показано, как инкапсулировать нейрон в MQL5 с помощью класса C_Neuron, с весами, смещением и числом входов, задаваемым параметром. Мы подробно разберём вычисление функции потерь на основе метода наименьших квадратов и организацию данных обучения в массивах. Так можно легко менять входы и повторять эксперименты, не изменяя реализацию.
Декомпозиция частичной информации: Когда два индикатора вместе информативнее, чем каждый по отдельности Декомпозиция частичной информации: Когда два индикатора вместе информативнее, чем каждый по отдельности
Мы представляем библиотеку декомпозиции частичной информации для MQL5, которая разделяет информацию двух источников о целевой переменной на четыре атома: два уникальных (по одному для каждого источника), общий и синергетический. В реализации используются квантильное разбиение на бины, предвычисленные логарифмы и подгонка по принципу максимальной энтропии (для I_ccs). Результаты сопоставляются с нулевой моделью на основе блочных перестановок, поскольку на конечных выборках оценки атомов превышают ноль. Используйте ее для отбора пар индикаторов и проверки статистической значимости, включая поправку на множественные сравнения на уровне семейства тестов.