English 中文 Español Deutsch 日本語 Português
preview
От начального до среднего уровня: Переменные (II)

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

MetaTrader 5Примеры | 20 января 2025, 09:46
325 0
CODE X
CODE X

Введение

Представленные здесь материалы предназначены исключительно для дидактических целей. Ни в коем случае нельзя рассматривать это как приложение, чьей целью будет что-то иное помимо изучения и освоения представленных концепций.

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

Здесь мы продолжим эту тему, исходя из того, что читатель адекватно понял исходный материал. В вопросе о сроке действия и видимости переменных мы сталкиваемся с тем, что новичкам немного сложно понять это. Причина в том, что во многих случаях мы НЕ ХОТИМ, чтобы глобальные переменные создавали неудобства. Мы хотим, чтобы переменные существовали только в пределах одного блока кода. Однако - и вот тут всё становится сложнее - мы НЕ хотим, чтобы значение переменной умерло или исчезло после завершения блока.

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

Однако у программистов на С/С++ данная концепция прочно укоренилась в сознании. А поскольку MQL5 является производным от этих языков, то и концепция в нем оказалась такой же, и это, на мой взгляд, очень положительный момент. В противном случае пришлось бы работать с глобальными переменными на уровне приложения, что часто оказывается серьезным неудобством.

Теперь, чтобы объяснить, как работает подобная концепция, давайте начнем новую тему.


Статические переменные

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 0;
07.     ulong value = 1;
08. 
09.     Print("Factorial of ", counter, " => ", value);
10.     counter = counter + 1;
11.     value = value * counter;
12.     Print("Factorial of ", counter, " => ", value);
13.     counter = counter + 1;
14.     value = value * counter;
15.     Print("Factorial of ", counter, " => ", value);
16.     counter = counter + 1;
17.     value = value * counter;
18.     Print("Factorial of ", counter, " => ", value);
19.     counter = counter + 1;
20.     value = value * counter;
21.     Print("Factorial of ", counter, " => ", value);
22. }
23. //+------------------------------------------------------------------+

Код 01

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

Главный момент заключается в следующем: когда мы запустим данный Код 01 в терминале MetaTrader 5, то получим то, что показано ниже.


Рисунок 01

Отлично, как видите, работает. Здесь мы вычисляем факториал числа. Только вместо того, чтобы сделать это и просто вернуть результат, мы вычисляем его шаг за шагом. Данный факт важен для того, чтобы понять, к чему я клоню.

А теперь внимание. В шестой строке мы создаем и инициализируем переменную. Она позаботится о подсчете текущего, вычисляемого, факториала. После этого, в седьмой строке, мы объявляем еще одну переменную и инициализируем ее соответствующим значением. И да, факториал нуля равен единице, так же как факториал единицы тоже равен единице. Данные знания необходимы для любой работы в области программирования. Потому что программирование подразумевает математическое решение задач (вопреки мнению многих людей), что программирование - это просто написание множества программ и их выполнение компьютером. Работа программиста, по сути, заключается в преобразовании математических формул в код, понятный машинам. По этой причине знание математики является основополагающим для того, чтобы стать хорошим программистом.

Возвращаясь к нашему вопросу, в строках 09, 12, 15, 18 и 21 мы выводим результаты в удобном для чтения виде. И между каждым из этих шагов мы сообщаем машине, как перейти к вычислению следующего значения. Теперь обратите внимание на важный факт: каждый раз, когда мы вычисляем факториал текущего числа, мы используем значение предыдущего факториала. То есть, хотя изначально счетчик и значение являются константами, при каждом новом запросе на вычисление эти ранее постоянные значения меняются и превращаются в новую константу. Это самая уникальная концепция переменных, которую мы должны унести с собой на всю оставшуюся жизнь в качестве программиста.

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. uchar counter = 0;
05. ulong value = 1;
06. //+------------------------------------------------------------------+
07. void OnStart(void)
08. {
09.     Factorial();
10.     Factorial();
11.     Factorial();
12.     Factorial();
13.     Factorial();
14. }
15. //+------------------------------------------------------------------+
16. void Factorial(void)
17. {
18.     Print("Factorial of ", counter, " => ", value);    
19.     counter = counter + 1;
20.     value = value * counter;
21. }
22. //+------------------------------------------------------------------+

