Как-то раз решил перенести свой советник с МТ4 на МТ5. И все было по началу хорошо, пока не обнаружил странное поведение в коде. При помощи записи состояния всех переменных стратегий в лог я выяснил, что некоторые условия срабатывали тогда, когда не надо. И наоборот, некоторые условия не срабатывали.
Самый простой пример:
double a = 5; double b = 10; if (a > b) { }
В любом языке программирования такое условие не выполнится. Но в MQL5 подобные условия иногда выполняются. И от чего это зависит — не понятно.
Тогда мне помогло лишь одно: я переехал с терминала МТ5 от брокера Альпари (он не хотел обновляться до свежей версии) на оригинальный МТ5 последней (на тот момент) версии. И это помогло, подобные баги исчезли. Менять что либо в коде было бесполезно.
И вот недавно я решился сделать заказ для знакомого. По началу все шло хорошо, но вот захотелось добавить асинхронное открытие и закрытие сделок. Казалось бы, что может быть проще?
Опустим такую деталь, что в очень удобном МТ5 нет специальной переменной в запросе, чтобы можно было однозначно судить о том, ответ на какой именно запрос открыть позицию пришел от сервера. Для этих целей есть только магик и комментарий к ордеру. Поэтому уже на этом этапе делаем костыль в виде записи специального числа в комментарии к сделке. Но это ладно, жить можно. Подумаешь, что почти в любом API есть обычно специальная переменная для передачи пользовательских данных. Ну решили в МТ5 такое не делать.
И вот значит встает вопрос, что иногда сделки не открываются с первого раза. Да и не всегда закрываются. Значит, нужно добавить повторные попытки открыть/закрыть позицию. Казалось бы, что может быть проще. Но MT5 не был бы MT5, если бы все было просто. Я бы лучше на C++ писал все, дайте мне REST API, поток котировок, чем вот это вот все.
Потому что имеем следующее:
pos_info.error++; const int close_error = pos_info.error; Print("-close-error ", symbol, " magic ", m_magic, " ticket ", ticket, " uid ", unique_id, " num ", close_error, " attempts ", m_open_attempts); if (close_error > m_open_attempts) { Print("-1-close-error; errors ", close_error); Print("-1-close-error; attempts ", m_open_attempts); break; } if (close_error == m_open_attempts) { Print("-2-close-error; errors ", close_error); Print("-2-close-error; attempts ", m_open_attempts); } if (close_error != m_open_attempts) { Print("-3-close-error; errors ", close_error); Print("-3-close-error; attempts ", m_open_attempts); } if (close_error < m_open_attempts) { Print("-4-close-error; errors ", close_error); Print("-4-close-error; attempts ", m_open_attempts); } if (close_error > m_open_attempts) { pos_info.state = TradePositionState::POSITION_CLOSE_ERROR; on_close_position_error(m_magic); on_close_position(m_magic, symbol, pos_info.type, result); remove_position(symbol, unique_id); Print("-4-remove ", symbol, " magic ", m_magic, " ticket ", ticket, " uid ", unique_id); break; }
Переменная close_error содержит 1, так как ошибка при закрытии позиции возникла 1 раз. Это видно в терминале в соответствующем сообщении. Переменная m_open_attempts содержит 5. Внимание, вопрос: какие условия сработают в этом коде?
Правильный ответ
Условия:
if (close_error > m_open_attempts) { Print("-1-close-error; errors ", close_error); Print("-1-close-error; attempts ", m_open_attempts); break; } if (close_error == m_open_attempts) { Print("-2-close-error; errors ", close_error); Print("-2-close-error; attempts ", m_open_attempts); }Не сработают, что логично.
Условия:
if (close_error != m_open_attempts) { Print("-3-close-error; errors ", close_error); Print("-3-close-error; attempts ", m_open_attempts); } if (close_error < m_open_attempts) { Print("-4-close-error; errors ", close_error); Print("-4-close-error; attempts ", m_open_attempts); }
Сработают. И условие:
if (close_error > m_open_attempts) { pos_info.state = TradePositionState::POSITION_CLOSE_ERROR; on_close_position_error(m_magic); on_close_position(m_magic, symbol, pos_info.type, result); remove_position(symbol, unique_id); Print("-4-remove ", symbol, " magic ", m_magic, " ticket ", ticket, " uid ", unique_id); break; }
Тоже сработает!
Тут кто-то заметит, что есть
break;
Потому что сами условия находятся в switch. Возможно, это запретная магия, и для одного case условия должен быть один break в конце, и его нельзя писать внутри условий if {}. Я не знаю, буду проверять, хотя как это может влиять на поведение условия… Отключение оптимизации — не помогает.
Попробовал поискать информацию о таких ошибках в интернетах. Нашел такое упоминание. И по сути, это все.
P.S.
Сегодня (15.05.2023) вышло обновление МТ5 (билд 3730), после чего баг исчез.
На MQL тоже, но ближе к телу.)
Про АПИ на MQL лучше не писать.))
Что-то вы не договариваете. Хотя если терминал был не оригинальный, а доработанный брокером, то это брокер мог накосячить.
Вот уж почти 10 лет работаю с MT5, подобных ошибок от компилятора никогда не встречал.
Когда встречалась «магия», каждый раз вскоре убеждался, что из-за собственной криворукости.
(А вот в API и библиотеках баги есть, это да.)
Быть может m_open_attempts вы изменяете асинхронно показному примеру, и пока исполнение кода добегает до последнего условия, он там уже другой. Вы как раз его не принтуете.
Асинхронщина она вообще такая, если ее программировать только изредка, она по башке часто будет бить. Я бы рыл в этом направлении