LifeHack для трейдеров Смешивание ForEach с определениями (#define) Статьи по MQL5

LifeHack для трейдеров: смешивание ForEach с определениями (#define)

— Что делает тебя крутым, брат? — Определения делают тебя крутым, братан.

Вы все еще пишете на MQL4 и хотите перейти на MQL5? Мы покажем вам, с чего начать! Теперь вы можете комфортно работать в MQL5 MetaEditor и при этом использовать нотацию MQL4 (на самом деле такая возможность появилась немного раньше, хотя в этой статье я хочу дать более полное и подробное описание того, как перенести функции MQL4 в MQL5).

Хороший программист — ленивый программист.

Создание советников почти всегда связано с большой работой с циклами. Циклы окружают нас повсюду: поиск ордеров, сделки в истории, объекты графиков, символы обзора рынка, бары в индикаторном буфере. Чтобы облегчить жизнь программисту, в MetaEditor есть фрагменты, означающие, что когда вы вводите первые символы, они автоматически превращаются в небольшой фрагмент кода после нажатия клавиши Tab. Вот как работает фрагмент цикла for:

Неплохо, но не покрывает все наши потребности. Рассмотрим простейший пример: предположим, что нам нужно перебрать все символы Market Watch..

Было бы здорово разработать сниппет MetaEditor, начинающийся с fes (for_each_symbol) и разворачивающийся в следующий блок:

В MetaEditor нет настраиваемых сниппетов, поэтому мы применим «определения». Макрозамена #define была изобретена ленивыми умными программистами, преследовавшими несколько целей. Среди них простота чтения и удобство написания повторяющегося кода..

Многие языки программирования, помимо стандартного цикла for, имеют его вариации, например: for (element: Collection) или for each (идентификатор типа в выражении). Если бы мы могли написать следующий код.

, жизнь программиста была бы немного проще. В Интернете можно найти противников и сторонников такого подхода. Здесь я покажу вам, как сделать то же самое с макросом #define..

Начнем с простой задачи — получить названия всех символов обзора рынка. Давайте начнем и напишем следующий макрос:

Компилятор прекрасно понимает эту запись, не возвращая ошибок. Начинаем отладку нажатием F5 и видим, что что-то пошло не так:

Проблема в том, что выражение s = SymbolName (i, true) в цикле for вычисляется после итерации, а наша переменная s не инициализируется на первой итерации, когда i = 0. инструкция ‘for’:

Оператор for состоит из трех выражений и исполняемого оператора:

for (выражение1; выражение2; выражение3) оператор;

Выражение 1 описывает инициализацию цикла. Выражение2 — проверка условия завершения цикла. Если это «истина», то выполняется оператор тела цикла for. Все повторяется до тех пор, пока выражение2 не станет «ложным». Если это «ложь», цикл завершается, и управление передается следующему оператору. Выражение ‡ вычисляется после каждой итерации. .

Процесс прост. Сделаем пару правок:

и получите нужный результат. Мы разработали макрос ForEachSymbol с параметрами символа и индекса, как если бы это был обычный цикл for, и работали с этими переменными в теле псевдопетля, как если бы они уже были объявлены и инициализированы с использованием необходимых значений. Таким образом, мы можем получить желаемые свойства символов обзора рынка с помощью функций SymbolInfoXXX (). Например:

Теперь мы можем написать аналогичный макрос для поиска графических объектов на графике:

Строка определения макроса ForEachObject стала немного длиннее. Кроме того, однострочный код замены сложнее понять. Но оказывается, что и этот вопрос уже решен: определение макроса теперь можно разделить на строки с помощью обратной косой черты ‘\’. Результат такой:

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

Начнем с поиска заказов. Сюда добавлена ​​только функция выбора истории HistorySelect ():

Вы можете заметить, что в этом макросе (и двух предыдущих) нет обработки ошибок. Например, что, если HistorySelect () вернет false? В этом случае мы не сможем пройти через все заказы в цикле. Кроме того, кто на самом деле анализирует результат выполнения HistorySelect ()? Таким образом, этот макрос не содержит ничего, что могло бы быть запрещено при обычном способе разработки программы..

Самая серьезная критика использования #define заключается в том, что макроподстановки не позволяют выполнять отладку кода. Я согласен с этим, хотя, как говорит fxsaber, "Надежно зафиксированному пациенту не требуется анестезия. Отлаженный макрос не требует отладки.".

Далее аналогично разработаем макрос для поиска позиций:

Искать сделки в истории:

Искать заказы в истории:

Соберите все макроподстановки в один файл ForEach.mqh4:

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

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

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

Как видите, значение индексной переменной здесь изменяется с size-1 на 0. Мы завершили знакомство с #define. Теперь пора разработать функции для удобного доступа в стиле MQL4..

1. Какие группы функций MQL4 описаны в статье.

Примечание. Замените такие переменные, как Point, Digits и Bar на Point (), Digits () и Bar (Symbol (), Period ()).

Группы MQL4 AccountXXXX, MQL4 MarketInfo, MQL4 Status check и MQL4 Predefined переменных должны быть преобразованы в MQL5. Таким образом, четыре файла: AccountInfo.mqh, MarketInfo.mqh, Check.mqh и Predefined.mqh должны быть добавлены в [папка даты] \ MQL5 \ Include \ SimpleCall \. В папке находятся семь файлов для преобразования функций MQL4 в MQL5: AccountInfo.mqh, Check.mqh, IndicatorsMQL4.mqh, IndicatorsMQL5.mqh, MarketInfo.mqh, Predefined.mqh и Series.mqh. .

Вы должны включить все эти файлы. Также обратите внимание на ограничение: файлы IndicatorsMQL4.mqh и IndicatorsMQL5.mqh нельзя включать вместе — вы можете выбрать только один из них. Таким образом, в папке есть два файла: SimpleCallMQL4.mqh включает все файлы плюс IndicatorsMQL4.mqh и SimpleCallMQL5.mqh включает все файлы плюс IndicatorsMQL5.mqh. .

Пример включения на основе MACD Sample.mq4.

Скопируйте MACD Sample.mq4 в папку MQL5 с советниками — например, в [папка данных] \ MQL5 \ Experts \, и измените расширение файла на mq5. Таким образом, мы получаем файл MACD Sample.mq5. Скомпилируйте и получите 59 ошибок и одно предупреждение.

Теперь подключите SimpleCallMQL4.mqh:

Скомпилируйте снова и получите 39 ошибок и одно предупреждение. Теперь вручную замените (Ctrl + H) полосы на полосы (символ (), период ()) и точку на точку (). Скомпилировать. Осталось 35 ошибок. Все они связаны с торговыми функциями. Но мы не будем говорить о торговых функциях в этой статье..

1.1. Счет MQL4XXXX.

Функции MQL4 AccountXXXX конвертируются в файл [папка даты] \ MQL5 \ Include \ SimpleCall \ AccountInfo.mqh.

Таблица соответствия функций MQL4 и MQL5 выглядит следующим образом:

MQL4 MQL5 AccountInfoXXXX MQL5 CAccountInfo Примечания AccountInfoDouble AccountBfoDouble CAccountInfo :: InfoDouble или CAccountInfo :: double методы AccountInfoInteger AccountInfoInteger CAccountInfo :: InfoInteger или CAccountInfoInteger CAccountInfo :: InfoInteger или CAccountInfo :: целочисленные методы AccountInfoString AccountInfoString или CAccountInfo :: целочисленные методы AccountInfoString AccountInfoString или CAccountInfo :: integer методы AccountInfoString AccountInfoString InfoString CAfoccountInance (методы AccountInfoString или CAccountInfo) : Баланс AccountCredit AccountInfoDouble (ACCOUNT_CREDIT) или CAccountInfo :: Credit AccountCompany AccountInfoString (ACCOUNT_COMPANY) или CAccountInfo :: Company AccountCurrency AccountInfoString (ACCOUNT_CURRENCY) или CAccountInfo :: Currency AccountEquity AccountInfoDouble (ACCOUNT_CURRENCY) или CAccountInfo :: Currency AccountEquity AccountInfoDouble (ACCOUNT_CURRENCY) или CAccountInfo :: Currency AccountEquity AccountInfoDouble (ACCOUNT) : FreeMargin AccountFreeMarginCheck — / — CAccountInfo :: FreeMarginCheck AccountFreeMarginMode Нет эквивалента Нет эквивалента Нет эквивалента AccountLeverage AccountInfoInteger (ACCOUNT_LEVERAGE) CAccountInfo :: Leverage В MQL4 он имеет int t ype, в MQL5 это long AccountMargin AccountInfoDouble (ACCOUNT_MARGIN) CAccountInfo :: Margin AccountName AccountInfoString (ACCOUNT_NAME) CAccountInfo :: Name AccountNumber AccountInfoInteger (ACCOUNT_LOGIN) CAccountInfo :: Login В MQL4 он имеет тип int, в MQL4 он имеет тип int, в MQL4 это long AccountProfit AccountInfoDouble (ACCOUNT_PROFIT) CAccountInfo :: Прибыль AccountServer AccountInfoString (ACCOUNT_SERVER) CAccountInfo :: Сервер AccountStopoutLevel AccountInfoDouble (ACCOUNT_MARGIN_SO_SO) CAccountInfo :: MarginStopOut В MQL4, он имеет тип INT, в MQL5, это двойной AccountStopoutMode AccountInfoInteger (ACCOUNT_MARGIN_SO_MODE) CAccountInfo :: StopoutMode.

Обратите внимание, что MQL5 не имеет эквивалента для MQL4 AccountFreeMarginMode. В дальнейшем вы используете MQL4 AccountFreeMarginMode на свой страх и риск. При обнаружении MQL4 AccountFreeMarginMode в лог отправляется предупреждение и NaN ("не число") возвращается.

Для остальных функций MQL4 AccountXXXX есть эквиваленты в двух версиях: через AccountInfoXXXX или через торговый класс CAccountInfo. Для AccountInfoDouble, AccountInfoInteger и AccountInfoString нет различий между MQL4 и MQL5..

Заголовок файла имеет следующий код. Как это работает?

Во-первых, давайте посмотрим на #define help:

Директива #define может использоваться для присвоения мнемонических имен константам. Есть две формы:

Директива #define заменяет выражение на все найденные далее записи идентификатора в исходном тексте..

В случае нашего кода это описание выглядит следующим образом (мы использовали форму без параметров): директива #define заменяет ORDER_TYPE_BUY или все дальнейшие найденные записи OP_BUY в исходном тексте. Директива #define заменяет ORDER_TYPE_SELL на все найденные далее записи OP_SELL в исходном тексте. Другими словами, после включения файла [папка даты] \ MQL5 \ Include \ SimpleCall \ AccountInfo.mqh в ваш советник MQL5, вы можете использовать типы OP_BUY и OP_SELL MQL4 привычным способом. Компилятор не вернет ошибку.

Итак, первая группа функций, которую мы переносим в тип MQL5: AccountBalance (), AccountCredit (), AccountCompany (), AccountCurrency (), AccountEquity () и AccountFreeMargin ():

Здесь в функциях MQL4 XXXX (void) используется параметрическая форма #define, где "пустота" действует как параметр. Это легко проверить: если мы удалим "пустота", мы получили "неожиданно в списке параметров формата макроса" ошибка при компиляции:

В случае MQL4 AccountFreeMarginCheck мы поступим иначе — установим AccountFreeMarginCheck как обычную функцию, в которой используется только код MQL5:

Как мы уже говорили выше, AccountFreeMarginMode не имеет эквивалента в MQL5, поэтому, "не число" и выдается предупреждение, когда в коде обнаруживается AccountFreeMarginMode:

Для остальных функций MQL4 поступаем аналогично:

1.2. MQL4 MarketInfo.

Функции MQL4 MarketInfotXXXX конвертируются в файл [папка даты] \ MQL5 \ Include \ SimpleCall \ MarketInfo.mqh.

MQL4 MarketInfo имеет тип double, но в MQL5 эквиваленты MarketInfo присутствуют в SymbolInfoInteger () (получить тип long) и в SymbolInfoDouble () (получить тип double). Здесь мы можем ясно заметить неудобство использования устаревшей функции MarketInfo (преобразование типов). На примере MQL5 SYMBOL_DIGITS:

MarketInfo (Symbol (), MODE_DIGITS) double) SymbolInfoInteger (symbol, SYMBOL_DIGITS)

1.2.1 Неопределенность с MQL4 MODE_TRADEALLOWED.

В MQL4 это простой флаг bool, а в MQL5 символ может иметь несколько видов разрешений / запретов:

ENUM_SYMBOL_TRADE_MODE.

ID Описание SYMBOL_TRADE_MODE_DISABLED Отключить торговлю по символу SYMBOL_TRADE_MODE_LONGONLY Разрешить только покупки SYMBOL_TRADE_MODE_SHORTONLY Включить только продажи SYMBOL_TRADE_MODE_CLOSEONLY Включить только закрытие YMBOL_TRADE_MODE_FULL ограничения торговли.

Я предлагаю false только в случае SYMBOL_TRADE_MODE_DISABLED и true для частичных ограничений или полного доступа (с предупреждением Alert и Print о частичных ограничениях).

1.2.2. Неопределенность с MQL4 MODE_SWAPTYPE.

В MQL4 MODE_SWAPTYPE возвращает только четыре значения (метод расчета свопа. 0 — в пунктах; 1 — в базовой валюте символа; 2 — в%; 3 — в валюте маржинальных средств), тогда как в MQL5 перечисление ENUM_SYMBOL_SWAP_MODE содержит девять значений, имеющих значения аналогично MQL4:

MQL4 MODE_SWAPTYPE MQL5 ENUM_SYMBOL_SWAP_MODE Нет эквивалент SYMBOL_SWAP_MODE_DISABLED 0 — в точках SYMBOL_SWAP_MODE_POINTS 1 — в базовой валюте символа SYMBOL_SWAP_MODE_CURRENCY_SYMBOL 3 — в маржинальные фонды валюты SYMBOL_SWAP_MODE_CURRENCY_MARGIN Нет эквивалента SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT 2 — в% SYMBOL_SWAP_MODE_INTEREST_CURRENT 2 — в% SYMBOL_SWAP_MODE_INTEREST_OPEN Нет эквивалентного SYMBOL_SWAP_MODE_REOPEN_CURRENT Нет эквивалентной SYMBOL_SWAP_MODE_REOPEN_BID.

В MQL5 может быть два варианта расчета свопов в%:

Будем рассматривать их как один вид. Для других опций MQL5, не имеющих аналогов в MQL4, выдается предупреждение и "не число" возвращается.

1.2.3. Неопределенность с MQL4 MODE_PROFITCALCMODE и MODE_MARGINCALCMODE.

В MQL4 MODE_PROFITCALCMODE (метод расчета прибыли) возвращает только три значения: 0 — Forex; 1 — CFD; 2 — Futures, а MODE_MARGINCALCMODE (метод расчета маржи) возвращает четыре: 0 — Forex; 1 — CFD; 2 — Фьючерсы; 3 — CFD на индексы. В MQL5 можно определить метод расчета маржинальных средств для инструмента (перечисление ENUM_SYMBOL_CALC_MODE), но нет возможности рассчитать прибыль. Я предполагаю, что в MQL5 метод расчета маржинальных средств совпадает с методом расчета прибыли, поэтому аналогичное значение с MQL5 ENUM_SYMBOL_CALC_MODE возвращается для MQL4 MODE_PROFITCALCMODE и MODE_MARGINCALCMODE.

Перечисление MQL5 ENUM_SYMBOL_CALC_MODE содержит десять методов. Сравним MQL4 MODE_PROFITCALCMODE с MQL5 ENUM_SYMBOL_CALC_MODE:

MQL4 MODE_PROFITCALCMODE "Форекс" MQL5 SYMBOL_CALC_MODE_FOREX.

MQL4 MODE_PROFITCALCMODE "CFD" MQL5 SYMBOL_CALC_MODE_CFD.

MQL4 MODE_PROFITCALCMODE "Фьючерсы" MQL5 SYMBOL_CALC_MODE_FUTURES.

Для других опций MQL5, не имеющих аналогов в MQL4, выдается предупреждение и "не число" возвращается:

1.3. Проверка статуса MQL4.

Функция проверки статуса MQL4 конвертируется в файл [папка даты] \ MQL5 \ Include \ SimpleCall \ Check.mqh.

Он включает в себя следующие элементы:

Классы Digits Точка IsConnected IsDemo IsDllsAllowed IsExpertEnabled IsLibrariesAllowed IsOptimization IsTesting IsTradeAllowed IsTradeContextBusy IsVisualMode TerminalCompany TerminalName TerminalPath MQL4 MQL5 MQL5 Примечание Digits MQL4 позволяет использовать цифры и цифры () одновременно точка MQL4 позволяет использовать и точку () одновременно IsConnected TerminalInfoInteger (TERMINAL_CONNECTED) CTerminalInfo :: IsConnected IsDemo AccountInfoInteger (ACCOUNT_TRADE_MODE) CAccountInfo :: TradeMode Получить один из значений из ENUM_ACCOUNT_TRADE_MODE перечисления IsDllsAllowed TerminalInfoInteger (TERMINAL_DLLS_ALLOWED) и MQLInfoInteger (MQL_DLLS_ALLOWED) CTerminalInfo :: IsDLLsAllowed TERMINAL_DLLS_ALLOWED имеет самый высокий статус, в то время как MQL_DLLS_ALLOWED можно пренебречь IsExpertEnabled TerminalInfoInteger (TERMINAL_TRADE_ALLOWED) CTerminalInfo :: IsTradeAllowed Состояние кнопки AutoTrading терминала IsLibrariesAllowed MQLInfoInteger (MQL_DLLS_ALLOWED) — / — Проверка бессмысленна: если программа применяет D LL и вы не разрешаете их использовать (вкладка dependencies программы), вы просто не сможете запустить программу. IsOptimization MQLInfoInteger (MQL_OPTIMIZATION) — / — Программа MQL5 имеет четыре режима: отладка, профилирование кода, тестирование и оптимизация IsTesting MQLInfoInteger (MQL_TESTER) — / — Программа MQL5 имеет четыре режима: отладка, профилирование кода, тестер SQL и оптимизация IsTraIndeAllowed ) — /- "Разрешить автоматическую торговлю" статус чекбокса в свойствах программы IsTradeContextBusy — / — — /- "ложный" возвращается IsVisualMode MQLInfoInteger (MQL_VISUAL_MODE) Программа MQL5 имеет четыре режима: отладка, профилирование кода, тестирование и оптимизация..