Код 02

Обратите внимание, что код 02 гораздо проще для понимания. С первого взгляда заметно, что мы вычисляем значение факториала от нуля до четырех. Это происходит, потому что мы имеем четыре вызова метода Factorial внутри основного блока кода, то есть метода OnStart. Как уже говорилось ранее, мы рассмотрим это позже. Но сейчас давайте сосредоточимся на понимании переменных.

Обратите внимание, что несмотря на кажущееся различие между кодом 01 и кодом 02, в обоих случаях результатом будет Рисунок 01. Однако здесь, в коде 02, мы используем две глобальные переменные, которые появляются при выполнении кода и исчезают только после его завершения. Между одним и другим моментом эти же переменные могут быть изменены любым методом или функцией, которая имеет над ними видимость. Даже если это изменение произошло по нашей вине, из-за того, что мы отвлеклись в процессе реализации кода. Это не редкость для сложных кодов.

Но даже если они являются глобальными переменными и не принадлежат какому-то конкретному блоку, эти значения должны быть инициализированы. Как видно, мы выполняем инициализацию в тот момент, когда их объявляем. Однако это можно сделать в любое другое время, что затрудняет отслеживание возможных изменений в их стоимости. Но для простоты мы инициализируем их прямо при объявлении. По этой причине в данный момент возникает вполне резонный вопрос: если мы разрабатываем что-то очень сложное, и боимся изменить значения какой-нибудь глобальной переменной по рассеянности во время написания кода приложения, не лучше ли объявить переменные counter и value внутри метода Factorial? Так мы не будем рисковать тем, что эти переменные могут быть изменены по недосмотру!

Да, лучшей идеей будет удалить counter и value из глобальной области видимости и поместить их в метод Factorial. Так мы сможем лучше контролировать переменные, которые находятся в коде. Давайте сделаем это и посмотрим, что получится. Судя по всему, и код 01, и код 02 работают, а если они работают, значит, мы на верном пути. Таким образом, внеся вышеупомянутые изменения, мы получим следующий код:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Factorial();
07.     Factorial();
08.     Factorial();
09.     Factorial();
10.     Factorial();
11. }
12. //+------------------------------------------------------------------+
13. void Factorial(void)
14. {
15.     uchar counter = 0;
16.     ulong value = 1;
17. 
18.     Print("Factorial of ", counter, " => ", value);    
19.     counter = counter + 1;
20.     value = value * counter;
21. }
22. //+------------------------------------------------------------------+

Код 03

Хорошо, теперь у нас больше нет проблемы глобальных переменных в области видимости кода. Наша программа на самом деле гораздо более организованная. Но как быть с результатом, ведь мы по-прежнему вычисляем факториал от нуля до четырех? Давайте посмотрим. После компиляции кода и его запуска в терминале MetaTrader 5, мы получаем следующий результат:


Рисунок 02

Ух ты! Это не сработало. Но почему? Ведь раньше это работало. На самом деле я не понимаю, поскольку мы, очевидно, запускаем метод пять раз, как и ожидалось. Однако, похоже, мы постоянно получаем одни и те же значения. Давайте немного подумаем... Сохраняем спокойствие.

Кажется я понял, что происходит: каждый раз, когда мы выполняем один из вызовов, присутствующих в том, что мы назвали главным блоком, а именно OnStart, мы снова объявляем переменные counter и value. При этом мы также инициализируем их начальными значениями, которые мы указали в других кодах выше. Вот почему это не сработало. Теперь понятно, что называется "жизненным блоком" переменной. Но у меня всё еще есть вопрос: что, если мы НЕ будем сообщать значение в строках 15 и 16? Может быть, это сработает! Нет, можно сделать это, если хотим, но в итоге мы попадем в проблемы, которые уже были рассмотрены в предыдущей статье.

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

Если это так, то пора положить конец этим страданиям. Чтобы решить данную проблему, не прибегая к какому-либо магическому решению и сохраняя переменные counter и value внутри метода Factorial, нам нужно использовать так называемую статическую переменную. Таким образом, переменная, объявленная как статическая, НЕ будет терять своего значения при различных вызовах одного и того же метода или функции.

