От начального к среднему уровню: Подокна (III)
Введение
В предыдущей статье От начального к среднему уровню: Подокна (II) были показаны некоторые ошибки и проблемы, с которыми мы можем столкнуться при попытке использовать индикатор в подокне. Более того, мы также увидели, что в MetaTrader 5 управление индикаторами реализовано довольно изобретательно. Всё это делается для того, чтобы избежать возможных конфликтов между данными, которые эти индикаторы предоставляют нам в процессе использования.
Как было показано в предыдущей статье, при наличии необходимых знаний в MetaTrader 5 можно сделать очень многое. И всё это с использованием чистого и простого MQL5. Безо всяких излишеств и бессмысленных вещей. Как многие, наверное, уже заметили, я не слишком люблю следовать жёсткой схеме. Мне нравится выходить за рамки и смотреть на то, что многие даже не представляют возможным. Поэтому я понимаю, что многие из вас, наверное, уже с нетерпением ждут возможности приступить к реализации более сложных задач. Но, как сказал бы мудрый человек, не будем торопиться.
Итак, давайте сосредоточимся на том, что будет объясняться в этой статье, оставив в стороне всё, что может отвлекать нас во время чтения. Потому что здесь мы увидим, что не всё так, как многие себе представляют.
Подокна (III)
Подокна весьма полезны, особенно если использовать их правильно, поскольку они позволяют очень просто, удобно и практично организовать множество вещей. Однако для простоты в MetaTrader 5 мы ограничены одним способом отображения подокон. Хотя это и может несколько ограничивать спектр того, что мы можем создать, в умелых руках это ограничение становится лишь небольшой деталью, ведь мы можем работать в этих рамках и сделать так, чтобы оно оставалось именно этим — простой деталью, а не настоящим ограничением, но скорее вызовом, который нам предстоит преодолеть.
Что ж, похоже, что настоящим ограничением являются лишь наше воображение и уровень наших знаний о том, что на самом деле можно сделать в MQL5, чтобы определённым образом управлять MetaTrader 5. Итак, начнём с самого простого случая — когда мы указываем компилятору MQL5, что хотим использовать подокно.
Об этом уже говорилось в конце предыдущей статьи. Однако там была показана лишь небольшая часть того, что мы действительно можем сделать. Чтобы всё было совершенно ясно, нам нужно вернуться к гораздо более простому примеру, чем тот, который мы рассматривали ранее. Таким образом, самый простой способ указать MetaTrader 5, что мы хотим использовать подокно или даже создать его, — просто воспользоваться приведённым ниже кодом.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. //+------------------------------------------------------------------+ 08. int OnInit(void) 09. { 10. return INIT_SUCCEEDED; 11. }; 12. //+------------------------------------------------------------------+ 13. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 14. { 15. return rates_total; 16. }; 17. //+------------------------------------------------------------------+
Код 01
Единственная и главная цель этого кода 01 — создать подокно на любом графике. Для этого мы используем шестую строку, где изменяем свойство самого индикатора, чтобы он размещался в подокне. Хотя это самый простой способ, он не единственный, как мы скоро увидим.
Но прежде чем перейти к этому, мне нужно объяснить ещё один очень важный момент. И вы можете — и даже должны — попробовать это, воспользовавшись приведённым выше кодом 01. Дело в том, что каждый раз, когда вы добавляете экземпляр этого кода 01 на график, создаётся новое подокно. И в зависимости от того, какую задачу должен выполнять этот индикатор, эти дополнительные экземпляры могут в итоге создать гораздо больше проблем, чем решить.
И поскольку в большинстве случаев мы можем захотеть предоставить эти коды другим трейдерам, которые на самом деле не знают, как ими пользоваться, нередко бывает так, что такие трейдеры добавляют индикатор на один и тот же график больше одного раза, создавая тем самым гораздо больше проблем, чем вы, как разработчик кода, могли предусмотреть.
Когда наш код размещается в основном окне графика, MetaTrader 5 часто довольно изобретательно использует параметры настройки нашего кода, чтобы проверить, не добавляется ли уже существующий экземпляр, уже присутствующий на графике. Если это так, новый экземпляр, который мы пытаемся создать, не будет создан. Однако если MetaTrader 5 определит, что мы действительно создаём совершенно новый, отличный экземпляр, он позволит появиться на графике новому экземпляру нашего кода.
Ну, в общих чертах именно это и происходит. Однако когда мы используем код, который создаёт или генерирует новое подокно на графике, этот механизм, используемый в MetaTrader 5, не срабатывает. Поэтому вы можете разместить несколько экземпляров кода 01 на одном графике, создав таким образом каскад подокон на графике текущего символа.
Хорошо, но что, если мы не хотим, чтобы это происходило? Как можно предотвратить создание новых подокон кодом, уже запущенным на текущем символе? Для этого нам придётся воспользоваться средствами MQL5, чтобы проанализировать, какая ситуация сложилась на текущем графике. Помните, что то, что мы здесь рассмотрим, — это лишь самые основы гораздо более обширной темы.
Для начала нам нужен способ проверить, присутствует ли наш код на графике. Для этого нам нужно добавить в наш код кое-что вполне конкретное. Это видно в приведённом ниже коде, который представляет собой своего рода обновлённую версию кода 01, который мы рассматривали недавно.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. //+------------------------------------------------------------------+ 08. int OnInit(void) 09. { 10. IndicatorSetString(INDICATOR_SHORTNAME, "Test 123."); 11. 12. return INIT_SUCCEEDED; 13. }; 14. //+------------------------------------------------------------------+ 15. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 16. { 17. return rates_total; 18. }; 19. //+------------------------------------------------------------------+
Код 02
А теперь обратите внимание на следующее, мой уважаемый читатель. В этом коде 02 мы добавили вызов, который находится в десятой строке. У этого вызова есть совершенно особая цель. Благодаря этому у нашего кода появится отображаемое имя на графике. Речь идёт об имени, которое мы видим в двойных кавычках. Разумеется, вам следует постараться, чтобы это имя было уникальным, поскольку именно его мы позже будем проверять, чтобы определить, присутствует наш код на графике или нет.
Но подождите-ка. Не было бы проще использовать имя исполняемого файла, чтобы проверить, есть ли на графике экземпляр нашего кода? Ну, в теории да, это было бы проще. Однако здесь есть одна проблема. При компиляции коду может быть присвоено определённое имя в качестве имени исполняемого файла. Но это имя может вступить в конфликт с именами других файлов, поскольку вы можете распространять свой код среди других людей. И тогда имя исполняемого файла может измениться, что сведёт на нет любую попытку проверить, присутствует ли наш код на текущем графике или нет.
Однако, используя этот вызов, который находится в десятой строке кода 02, мы избегаем подобных проблем, поскольку после компиляции пользователь вряд ли сможет изменить строку, которую мы здесь задаём. Помните, что вы можете использовать любое значение, предпочтительно такое, которое считаете уникальным. И вот что самое важное: эта строка должна быть уникальной.
Хорошо, но как эта строка поможет нам определить, есть ли у нас уже открытый экземпляр на текущем графике? Ну а теперь начинается самое интересное.
Исходя из того, что эта строка позволяет нам определить, присутствует ли наш код на графике или нет, мы добавим код для такой проверки. Но прежде чем это сделать, мне нужно, чтобы вы поняли ещё одну вещь. Это делается с помощью кода, приведённого ниже.
1. //+------------------------------------------------------------------+ 2. #property copyright "Daniel Jose" 3. //+------------------------------------------------------------------+ 4. void OnStart(void) 5. { 6. Print(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); 7. } 8. //+------------------------------------------------------------------+
Код 03
Этот код просто покажет нам, сколько окон в данный момент существует на графике, на котором он выполняется. Обратите на это внимание, мой уважаемый читатель, потому что мне нужно, чтобы вы очень хорошо поняли, к чему мы вскоре придём. При выполнении этого кода 03 мы получим нечто подобное тому, что показано ниже.