Первые два пункта (Digits и Point) реализовать нельзя, так как здесь полностью перепутаны MQL4 и MQL5. В частности, MQL4 может одновременно работать с Digits и Digits (), а также Point и Point (). Например, я не знаю, как преобразовать Digits и Digits () в Digits () с помощью ‘define’. Остальные точки находятся как XXXX () и могут быть заменены эквивалентами MQL5..

Реализация следующая:

1.4. Предопределенные переменные MQL4.

Реализация в файле [папка данных] \ MQL5 \ Include \ SimpleCall \ Predefined.mqh.

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

_Digits _Point _LastError _Period _RandomSeed _StopFlag _Symbol _UninitReason Ask Bars Bid Close Digits High Low Open Point Time Volume.

Предопределенные переменные _XXXX преобразуются в функции MQL5 с использованием непараметрической формы #define:

Единственное исключение сделано для "_Случайное зерно" — эта переменная хранит текущий статус генератора псевдослучайных целых чисел. Его нельзя конвертировать в MQL5 для Bars (точнее, Bars оставлен на замену вручную). Для цифр и точек решения нет. Как упоминалось выше, Цифры и Цифры (), а также Точка и Точка () могут быть найдены в тексте одновременно..

MQL4 Ask и Bid заменены пользовательскими (самописными) функциями GetAsk () и GetBid ():