Но это звучит очень сложно, не так ли? На практике всё гораздо проще. Если мы будем внимательно относиться к тому, что делаем, всё пройдет хорошо. Однако если мы будем неосторожными, ситуация может выйти из-под контроля. Чтобы понять это, давайте посмотрим, как код будет выглядеть на практике. Его можно увидеть ниже.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Factorial();
07.     Factorial();
08.     Factorial();
09.     Factorial();
10.     Factorial();
11. }
12. //+------------------------------------------------------------------+
13. void Factorial(void)
14. {
15.     static uchar counter = 0;
16.     static ulong value = 1;
17. 
18.     Print("Factorial of ", counter, " => ", value);    
19.     counter = counter + 1;
20.     value = value * counter;
21. }
22. //+------------------------------------------------------------------+

Код 04

Обратите внимание: единственным отличием кода 03 от кода 04 является наличие зарезервированного слова static в строках 15 и 16. Однако именно благодаря этому теперь результат выполнения кода 04 в терминале MetaTrader 5 выглядит именно так, как показано на рисунке 01, то есть мы получили долгожданный успех. Но из-за статической природы переменных, объявленных как статические, к ним следует относиться с осторожностью и вниманием. Это связано с тем, что в отношении них действуют особые правила. И мы вовсе не обязаны делать определенные вещи, но должны понимать, как они работают.

Статическая переменная - это, прежде всего, переменная, которая всегда должна находиться внутри блока. Хотя в некоторых случаях мы можем использовать их вне блоков для определенных целей, мы всегда должны думать о том, чтобы использовать их внутри какого-то блока.

Во-вторых, за исключением очень специфических случаев, мы НИКОГДА не должны инициализировать статическую переменную вне того места, где она объявлена. Если делать это без нужной осторожности, можно потерять контроль над кодом. Поскольку мы работаем с простыми материалами, направленными на изучение, у нас может возникнуть ложное чувство контроля. Однако не стоит обманываться, любая неосторожность с нашей стороны приведет к потерю нескольких часов или дней, в попытках решения проблемы. Чтобы сделать это предельно ясным, мы внесем небольшое изменение в код 04. Посмотрим, что из этого выйдет. Изменения можно увидеть ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Factorial();
07.     Factorial();
08.     Factorial();
09.     Factorial();
10.     Factorial();
11. }
12. //+------------------------------------------------------------------+
13. void Factorial(void)
14. {
15.     static uchar counter;
16.     static ulong value = 1;
17. 
18.     counter = 1;
19.     Print("Factorial of ", counter, " => ", value);    
20.     counter = counter + 1;
21.     value = value * counter;
22. }
23. //+------------------------------------------------------------------+

Код 05

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


Рисунок 03

Это безумие! Насколько я могу судить, то, что должно было быть вычислением факториала, стало вычислением степеней кратных двум. Странно. Но почему это произошло? Тут есть небольшая хитрость, позволяющая правильно работать со статическими переменными. Более опытный программист, столкнувшись с кодом, который ведет себя нестандартно, сразу же заподозрит ошибку в использовании переменных. Если язык позволяет использовать данный вид переменных и код содержит переменные такого типа, то сначала необходимо проверить эти переменные.

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

Но давайте вернемся к вопросу о том, почему код повел себя странно, хотя, казалось бы, ничего страшного в нем нет, - это первая мысль, которая приходит в голову любому программисту. Однако статические переменные ИНИЦИАЛИЗИРУЮТСЯ в момент их создания. В ином случае, при присвоении ей значения переменная будет вести себя как локальная переменная. Другими словами, она как будто была объявлена в этот момент. Естественно, это означает, что внутри блока следует по возможности избегать того, что показано в строке 18 кода 05. Это приведет к «поломке» статической переменной и ее некорректной работе. Вот почему код вел себя странно: то, что было статической переменной, теперь стало обычной переменной.

Хорошо, благодаря этому у нас уже есть хорошая основа, чтобы начать работу над следующими пунктами.