Рисунок 01
Теперь, добавив несколько подокон, мы получим то, что показано на следующем рисунке.

Рисунок 02
Хм, интересно. Тогда мы можем использовать MQL5, чтобы узнать, сколько подокон существует на графике. Но что произойдёт, если мы захотим узнать, какой именно индикатор там находится? Итак, для этого мы изменим код 03 и получим нечто похожее на то, что показано ниже.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++) 07. for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--) 08. PrintFormat("In the sub window [%d] was found this indicator >>%s<<", c0, ChartIndicatorName(0, c0, c1)); 09. } 10. //+------------------------------------------------------------------+
Код 04
Теперь, когда мы запустим этот код 04, получим результат, который можно увидеть ниже.

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

Рисунок 04
То, что мы можем увидеть на предыдущем рисунке, весьма интересно. Обратите внимание, что на этом рисунке 04 указаны названия исполняемых файлов, находящихся на графике. Однако на рисунке 03 название каждого индикатора отображается иначе. Поэтому, думаю, уже становится ясно, что имя исполняемого файла не обязательно должно быть связано с именем индикатора. На самом деле, такого рода возможность довольно сильно упрощает некоторые задачи. И да, вам стоит поблагодарить команду, которая придумала и встроила такую функциональность в MetaTrader 5, потому что в будущем она действительно позволит нам делать некоторые вещи. Однако моя цель здесь как раз в том, чтобы помочь вам понять эти мелкие детали и тем самым помочь вам создавать собственные решения.
Хорошо, но что произошло бы, если бы мы не использовали ту десятую строку кода 02? Что ж, уважаемый читатель, чтобы это показать, мы воспользуемся кодом 01. Таким образом, после добавления его на график и повторного запуска кода 04 мы получили бы результат, показанный ниже.

