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

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

MetaTrader 5Примеры | 22 января 2025, 08:40
337 2
CODE X
CODE X

Введение

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

В предыдущей статье "От начального до среднего уровня: Переменные (II)", мы обсудили и объяснили, как использовать статические переменные в нашем коде. Это необходимо для того, чтобы избежать ненужного использования глобальных переменных. Итак, с основными переменными мы закончили. Однако остается вопрос о типе данных, которые может содержать каждая переменная, что всё еще имеет некоторое отношение к этой проблеме. Я не буду рассматривать данный аспект в рамках темы переменных. Об этом мы расскажем в отдельной теме, посвященной исключительно этому.

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

Но мы начнем новую тему, чтобы было понятно, что функция - это особая переменная.


Особая переменная: Функции

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

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

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

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

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(One_Radian());
07. }
08. //+------------------------------------------------------------------+
09. double One_Radian()
10. {
11.     return 180. / M_PI;
12. }
13. //+------------------------------------------------------------------+

Код 01

В коде 01 у нас простой и наглядный пример. При выполнении данного кода мы получим такой результат:


Рисунок 01

Хорошо, сейчас вы можете себя спросить: зачем делать это таким образом? Не проще ли поместить вычисления из строки 11 прямо в строку 06 и вывести результат? Да, так и есть. Однако если вы так подумали, значит, вы не поняли идею, приведенную в данном примере. Идея не в том, чтобы выполнить само вычисление, а в том, чтобы сгенерировать константу, которая может быть использована глобально в любой части кода. Если бы каждый раз, когда нам нужно было узнать значение константы, приходилось писать код для ее вычисления, тогда стало бы очень сложно улучшить или исправить код. С другой стороны, если всё будет заключено в функции с представительным именем, которая генерирует эту константу, всё будет намного проще, быстрее и практичнее. И это сделает нас гораздо эффективнее как программистов.

Давайте рассмотрим возможность разработки 3D-программы, которой нужно значение в градусах-радианах. И не просто в одной строке кода, а в сотнях, распределенных по всей программе. В этот момент я задам вопрос: что проще - писать вычисления каждый раз или поместить их в одну функцию, как показано в коде 01?

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Counting();
07.     Print(Counting());
08.     Counting();
09.     Counting();
10.     Print(Counting());
11. }
12. //+------------------------------------------------------------------+
13. ulong Counting(void)
14. {
15.     static ulong Tic_Tac = 0;
16. 
17.     Tic_Tac = Tic_Tac + 1;
18. 
19.     return Tic_Tac;
20. }
21. //+------------------------------------------------------------------+

Код 02

В данном случае при выполнении этого кода 02 мы получим результат, подобный показанному ниже:


Рисунок 02

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


Предопределенные переменные

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

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

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(_LastError);
07.     _LastError = 2;
08.     Print(_LastError);
09. }
10. //+------------------------------------------------------------------+

Код 03

Если вы только начали изучать MQL5, обратите внимание на то, что я сейчас расскажу. В строке 6 этого кода 03 мы просим вывести на терминал текущее значение переменной _LastError. Поскольку в MQL5 это предопределенная переменная, объявлять ее не обязательно. Компилятор вполне способен распознать ее.

Однако как только компилятор встретит седьмую строку, как видно в этом коде 03, то произойдет ошибка, как показано на следующем изображении:

Рисунок 03

Почему такое происходит? Причина в том, что эти предопределенные переменные в MQL5 рассматриваются как константы в коде, который мы пытаемся использовать. Однако на уровне кода, который будет интерпретироваться MetaTrader 5 на этапе исполнения, данные переменные не считаются константами.

На первый взгляд такая ситуация может показаться очень запутанной и сложной, особенно для тех, кто только начинает осваивать программирование. Однако прежде, чем мы перейдем к другим вопросам об этих предопределенных переменных, мы должны понять следующее: поскольку эти переменные будут существовать в любом коде MQL5, мы НЕ ДОЛЖНЫ пытаться создать другую переменную с тем же именем, что и эти предопределенные переменные. Пытаясь сделать это, мы также нарушим безопасность, предложенную самой платформой.

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

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

Чтобы проверить это на практике, можно использовать приведенный ниже код:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(_LastError);
07.     SetUserError(2);
08.     Print(_LastError);
09. }
10. //+------------------------------------------------------------------+

Код 04

На самом деле, данный код будет скомпилирован и вполне может быть выполнен. Однако, если запустить его в MetaTrader 5, мы увидим нечто подобное тому, что показано на рисунке ниже:


Рисунок 04

Что это за странное число? Подождите секунду. Действительно, в седьмой строке кода 04 мы присваиваем то же значение, что и в той же строке кода 03. Хорошо, мы понимаем, что код 03 не был скомпилирован по причинам, описанным выше, но даже в этом случае значение, показанное на изображении 4, не соответствует нашим ожиданиям.

На самом деле, это значение - то самое, которое мы пытались поместить в переменную _LastError, но оно было смещено. Это необходимо для того, чтобы избежать конфликтов с любыми предопределенными значениями ошибок. Чтобы получить значение, которое мы хотим присвоить _LastError, нужно сделать небольшую поправку. Однако прежде, чем приступить к этой корректировке, необходимо понять кое-что еще. Обычно многие программисты не используют имя предопределенной переменной непосредственно в коде. Многие предпочитают (а на самом деле так лучше всего) использовать функцию, которая возвращает значение такой предопределенной переменной. Хотя ничто не мешает нам написать код так, как показано выше, наиболее распространенным и, по мнению многих, наиболее правильным будет использование кода, подобного следующему:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(GetLastError());
07.     SetUserError(2);
08.     Print(GetLastError());
09. }
10. //+------------------------------------------------------------------+

Код 05

Обратите внимание, что код, по сути, делает то же самое. Однако для многих код 05 является более читаемым, чем код 04. Так мы даем понять другим программистам, которые читают код, что обращаемся к значению предопределенной переменной. А вы заметили, что то, о чем говорили в предыдущей теме, применимо и здесь? Способ доступа к предопределенным переменным для их последующего чтения, не имеет значения. Но метод изменения их значений всегда будет таким же. Например, чтобы удалить любое значение из переменной _LastError, мы НЕ ДОЛЖНЫ использовать процедуру, показанную в седьмой строке приведенных выше кодов. Если это сделать, то присвоим новое значение ошибки. Правильным способом очистки или удаления ошибок из _LastError, является использование другой процедуры, предусмотренной в MQL5. Она такая:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(GetLastError());
07.     SetUserError(2);
08.     Print(GetLastError());
09.     SetUserError(0);
10.     Print(GetLastError());
11.     ResetLastError();
12.     Print(GetLastError());
13. }
14. //+------------------------------------------------------------------+

Код 06

Если вы видите это впервые, будьте очень внимательным. Когда этот код выполняется, результат будет таким, как показано ниже:


Рисунок 05

Обратите внимание: когда будет выполнена шестая строка, будет напечатана первая строка, которую видно на изображении 05. Это означает, что в переменной _LastError нет ни ошибки, ни значения. После выполнения седьмой строки мы присвоим значение переменной _LastError, как показано выше. Однако некоторые новички пытаются использовать девятую строку для очистки переменной _LastError. Но когда мы сделаем это и выведем результат, то получим ненулевое значение. Почему так происходит? Причина та же, что и в предыдущем случае. Когда мы используем SetUserError для присвоения значения _LastError, это значение смещается. По этой причине попытка присвоить любое значение с помощью данной функции не приведет к ожидаемому значению. Так как наша цель - поместить в переменную _LastError значение ноль, правильнее всего будет использовать строку 11. Когда процедура в строке 11 выполняется, значение ноль должно быть присвоено _LastError.

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

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

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


Перечисления и определения констант

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int OnInit()
05. {
06.    return INIT_SUCCEEDED;
07. };
08. //+------------------------------------------------------------------+
09. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
10. {
11.    return rates_total;
12. };
13. //+------------------------------------------------------------------+

Код 07

Здесь, в шестой строке, мы находим то, что не имеет особого смысла для многих, хотя встречается практически в каждом коде индикатора. Поговорим поподробнее об этом, когда придет время. Сейчас я показываю этот код 07 просто для примера того, что можно встретить во многих кодах. Хотя зарезервированное слово return подразумевает переменную или значение, здесь мы используем текст. Что означает данный текст и почему мы используем именно его, а не какой-то другой? На самом деле, мы могли бы использовать что-то другое, но давайте делать по одному шагу за раз.

Если обратиться к разделу Константы, перечислители и структуры, то увидим, что в MQL5 определено множество констант и перечислений. Данные перечисления и константы, как, например, в шестой строке кода 07, имеют свое название в программировании. Данные сущности называются псевдонимами, и да, они написаны именно так, поскольку мы не можем использовать ударения в языке программирования. Его цель - создать лучшее представление, чтобы помочь нам запомнить его функцию или сделать код более удобным для чтения.

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

Можно использовать значение больше нуля или просто написать слово true. ТЕОРИТИЧЕСКИ оба варианта могут работать. Иными словами, то же самое значение в строке 6 кода 07 можно было бы записать так:

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
int OnInit()
{
   return true;
};
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
{
   return rates_total;
};
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    Print(reason);
};
//+------------------------------------------------------------------+

Код 08

Однако в этом случае наш код не сработает. Почему он же так произойдет? Это не имеет никакого смысла, поскольку при использовании значения true, мы утверждаем, что OnInit завершился успешно. Да, уважаемый читатель. Возвращение true означает выполнение чего-либо без ошибок. Однако даже в этом случае наш код потерпит неудачу и закроется сразу после выполнения OnInit. Причина этого кроется в значении, связанном с псевдонимом INIT_SUCCEEDED.

Дело не в том, что мы не можем использовать другое значение, просто нам нужно понять, что INIT_SUCCEEDED заменяет значение более удобным для человека способом. Если посмотреть документацию, то можно увидеть, что значение INIT_SUCCEEDED фактически равно нулю. В булевой логике значение ноль обозначает false. Поэтому, используя значение true, код 08 потерпит неудачу, даже если в нем нет ошибок.

Важная деталь: если запускать код 08, то сразу после его выполнения мы увидим следующее сообщение в терминале:


Рисунок 06

Я знаю, что сейчас это не имеет никакого смысла, но я вам гарантирую, что со временем всё станет ясно. Поэтому можно использовать значение ноль или false в шестой строке кода 08, и это будет прекрасно работать, но только если мы удалим индикатор с графика. Однако это не единственный тип псевдонима, который можно использовать. Также можно использовать что-то вроде следующего:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int OnInit()
05. {
06.    return ERR_SUCCESS;
07. };
08. //+------------------------------------------------------------------+
09. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
10. {
11.    return rates_total;
12. };
13. //+------------------------------------------------------------------+
14. void OnDeinit(const int reason)
15. {
16.     Print(reason);
17. };
18. //+------------------------------------------------------------------+

Код 09

В случае, показанном в коде 09, а также при использовании значения ноль или false в шестой строке кода 08, после удаления индикатора с графика получим такой результат:


Рисунок 07

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. int OnInit()
05. {
06.    return GetLastError();
07. };
08. //+------------------------------------------------------------------+
09. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
10. {
11.    return rates_total;
12. };
13. //+------------------------------------------------------------------+
14. void OnDeinit(const int reason)
15. {
16.     Print(reason);
17. };
18. //+------------------------------------------------------------------+

Код 10

Это будет крайний случай, поскольку если во время выполнения любой части кода из OnInit, произойдет ошибка, возвращаемое значение будет отличаться от нуля или любого из указанных выше значений, представляющих собой ноль. Это происходит так, потому что GetLastError (как упоминалось выше) обнаружит, что _LastError содержит некоторое значение. Однако важно отметить, что ошибка может возникнуть в любом месте кода, и эта ошибка может быть частью того, что мы написали, а может и не быть ею. Иногда ошибки связаны не с упущениями в коде, а с взаимодействием между значениями. Это может привести к тому, что у переменной _LastError по какой-либо причине будет ненулевое значение. По этой причине данный тип управления считается экстремальным. Наличие кода, в котором используется такой подход, является редкостью. Однако, если мы решим попробовать, то обнаружим, что часто возникают интересные ситуации.

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