Типы данных

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

Мы говорим о типах данных или переменных. Различные языки, но в основном скриптовые, такие как JavaScript и Python, не требуют от программиста объявления типа хранимых данных. То есть они относятся к НЕТИПИЗИРОВАННОМУ виду, в то время как другие, такие как C/C++ и сам MQL5, являются сильно ТИПИЗИРОВАННЫМИ. Другими словами, они требуют от программиста указать, какой тип данных ожидается. Что это означает на практике? Это означает, что переменная в Python может принимать любое значение. Однако переменная в MQL5 не может принимать любое значение. Это теоретически, поскольку есть способы обойти подобные неудобства.

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

В этот момент вы, пожалуй, думаете о том, чтобы отказаться от понимания MQL5 и начать искать что-то более простое, например Python или JavaScript. Однако, не умаляя значения других нетиповых языков, можно сказать, что когда вы научитесь работать с типами, присутствующими в языке, работа на том языке, где такого контроля нет, становится очень монотонной, а иногда и скучной. Работа с данными предполагает понимание того, что они представляют из себя, как можно их классифицировать по типам и какие пределы у каждого из них. Подобные знания открывают двери для множества интересных приложений, таких как криптография или сжатие данных.

Но оставим данный вопрос на другой раз. Давайте разберемся сначала с типами и их основными ограничениями.

В MQL5 у нас есть несколько основных типов: целые числа, логические, литералы, с плавающей точкой, перечислители и строки. Они также встречаются в коде на языке C/C++. Однако помимо данных типов, распространенных во многих языках на базе C/C++, в MQL5 есть и особые, такие как данные о цвете и данные о дате и времени. Хотя, как мы увидим ниже, они являются производными от других типов, сам факт их существования может быть полезен в определенные моменты.

С другой стороны, сложные типы данных есть и в C/C++, и в MQL5. Они делятся на структуры и классы. Что касается классов, то они существуют только в C++. Однако в MQL5 классы гораздо проще для понимания и работы, чем в C++. Хотя иногда мне, как программисту на C++, не хватает некоторых ресурсов класса, которые есть в C++, но их нет в MQL5, но даже если их нет, мы адаптируемся так, чтобы работа и цель были достигнуты.

Хорошо, это было базовое введение в тему. Но прежде, чем закончить данную статью, мы можем поговорить еще немного, например, о пределах возможностей каждого из основных типов. Знание и понимание данных ограничений окажет большую помощь в создании ваших будущих кодов, независимо от того, какой цели мы хотим достичь. Начнем с небольшой таблицы, которую можно увидеть ниже.

Тип Количество байтов Наименьшее значение Наибольшее значение
char 1 -128 127
uchar 1 0 255
bool 1 0 (False) 1 (True)
short 2 -32 768 32 767
ushort 2 0 65 535
int 4 - 2 147 483 648 2 147 483 647
uint 4 0 4 294 967 295
color 4 -1 16 777 215
float 4 1.175494351e-38 3.402823466e+38
long 8 -9 223 372 036 854 775 808 9 223 372 036 854 775 807
ulong 8 0 18 446 744 073 709 551 615
datetime 8 0 (01/01/1970 00:00:00) 32 535 244 799 (31/12/3000 23:59:59)
double 8 2.2250738585072014e-308 1.7976931348623158e+308

Таблица основных типов

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

Однако в этой таблице есть два элемента, которые рассмотрим более подробно в будущем: типы double и float. Это связано с тем, что у обоих есть свои особенности, которые нужно объяснять отдельно.