Рисунок 05
Теперь, открыв список индикаторов, мы можем увидеть следующее:

Рисунок 06
Хм, я этого не понимаю. Что здесь произошло? Итак, дорогой читатель, вы можете заметить, что на обоих рисунках я выделяю определённую информацию. Обратите теперь внимание на то, что, поскольку мы не задали имя для нашего индикатора, при попытке определить, какой индикатор присутствует в каждом окне, в качестве идентификатора стало использоваться имя исполняемого файла. Тем не менее я вновь подчёркиваю, что подобных ситуаций, как та, что показана на предыдущих рисунках, по возможности всегда следует избегать. Особенно когда мы действительно хотим сохранить определённый контроль над своим кодом. Как мы уже отмечали, пользователь может изменить имя исполняемого файла, и, если он это сделает, мы в итоге полностью потеряем контроль над некоторыми аспектами, связанными с нашим кодом. Поэтому очень важно знать, как и когда задавать короткое имя, — а именно это и делает десятая строка кода 02.
Существуют и другие причины использовать короткие имена в индикаторах. Но сейчас я не буду углубляться в эти причины, поскольку для их понимания нам пришлось бы сделать нечто, для чего, на мой взгляд, ещё не настал подходящий момент.
Итак, после этой базовой демонстрации некоторых аспектов, связанных с подокнами, мы можем начать работать над чем-то немного более сложным. Это связано с тем, что бывают ситуации, когда не следует использовать такие вещи обычным способом. На самом деле нам нужно добиться, чтобы они создавались по-другому.
Но что вы собираетесь делать? Что ж, дорогой читатель, обычно, когда мы работаем с индикаторами, мы не хотим — или, точнее, нам не нужно, — чтобы они дублировались. Существует очень мало ситуаций, в которых нам нужно, чтобы у определённого индикатора был второй экземпляр на том же графике. Когда такая ситуация действительно возникает, мы должны знать, как обойти это ограничение. Это связано с тем, что MetaTrader 5 весьма хитро предотвращает дублирование индикатора. Вы можете проверить это, воспользовавшись приведённым ниже кодом.
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, clrDodgerBlue} 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, 2); 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. //+------------------------------------------------------------------+
Код 05
Как бы вы ни старались, вам не удастся разместить два экземпляра этого кода 05 на одном графике. Это объясняется просто тем, что для MetaTrader 5 наличие второго экземпляра в данном случае было бы совершенно излишним. Тем не менее, давайте внесём небольшое изменение, добавив строку, чтобы можно было разобраться в этом более подробно. Строка, которую мы добавим, будет примерно такой, как в десятой строке кода 02. Таким образом, наш код 05 будет изменён, как показано в следующем фрагменте.
. . . 26. //+------------------------------------------------------------------+ 27. int OnInit(void) 28. { 29. IndicatorSetString(INDICATOR_SHORTNAME, "Averange 20 SMA."); 30. 31. for (uint c = 0; c < Averange.Size(); c++) . . .
Фрагмент 01
Теперь добавим этот новый код на график, и, как бы вы ни старались, вам снова не удастся создать второй экземпляр. Но строку 29, показанную во фрагменте 01, мы добавили именно для того, чтобы при выполнении скрипта, приведённого в коде 04, получить то, что показано на следующем рисунке.