Хорошо, в качестве последнего вопроса, который мы обсудим в этой статье, мы рассмотрим, как использование констант и перечислений, определенных внутри MQL5, может повлиять на нашу работу. Как уже было показано в предыдущей теме, с помощью процедуры SetUserError мы можем присвоить системной переменной _LastError любое значение. Но а что, если мы хотим узнать, какое именно значение было присвоено с помощью SetUserError? Как мы можем это выяснить? Это самая простая часть. В документации SetUserError описано, как следует выполнять настройку. Часть текста приводится ниже:

Устанавливает предопределенную переменную _LastError в значение, равное ERR_USER_ERROR_FIRST + user_error

То есть, если вычесть ERR_USER_ERROR_FIRST из значения, найденного в _LastError, можно определить точное значение, которое было задано в SetUserError. Давайте рассмотрим пример приложения в приведенном коде:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(GetLastError());
07.     SetUserError(2);
08.     Print(GetLastError());
09.     Print(GetLastError() - ERR_USER_ERROR_FIRST);
10. }
11. //+------------------------------------------------------------------+

Код 11

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


Рисунок 08

Обратите внимание, что показано три значения. Однако нас интересуют второе и третье, поскольку в данном случае коррекция значения выполняется именно для того, чтобы определить, какое именно значение было присвоено процедурой SetUserError, чтобы указать на ошибку.


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

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

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

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

Прикрепленные файлы |
Anexo.zip (2.11 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
amrali
amrali | 13 февр. 2025 в 19:38
MetaQuotes:

Ознакомьтесь с новой статьей: От базового к промежуточному уровню: Переменные (III).

Автор: CODE X

После того как я только что прочитал заголовок "Специальные переменные: Функции", я подумал, что в статье будет обсуждаться специальный тип "указатели функций".
CODE X
CODE X | 14 февр. 2025 в 14:28
amrali # :
После того как я только что прочитал заголовок "Специальные переменные: Функции", я решил, что в статье будет рассмотрен специальный тип "указатели функций".

Об этом будет рассказано позже в другой статье, созданной специально для этой цели. Так как для того, чтобы понять, зачем использовать указатели на функции, нужно сначала разобраться в другом типе понятий - как работать с событиями. 🙂👍

Нейросети в трейдинге: Контекстно-зависимое обучение, дополненное памятью (MacroHFT) Нейросети в трейдинге: Контекстно-зависимое обучение, дополненное памятью (MacroHFT)
Предлагаю познакомиться с фреймворком MacroHFT, который применяет контекстно зависимое обучение с подкреплением и память, для улучшения решений в высокочастотной торговле криптовалютами, используя макроэкономические данные и адаптивные агенты.
Нейросимвольные системы в алготрейдинге: Объединение символьных правил и нейронных сетей Нейросимвольные системы в алготрейдинге: Объединение символьных правил и нейронных сетей
Статья рассказывает об опыте разработки гибридной торговой системы, объединяющей классический технический анализ с нейронными сетями. Автор подробно разбирает архитектуру системы — от базового анализа паттернов и структуры нейросети до механизмов принятия торговых решений, делясь реальным кодом и практическими наблюдениями.
Разработка системы репликации (Часть 59): Новое будущее Разработка системы репликации (Часть 59): Новое будущее
Правильное понимание разных идей позволяет нам делать больше с наименьшими усилиями. В этой статье мы рассмотрим, почему необходимо настроить применение шаблона до того, как сервис начнет взаимодействовать с графиком. И что, если мы улучшим указатель мыши, чтобы иметь возможность делать больше вещей с его помощью?
Введение в MQL5 (Часть 8): Руководство для начинающих по созданию советников (II) Введение в MQL5 (Часть 8): Руководство для начинающих по созданию советников (II)
В этой статье рассматриваются частые вопросы, которые начинающие программисты задают на форуме MQL5. Также демонстрируются практические решения. Мы научимся совершать основные действия: покупку и продажу, получение цен свечей, а также управление торговыми аспектами, включая торговые лимиты, периоды и пороговые значения прибыли/убытка. В статье представлены пошаговые инструкции, которые помогут вам лучше понять и реализовать обсуждаемые концепции на MQL5.