Конечно, мы могли бы написать макрос для Ask и более простым способом:

Но в примечании к SymbolInfoDouble говорится:

Если функция используется для получения данных на последнем тике, лучше применить SymbolInfoTick (). Возможно, по символу нет котировок, так как терминал подключен к торговому счету. В этом случае запрошенное значение будет неопределенным..

В большинстве случаев достаточно использовать функцию SymbolInfoTick (), которая позволяет получить значения Ask, Bid, Last и Volume за один вызов, а также время прихода последнего тика..

Теперь давайте представим что-то новое — используйте "оператор"

Ключевое слово ‘operator’ будет использоваться для перегрузки (переназначения) оператора индексации []. Это необходимо для перевода массивов таймсерий MQL4 (Open [], High [], Low [], Close [], Time [], Volume []) в форму MQL5..

Вот о чем нам сообщает справка "оператор":

Перегрузка операций позволяет использовать операционную нотацию (записанную в виде простых выражений) для сложных объектов — структур и классов..

Таким образом, мы можем предположить, что нам нужно будет создать класс для перегрузки оператора индексации [].

Директива #define может использоваться для присвоения мнемонических имен константам. Есть две формы:

Директива #define заменяет выражение на все найденные далее записи идентификатора в исходном тексте..

следующий код можно прочитать как: директива #define заменяет 159 для всех дальнейших найденных записей в исходном тексте.