Рисунок 07
Но этого и следовало ожидать, учитывая то, что мы видели ранее. Да, уважаемый читатель. Но знаете ли вы на самом деле, почему нам не удаётся разместить второй экземпляр кода 05 на том же графике? Конечно, знаю. Я уже пытался это сделать, но, поскольку у нас нет возможности изменить тип скользящей средней или способ её расчёта, MetaTrader 5 в итоге рассматривает этот код 05 как нечто неизменное. Следовательно, если мы попытаемся создать второй экземпляр, не внеся в код изменений, которые заставили бы MetaTrader 5 интерпретировать его иначе, нам не удастся создать второй экземпляр на том же графике.
Очень хорошо, вы, по сути, дали идеальное объяснение. Но есть ещё одна причина, и она связана со строкой 16 этого кода 05. А теперь будьте внимательны. Ваше объяснение того, почему MetaTrader 5 не позволяет разместить на графике второй экземпляр индикатора, действительно верно. Однако, когда мы изменяем свойство самого индикатора, это правило перестаёт действовать, и мы получаем другой тип поведения. Чтобы это проверить, достаточно изменить код 05 так, как показано в следующем фрагменте.
. . . 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(); 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. IndicatorSetString(INDICATOR_SHORTNAME, "Averange 20 SMA."); 30. 31. for (uint c = 0; c < Averange.Size(); c++) . . .
Фрагмент 02
Обратите внимание, что, хотя в этом фрагменте 02 я показываю более широкий участок кода, наше внимание по-прежнему сосредоточено именно на шестнадцатой строке. И обратите внимание, что в 29-й строке мы по-прежнему указываем строку, чтобы использовать её так, как было показано ранее. После компиляции кода 05 с этой модификацией, показанной во фрагменте 02, мы сможем запустить его так, что при выполнении кода 04 общий результат будет таким, как показано на следующем рисунке.

Рисунок 08
Но подождите-ка. Почему на этот раз MetaTrader 5 не помешал создать второй экземпляр? Что ж, дорогой читатель, причина именно в том, что мы изменили свойство кода так, чтобы он создавал подокно. Как правило, и это мы уже видели в предыдущей статье, мы можем использовать подокно для более сложного анализа, например для построения скользящей средней. Не имело бы никакого смысла, если бы MetaTrader 5 ограничивал добавление нового индикатора на график настолько, что не позволял бы нам создать второй экземпляр, поскольку этот новый экземпляр можно было бы использовать именно для создания того, что можно считать несколько более сложного графического построения.
Однако мы не всегда действительно хотим, чтобы пользователь или трейдер, использующий один из наших кодов, мог создать второй экземпляр определённого индикатора. И всё же в целях упорядочения мы хотим создать или, точнее, использовать подокно на графике. Если мы сами используем индикатор, основанный на подобной структуре, то понимаем, что не следует пытаться создать второй экземпляр. Но другие люди могут попытаться сделать это по той или иной причине. Поэтому мы должны создать механизмы, которые не позволят создать второй экземпляр нашего индикатора, именно для того, чтобы не появилось второе подокно.
Об этом мы подробно поговорим чуть позже. Но сначала почему бы нам немного не поэкспериментировать с этим кодом 05, который создаёт второе подокно? Есть некоторые детали, которые могут пригодиться в будущем, и это отличная возможность показать, какой контроль мы можем осуществлять над некоторыми свойствами подокна.
Например, знаете ли вы, что в нашем исходном коде можно указать, какой должна быть высота подокна? Таким образом, всё будет правильно распределено с самого начала, и пользователю будет гораздо удобнее работать.
Чтобы этого добиться, нам нужно кое-что добавить в код 05. А то, что мы собираемся сделать, показано в следующем фрагменте.
. . . 11. }Averange[] = 12. { 13. {20, MODE_SMA, clrDodgerBlue} 14. }; 15. //+----------------+ 16. #property indicator_separate_window 17. #property indicator_height 50 18. #property indicator_applied_price PRICE_CLOSE 19. #property indicator_buffers Averange.Size(); 20. #property indicator_plots Averange.Size(); 21. //+------------------------------------------------------------------+ 22. struct stInfos 23. { . . .
Фрагмент 03
Теперь, когда мы запустим код 05 с изменениями, показанными в этом фрагменте 03, результат будет таким, как показано ниже.