Но давайте вкратце проанализируем данную таблицу. Можно заметить сходство в названиях, где в некоторых случаях буква u предшествует имени типа, как в char и uchar. Буква u имеет особое значение: когда перед именем типа стоит эта буква, это означает, что тип начинается с нуля и доходит до определенного предела. Потому что эта начальная буква u происходит от английского слова unsigned, что означает "беззнаковый". Но что означает "беззнаковый" на практике? Когда у нас есть беззнаковое значение, это значит, что оно всегда будет интерпретироваться как положительное. С другой стороны, когда значение имеет знак, он может быть как положительным, так и отрицательным. Это станет понятнее, когда мы поговорим о математических операциях. Но в принципе, это можно интерпретировать так: если мы хотим хранить отрицательное значение, можно поместить его в знаковый тип. Однако, если все хранимые значения положительные, можно использовать беззнаковый тип. Но почему я говорю о том, что возможно, и не правильнее ли было бы сказать о том, что нужно? На самом деле, это не обязательно. Когда мы будем говорить о математических операциях, я расскажу об этом подробнее. Но здесь действует фундаментальное правило: целочисленные значения, то есть те, в которых не используется плавающая точка, являются точными. С другой стороны, значения с плавающей точкой не являются точными. Хотя, глядя на эту таблицу, можно подумать, что лучше всегда использовать данные типа double, поскольку они охватывают значительный диапазон, на практике это не всегда так. Поэтому хорошему программисту необходимо знание того, как выбрать правильный тип.

Однако вы, вероятно, смотрите на эту таблицу и думаете: а где же тип string, разве это не базовый тип?! Да, тип string - это базовый тип. Но это особый тип, который лучше подходит для другой категории, о которой мы расскажем позже. По этой причине он не представлен в таблице.


Заключительные идеи

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

Мы также получили краткое представление о теме следующей статьи, а именно о типах данных. Мы обнаружили, что для каждого типа данных в MQL5 существуют различия и ограничения, но не объяснили, почему данные ограничения существуют и как их можно обойти, чтобы расширить их для более конкретных целей.

Но не волнуйтесь, скоро мы это увидим. На этом я прощаюсь с вами. Оставляю прикрепленные к статье коды, чтобы вы могли поэкспериментировать с ними и сделать свои собственные выводы относительно того, что мы здесь представили. До скорой встречи!

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

Прикрепленные файлы |
Anexo.zip (1.75 KB)
Пользовательский индикатор: Отображение сделок входа, выхода и разворота позиции на неттинговых счетах Пользовательский индикатор: Отображение сделок входа, выхода и разворота позиции на неттинговых счетах
В данной статье мы рассмотрим нестандартный способ создания индикатора в MQL5. Вместо того, чтобы фокусироваться на тренде или графическом паттерне, нашей целью будет управление собственными позициями, включая частичные входы и выходы. Мы будем активно использовать динамические матрицы и некоторые торговые функции, связанные с историей сделок и открытыми позициями, чтобы указать на графике, где осуществились данные сделки.
Создание советника Daily Drawdown Limiter на языке MQL5 Создание советника Daily Drawdown Limiter на языке MQL5
В статье подробно рассматриваются возможности реализации советника на основе торгового алгоритма. Это поможет автоматизировать систему на MQL5 и взять под контроль дневную просадку.
Функции активации нейронов при обучении: ключ к быстрой сходимости? Функции активации нейронов при обучении: ключ к быстрой сходимости?
В данной работе представлено исследование взаимодействия различных функций активации с алгоритмами оптимизации в контексте обучения нейронных сетей. Особое внимание уделяется сравнению классического ADAM и его популяционной версии при работе с широким спектром функций активации, включая осциллирующие функции ACON и Snake. Используя минималистичную архитектуру MLP (1-1-1) и единичный обучающий пример, производится изоляция влияния функций активации на процесс оптимизации от других факторов. Предложен подход к контролю весов сети через границы функций активации и механизма отражения весов, что позволяет избежать проблем с насыщением и застоем в обучении.
Торговый инструментарий MQL5 (Часть 2): Расширение и применение EX5-библиотеки для управления позициями Торговый инструментарий MQL5 (Часть 2): Расширение и применение EX5-библиотеки для управления позициями
Узнайте, как импортировать и использовать EX5-библиотеки в вашем коде или проектах MQL5. В этой статье мы расширим ранее созданную EX5-библиотеку, добавив больше функций управления позициями и создав два советника. В первом примере будет использоваться технический индикатор Variable Index Dynamic Average для разработки советника по стратегии трейлинг-стопа, а во втором - торговая панель для мониторинга, открытия, закрытия и изменения позиций. Эти два примера продемонстрируют, как использовать обновленную EX5-библиотеку для управления позициями.