Español Português
preview
От начального до среднего уровня: Навигация по песочнице

От начального до среднего уровня: Навигация по песочнице

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

Введение

В предыдущей статье, От начального до среднего уровня: Произвольный доступ (II), было показано, как мы можем работать с файлами, обеспечивая произвольный доступ к содержащимся в них данным или информации. Также объяснялось и демонстрировалось, что одна и та же концепция не всегда приводит к одному и тому же результату если смотреть исключительно на внутреннее содержимое файла. Однако, наблюдая за результатами, которые выводятся на терминал, различий между одной реализацией и другой не будет, поскольку, по сути, сама реализация позаботится о корректировке и адаптации результатов к ожидаемым.

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

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

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

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


Навигация по файлам и каталогам

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

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

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int handle;
07.     const datetime dt = D'31.10.2024 15:30:10';
08.     const int i32 = 356248;
09.     string filenames[];
10. 
11.     if (FileSelectDialog("Save as...", NULL, "All files (*.*)|*.*", FSD_WRITE_FILE, filenames, "Hello Word.txt") <= 0)
12.         return;
13. 
14.     if ((handle = FileOpen(filenames[0], FILE_WRITE| FILE_READ | FILE_ANSI)) == INVALID_HANDLE)
15.     {
16.         Print("Error...");
17.         return;
18.     };
19. 
20.     FileWrite(handle, i32, "Info", dt);
21. 
22.     FileFlush(handle);
23.     
24.     FileSeek(handle, 0, SEEK_SET);
25.     while (!FileIsEnding(handle))
26.         Print(FileTell(handle), " >> ", FileReadString(handle));
27. 
28.     FileClose(handle);
29. }
30. //+------------------------------------------------------------------+

Код 01

"Я не понимаю. Где именно в коде произошли изменения? На первый взгляд, это в точности то же самое, что и коды, которые мы рассматривали в предыдущей статье". Изменения очень незначительны и, на первый взгляд, не оказывают существенного влияния на код. Многие считают, что для разработки нового кода необходимо его радикально переработать, но на практике мы не всегда поступаем именно так. В принципе, изменение здесь очень легко понять, и оно находится в строке 11. Однако, несмотря на то, что изменение касается только строки 11, при выполнении этого кода произойдет нечто иное. Для начала функция FileSelectDialog откроет окно, как показано ниже:

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

В окне, которое мы видим на изображении 01, предоставляемом операционной системой и управляемом ею, мы можем легко визуализировать некоторые элементы. Во-первых, заголовок окна. Как видите, это тот самый заголовок, который мы указали в качестве первого аргумента функции FileSelectDialog. Поскольку второй аргумент, передаваемый функции, имеет значение NULL, мы начнём с корневого каталога песочницы. Внимание, уважаемый читатель: поскольку мы находимся внутри песочницы, МЫ НЕ СМОЖЕМ покинуть каталог, а точнее, текущий корневой каталог. Иными словами, у вас не будет возможности свободно перемещаться по всем каталогам на диске, где установлен MetaTrader 5. Таким образом, мы будем ограничены структурой каталогов текущей песочницы.

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

Хорошо, теперь нам нужно разобраться с двумя последними аргументами функции FileSelectDialog. Данная часть может немного отличаться в зависимости от типа выполняемой вами реализации. Но, по сути, пятый аргумент всегда должен быть динамическим массивом типа string. Это связано с тем, что функция заполнит этот массив данными о взаимодействии пользователя с окном, показанным на изображении 01. Последний аргумент, в свою очередь, не обязательно должен выглядеть так, как в коде 01. Однако, если вы планируете использовать конкретное имя файла, необходимо указать его здесь. Таким образом, мы наконец получим представление о том, какое имя по умолчанию будет ожидаться нашим приложением. Стоит помнить, что пользователь может изменить данное имя.

Хорошо, если всё пройдёт гладко, функция вернёт значение больше нуля. Если этого не произойдёт, значит, произошла ошибка, и нам придётся прервать работу приложения. Это делается в строке 12. Если нам это удастся, и поскольку мы хотим сохранить файл, перейдем к строке 14, где код снова будет работать так же, как и в предыдущей статье. Однако обратите внимание, что при создании или открытии файла с помощью функции FileOpen первым передаваемым аргументом является именно первое значение, содержащееся в массиве. Этот массив можно использовать так, чтобы в него загружались сразу несколько выбранных пользователем файлов. Файлы будут выбраны пользователем во время вызова из строки 11. Как уже упоминалось, вам нужно попрактиковаться, чтобы лучше понять, как использовать функцию FileSelectDialog в ваших приложениях в MetaTrader 5.

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


Навигация с помощью кода

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

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

Отлично, для начала и для того, чтобы вы могли понять, как работает этот тип навигации, мы будем исходить из того, что песочница каталога MQL5\Files пуста. Иными словами, внутри песочницы пока нет файлов или каталогов. Важно начать именно с этого принципа, чтобы всё имело смысл. Исходя из этого, мы начнем с кода, который видим ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     long    handle;
07.     string  szFileName;
08. 
09.     if ((handle = FileFindFirst("*", szFileName)) == INVALID_HANDLE)
10.     {
11.         Print("Failed...");
12.         return;
13.     }
14.     do
15.     {
16.         Print(szFileName, " is a ", FileIsExist(szFileName) ? "file ..." : "directory...");
17.     }while (FileFindNext(handle, szFileName));
18.     FileFindClose(handle);
19. 
20.     Print("Search in directory completed successfully.");
21. }
22. //+------------------------------------------------------------------+

Код 02

Запомните: все наши действия будут ограничены той песочницей, с которой мы работаем. В принципе, невозможно просматривать файлы или каталоги за пределами песочницы. Не забудьте об этом. Таким образом, при выполнении кода 02 мы получим такой результат:

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

"Боже мой, что здесь произошло? Как мог код дать сбой? Чем я заслужил это? Это может быть только божественное наказание". (СМЕХ) Успокойтесь, уважаемый читатель, давайте не будем торопиться. В коде нет никаких ошибок, всё работает отлично. "Как такое возможно? Разве вы не видите, что возникла ошибка?" Опять же, давайте не будем спешить. Вы помните, что было сказано перед началом? Таким образом, в принципе, каталог MQL5\Files, который мы здесь используем в качестве песочницы, должен быть совершенно пустым?

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

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

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

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

Итак, теперь у нас есть что-то, что можно показать. Когда мы снова выполним код 02, мы получим результат, показанный ниже:

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

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

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

Отлично, мы знаем, что при указании фильтра для функции FileFindFirst, мы можем включить путь внутри песочницы. А что, если мы преобразуем этот же код 02 в рекурсивный код? Получим ли мы желаемое поведение? Таким образом, строка 16 из кода 02 может сообщить нам имя каждого файла и его местоположение. Итак, это и есть главный вопрос, который нам необходимо решить сейчас. Стоит помнить, что существует несколько способов сделать то, что я собираюсь здесь показать. Каждый случай индивидуален.

Итак, первое, что нужно сделать, — это изменить код на что-то похожее на то, что показано ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (FileIsExist(szFileName)) Print(szFileName);
22.     }while (FileFindNext(handle, szFileName));
23.     FileFindClose(handle);
24. }
25. //+------------------------------------------------------------------+

Код 03

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

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

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

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

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

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

Помните, что во время проверки наличия косой черты в строке мы будем проверять, ссылается ли строка на каталог. А что, если мы изменим код, чтобы он использовал данную информацию? Иными словами, вместо того, чтобы игнорировать информацию о том, что строка содержит имя каталога, мы бы внесли изменение для вызова SearchIn из строки 11 с содержимым этой строки, которое, как мы знаем в данном случае, является каталогом. Что происходит? Хорошо, давайте посмотрим, как это работает на практике. Исходя из этой идеи, мы можем изменить код 03, как показано ниже:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szFileName);
23.         else
24.             Print(szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Код 04

Отлично, в коде 04 мы можем увидеть изменения, которые были внесены в код для реализации того, что было объяснено ранее. Поэтому при выполнении кода 04 мы получим совершенно иной результат, нежели тот, который мы видели на изображении 06. Но даже при этом результат будет весьма похож на то, что можно увидеть на изображении 06. Кому-то результат покажется понятным, а кто-то может быть сбит с толку. Для наглядности, вы можете посмотреть изображение 07 ниже:

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

Итак, в чём же загвоздка? Хорошо, взглянув на изображение 07, не могли бы вы сказать, к какой папке относится файл Backup.zip? Можно сказать, это папка Sub 02. Однако при более внимательном рассмотрении можно заметить, что нечто подобное произошло и с папками Sub 01 и Sub 11. "Но подождите секунду. Это оказалось гораздо сложнее, чем я себе представлял. Рассматривая изображение 04, я замечаю, что папка Sub 02 находится в корневом каталоге, как и папка Sub 01. Но, увидев это в таком виде, как показано на изображении 07, у меня создаётся впечатление, что в действительности файл Backup.zip должен находиться по пути Sub 01\Sub 11\Sub 02. Это кажется неправильным. Теперь я немного запутался".

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

Анимация 01

На изображении 01 отчетливо видна очень простая структура папок, а также файл, который не отображается на изображении 07. На первый взгляд это кажется довольно странным. На изображении 07 видно, что файл Backup.zip отображается, несмотря на то, что он находится внутри каталога. Так в чём же ошибка? Ошибка заключается в том, что в строке 22 из кода 04 мы игнорируем структуру каталогов. В действительности мы получаем доступ только к каталогам, не принимая во внимание древовидную структуру. Решение подобных задач очень простое и даже несколько тривиальное, если задуматься.

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

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szDir + szFileName);
23.         else
24.             Print(szDir, szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Код 05

Давайте теперь запустим новый код, показанный выше. В результате получается следующее.

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

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

Связано именно с особенностями взаимодействия функций FileFindFirst и FileFindNext. Суть в том, что при выполнении функции FileFindFirst система запрашивает у ОС результат, соответствующий указанному фильтру. В результате может быть получен файл или каталог. Теоретически, невозможно контролировать, что произойдет раньше. Это определяется ОС. Но проблема возникает, когда мы снова задаемся вопросом, что же является следующим элементом. Это делается с помощью функции FileFindNext. Так в чём же проблема? Хорошо, предположим, мы хотим просмотреть все файлы, прежде чем переходить к каталогам, или наоборот. Как вы могли это сделать? Помните, что мы не можем контролировать, какой тип элемента ОС вернет вам. Мы получим только этот элемент, и сами решим, что с ним делать.

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


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

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

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

Файл Описание
Code 01  Демонстрирует навигацию между папками.
Code 02   Демонстрирует навигацию между папками. 
Code 03   Демонстрирует навигацию между папками.

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

Прикрепленные файлы |
Anexo.zip (1.59 KB)
Особенности написания Пользовательских Индикаторов Особенности написания Пользовательских Индикаторов
Написание пользовательских индикаторов в торговой системе MetaTrader 4
Встраивание торговой дисциплины в код (Часть 2): Разработка механизма принудительного соблюдения дневного лимита сделок на уровне всего счета в MQL5 Встраивание торговой дисциплины в код (Часть 2): Разработка механизма принудительного соблюдения дневного лимита сделок на уровне всего счета в MQL5
Мы разработали систему, которая устанавливает ежедневный лимит на количество сделок, чтобы вы соблюдали свои торговые правила. Она отслеживает все совершенные сделки на счете и автоматически вмешивается при достижении установленного лимита, предотвращая дальнейшую активность. Благодаря интеграции контроля непосредственно в платформу, система обеспечивает поддержание дисциплины даже при повышении рыночного давления.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Теория графов: Применение алгоритма поиска в ширину (BFS) в торговой системе Теория графов: Применение алгоритма поиска в ширину (BFS) в торговой системе
Поиск в ширину (BFS) использует обход по уровням для моделирования структуры рынка как ориентированного графа свингов цен, развивающихся во времени. Анализируя исторические бары или сессии слой за слоем, BFS отдает приоритет недавнему поведению цен, при этом учитывая более глубокую рыночную память.