Рисунок 09
Такой приём оказывается чрезвычайно полезным в самых разных ситуациях, мой уважаемый читатель. Это связано с тем, что, используя то, что указано в семнадцатой строке этого фрагмента 03, мы задаём значение высоты подокна. Эта высота НЕ МОЖЕТ БЫТЬ ИЗМЕНЕНА ни трейдером, ни пользователем нашего индикатора, поскольку MetaTrader 5 не позволит её изменить.
Разумеется, вы не будете использовать такую конструкцию, если создаёте скользящую среднюю. Я делаю это здесь только для того, чтобы показать, что такое возможно. Однако подобные конструкции обычно используют при реализации и добавлении элементов управления или объектов в подокно. В таком случае использовать эту строку 17 вполне логично, поскольку мы не хотим, чтобы пользователь или трейдер изменял высоту подокна. В противном случае он может скрыть некоторые из находящихся там элементов управления или объектов либо затруднить работу с ними. Такой приём действительно интересен, и вы можете довольно подробно поэкспериментировать с этим приёмом.
Есть ещё одно свойство, весьма полезное в самых разных ситуациях. Использовать его можно очень просто. Это можно продемонстрировать с помощью пустого индикатора, как в следующем коде.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. #property indicator_height 150 08. #property indicator_maximum 80 09. #property indicator_minimum 15 10. #property indicator_plots 0 11. //+------------------------------------------------------------------+ 12. int OnInit(void) 13. { 14. return INIT_SUCCEEDED; 15. }; 16. //+------------------------------------------------------------------+ 17. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 18. { 19. return rates_total; 20. }; 21. //+------------------------------------------------------------------+
Код 06
Это действительно интересно. Очень интересно, уважаемый читатель. Часто вы можете потерять немало времени, пытаясь сделать те или иные вещи. Тем не менее, с помощью этого простого приёма, показанного в коде 06, мы можем очень быстро делать многое. Но прежде чем говорить об этом, посмотрите на результат выполнения на следующем рисунке.

Рисунок 10
Нас здесь интересуют именно эти значения, которые отображаются в правой части подокна. А теперь обратите внимание на одну вещь, уважаемый читатель, потому что она может оказаться для вас весьма полезной. Обратите внимание, что в восьмой строке этого кода 06 мы задаём значение, которое будет использоваться как максимальное значение подокна. Аналогичным образом в строке 9 мы указываем минимальное значение. Конечно, во многих случаях нет необходимости явно задавать минимальное значение, поскольку по умолчанию MetaTrader 5 установит его равным нулю. Так что здесь мы можем сделать кое-что весьма интересное. Для этого давайте рассмотрим код 06, изменённый следующим образом.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. #property description "DEMO Indicator" 05. //+------------------------------------------------------------------+ 06. #property indicator_separate_window 07. #property indicator_height 150 08. #property indicator_maximum indicator_height 09. #property indicator_plots 0 10. //+------------------------------------------------------------------+ 11. int OnInit(void) 12. { 13. return INIT_SUCCEEDED; 14. }; 15. //+------------------------------------------------------------------+ 16. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) 17. { 18. return rates_total; 19. }; 20. //+------------------------------------------------------------------+
Код 07
Но что за безумие вы задумали? Спокойно, уважаемый читатель, сейчас вы всё поймёте. Сначала запустим этот код 07. И вот результат, который мы увидим ниже.