Другими словами, код в OnStart преобразуется в:

Здесь весь класс помещен в #define,

Эту замену можно представить следующим образом:

Другими словами, в OnStart мы фактически ссылаемся на объект Volume класса CVolume, на метод [], куда мы передаем индекс i. Тот же принцип применяется к сериям MQL4 Open, High, Low, Close и Time..

Наконец, у нас есть функции MQL4 iXXX: iOpen, iHigh, iLow, iClose, iTime и iVolume. Мы должны применить для них метод объявления пользовательской функции.

Пример для iClose:

2. Изменения в других файлах.

В [папка данных] \ MQL5 \ Include \ SimpleCall \ IndicatorsMQL4 .mqh теперь все имена строк MQL4 заносятся в заголовок:

В [папка данных] \ MQL5 \ Include \ SimpleCall \ Series.mqh мы удалили.

Теперь они записаны в [папка данных] \ MQL5 \ Include \ SimpleCall \ Header.mqh:

а также iClose, iHigh, iLow, iOpen, iTime и iVolume — теперь они устанавливаются в [папка данных] \ MQL5 \ Include \ SimpleCall \ Predefined.mqh.

Заключение.

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

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

Только упрощенные торговые функции MQL4 отсутствуют для полной совместимости. Но и этот вопрос решаем. В заключение повторим плюсы и минусы этого подхода:

ограничение обработки возвращаемой ошибки при обращении к индикаторам; падение скорости тестирования при одновременном доступе к нескольким индикаторам; необходимость правильного выделения линий индикатора в зависимости от того, подключен IndicatorsMQL5.mqh или IndicatorsMQL4.mqh; невозможность отладки макро-подстановки #define; нет всплывающей подсказки для параметрических #define arguments; потенциальные столкновения переменных, скрытых за макросами. Плюсы простота написания кода — одна строка вместо нескольких; наглядность и лаконичность — чем меньше кода, тем легче его понять; макроподстановки выделены красным, что упрощает просмотр идентификаторов пользователей и функций; возможность разрабатывать собственные эквиваленты сниппетов.

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

Похожие статьи