Рисунок 11
А теперь обратите внимание: на рисунке 11 я намеренно выделяю один момент. А что это означает на практике? Итак, мой уважаемый читатель, помните, я упоминал, что в некоторых случаях бывает удобно, чтобы индикатор имел определённую высоту? Именно на это нам и указывает Рисунок 11. Обратите внимание, что в строке 7 кода 07 мы указываем высоту подокна в пикселях. Сразу после этого, в строке 8, мы указываем компилятору использовать эту же высоту как максимальный предел, который должен применяться и отображаться в индикаторе.
И что? Как это может помочь нам на практике? Обратите внимание на то, что мы только что сделали, мой уважаемый читатель. Поскольку высота подокна задана в строке 7, при использовании этой же высоты в качестве максимального значения индикатора каждый пиксель будет соответствовать определённому значению, которое мы сможем легко увидеть с помощью этого же индикатора.
Хм, я пока не понял. Не могли бы вы объяснить это немного подробнее? Ну, я не буду это объяснять; я лучше покажу вам, потому что так будет гораздо интереснее. Посмотрите на анимацию ниже.

Анимация 01
Обратите внимание на значения с правой стороны, когда мы находимся внутри подокна. А теперь подумайте вот о чём: вы хотите выровнять различные элементы управления внутри подокна так, чтобы они были распределены наилучшим образом. Как это сделать проще всего? Программируя? Да, возможно. Но реализовать графический интерфейс с помощью различных кнопок, текстов и графиков будет гораздо быстрее. Если вы сможете перейти в подокно и, используя то, что показано в этой анимации 01, взять значения, отображаемые справа, и применить их к элементам управления, разве вы не согласитесь? Это позволит вам очень быстро распределять графические объекты по подокну, поскольку вам нужно будет лишь проверить, какое значение отображается, и указать его как позицию элемента управления.
Есть гораздо более быстрый способ сделать это. Именно этот способ я разобрал в двух довольно старых статьях, которые опубликовал здесь, в сообществе. Вы можете посмотреть их здесь:
Несколько индикаторов на одном графике (Часть 05): Превращаем MetaTrader 5 в систему RAD (I)
Несколько индикаторов на одном графике (Часть 06): Превращаем MetaTrader 5 в систему RAD (II)
Правда, когда я писал те статьи, я не осознавал, что многие из тех, кто будет их читать, не были программистами — и, возможно, до сих пор ими не являются. Из-за этого значительная часть тех объяснений получилась слишком поверхностной, и многие из вас не смогли по-настоящему воспользоваться знаниями, представленными там.
То же самое произошло и с другими моими ранними статьями. В течение недель и месяцев после тех публикаций многие из вас, кто и сегодня следит за моими публикациями, просили меня подробнее объяснить отдельные детали, связанные со многими моими кодами. Поэтому и было решено создать эту серию. Надеюсь, вам нравится эта серия и что с её помощью вы успешно учитесь.
Заключительные замечания
В этой статье мы рассмотрели некоторые возможности, которые помогают определить, стоит ли использовать подокно, если наша цель — работать в MQL5 максимально просто, быстро и удобно. Однако — и в этом как раз суть всего вопроса — мы не всегда сможем пойти по этим более простым и лёгким путям. Существует множество ситуаций, в которых нам действительно придётся применить несколько более глубокий подход и где потребуется чуть более высокий уровень знаний.
Однако то, что действительно будет определять время, необходимое для создания конкретного приложения, — это не уровень знаний того или иного программиста, а степень его творческого подхода, позволяющего видеть решения там, где их больше никто не видит. И это то, чего я не могу передать ни вам, ни кому бы то ни было, уважаемый читатель. Это зависит исключительно от того, насколько вы постараетесь развить свою креативность настолько, чтобы упрощать задачи, которые для других были бы гораздо более трудоёмкими.
В следующей статье мы начнём рассматривать именно такой тип задач, в которых самое простое решение не всегда будет самым подходящим.
| Файл MQ5 | Описание |
|---|---|
| Indicators\Code 01 | Базовая демонстрация |
| Indicators\Code 02 | Базовая демонстрация |
| Indicators\Code 03 | Базовая демонстрация |
| Indicators\Code 04 | Базовая демонстрация |
| Indicators\Code 05 | Базовая демонстрация |
| Indicators\Code 06 | Базовая демонстрация |
| Scripts\Code 01 | Базовая демонстрация |
| Scripts\Code 02 | Базовая демонстрация |
Перевод с португальского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/pt/articles/17117
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейронная сеть на практике: График функции ReLU
Нейронная сеть на практике: Рождение C_Neuron
Стресс-тестирование последовательностей сделок методом Монте-Карло в MQL5
Мультитаймфреймовый движок без утечек дескрипторов с чтением закрытых баров в MQL5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования