marketeer: По исходнику можете посмотреть, что реквоты обрабатываются правильно - по крайней мере аналогичным образом, как в других пятерочных исходниках. После первой ошибки реквоты поступают новые цены, они подставляются в следующий запрос, но ошибка остается. Причем при всех последующих попытках рефреш возвращает уже одни и те же цены. Количество попыток не важно - можно пытаться отрефрешиться до бесконечности. Очень похоже на баг в тестере.
Очень похоже на баг в программе. Бегло просмотрел, по моему она находится здесь:
switch(cmd)
{
case OP_BUY:
request.type = ORDER_TYPE_BUY;
case OP_SELL:
request.type = ORDER_TYPE_SELL;
request.action = TRADE_ACTION_DEAL;
break;
case OP_BUYLIMIT:
request.type = ORDER_TYPE_BUY_LIMIT;
case OP_SELLLIMIT:
request.type = ORDER_TYPE_SELL_LIMIT;
case OP_BUYSTOP:
request.type = ORDER_TYPE_BUY_STOP;
case OP_SELLSTOP:
request.type = ORDER_TYPE_SELL_STOP;
request.action = TRADE_ACTION_PENDING;
break;
}
Ордера на покупку переквалифицируются как ордера на продажу, так как за оператором case: OP_BUY тут же выполняется case: OP_SELL_. Это же видно и из лога: устанавливается ордер OP_SELL,
2) Как в тестере просмотреть позиции на чартах? По умолчанию открывается только чарт валюты, на которой запускался эксперт, но он же многовалютный. И как на графике с результатами тестирования получить инфу, где какая сделка была проведена, где какая позиция создавалась/поменялась? Сейчас график совершенно неинформативный. Всплывающих подсказок нет. Клики на нем никакой контекстной инфы не выводят.
Терминал еще будет дорабатываться, мы только выпустили платформу. Все разумное и полезное будет добавляться.
Дополнительные вопросы. 1) В библиотеке делается попытка получить идентификатор сделки для только что открытой позиции из result.deal, но там почему-то всегда ноль. Нужно это, чтобы в идущем следом вызове HistoryDealGetInteger(result.deal, DEAL_POSITION_ID, LID); получить идентификатор самой позиции. В общем, вопрос - как получить id позиции, "не отходя от кассы"?
Так как торговые операции выполняются асинхронно, то Вам придется подождать момента, когда позиция будет открыта (если Вам непременно нужно получить IВ позиции сразу же после отправки OrderSend()). Вот примерный код:
//+------------------------------------------------------------------+//| Check_DEAL_POSITION_ID_after_Open.mq5 |//| Copyright 2010, MetaQuotes Software Corp. |//| http://www.mql5.com |//+------------------------------------------------------------------+#property copyright "Copyright 2010, MetaQuotes Software Corp."#property link "http://www.mql5.com"#property version "1.00"//+------------------------------------------------------------------+//| Expert initialization function |//+------------------------------------------------------------------+intOnInit()
{
//---//---return(0);
}
//+------------------------------------------------------------------+//| Expert deinitialization function |//+------------------------------------------------------------------+voidOnDeinit(constint reason)
{
//---
}
//+------------------------------------------------------------------+//| Expert tick function |//+------------------------------------------------------------------+voidOnTick()
{
//---staticbool opened=false;
if(!opened)
{
MqlTick tick;
if(SymbolInfoTick(Symbol(),tick));
MqlTradeRequest request;
request.symbol=Symbol();
request.type=ORDER_TYPE_BUY; //ORDER_TYPE_BUY; //cmd; // ВОТ ЗДЕСЬ !!!
request.volume=0.1;
request.price=tick.ask;
request.deviation=50;
request.sl=0;
request.tp=0;
request.action=TRADE_ACTION_DEAL;
request.order=0;
request.comment="Test";
MqlTradeResult result;
if(OrderSend(request,result))
{
long posID=-1;
int counter=0;
ResetLastError();
//--- пытаемся выбрать позицию с интервалом в 50 миллисекундwhile(!PositionSelect(Symbol()) && !IsStopped())
{
counter++;
bool stopped=IsStopped();
//--- выведем текущее состояниеPrint(counter,": positions=",PositionsTotal()," error=",GetLastError()," IsStopped()=",stopped);
//--- больше 100 попыток делать бессмысленноif(counter>100) break;
ResetLastError();
//--- заснем на 50 миллисекундSleep(50);
}
//--- будем считать, что позиция выбрана успешно - теперь можно получить ID розицииPositionGetInteger(POSITION_IDENTIFIER,posID);
Print("posID=",posID);
opened=true;
}
else
{
Print("Не удалось совершить покупку. Код ответа=",result.retcode,", Ошибка ",GetLastError());
}
}
}
//+------------------------------------------------------------------+
Вторй вариант - запросить ID позиции, к которой относится сделка. Выглядит чуть короче, но желательно все равно проверять результат выполнения HistoryDealSelect():
//+------------------------------------------------------------------+//| Check_DEAL_POSITION_ID_after_Open.mq5 |//| Copyright 2010, MetaQuotes Software Corp. |//| http://www.mql5.com |//+------------------------------------------------------------------+#property copyright "Copyright 2010, MetaQuotes Software Corp."#property link "http://www.mql5.com"#property version "1.00"//+------------------------------------------------------------------+//| Expert tick function |//+------------------------------------------------------------------+voidOnTick()
{
//---staticbool opened=false;
if(!opened)
{
MqlTick tick;
if(SymbolInfoTick(Symbol(),tick));
MqlTradeRequest request;
request.symbol=Symbol();
request.type=ORDER_TYPE_BUY; //ORDER_TYPE_BUY; //cmd; // ВОТ ЗДЕСЬ !!!
request.volume=0.1;
request.price=tick.ask;
request.deviation=50;
request.sl=0;
request.tp=0;
request.action=TRADE_ACTION_DEAL;
request.order=0;
request.comment="Test";
MqlTradeResult result;
if(OrderSend(request,result))
{
long posID=-1;
ResetLastError();
ulong deal=result.deal;
//--- запросим всю историю HistorySelect(0,TimeCurrent());
HistoryDealSelect(deal);
HistoryDealGetInteger(deal,DEAL_POSITION_ID,posID);
Print("posID=",posID);
opened=true;
}
else
{
Print("Не удалось совершить покупку. Код ответа=",result.retcode,", Ошибка ",GetLastError());
}
}
}
//+------------------------------------------------------------------+
Я сделал проверку в небольшом цикле по первому варианту, потому что этот второй вроде бы не работает - result.deal равно нулю после OrderSend. Соответственно HistoryDealSelect ничего не выделит. Попутно возникает принципиальный вопрос, зачем вызывать HistoryDealSelect, если в HistoryDealGetInteger явным образом указывается тот же самый id сделки?
Так как торговые операции выполняются асинхронно, то Вам придется подождать момента, когда позиция будет открыта (если Вам непременно нужно получить IВ позиции сразу же после отправки OrderSend()). Вот примерный код:
Вот этот кусочек очень интересен:
if(SymbolInfoTick(Symbol(),tick));
Для чего здесь "if"?
Далее, если SymbolInfoTick() завершится неуспешно, - какой смысл в последующем присваивании мусора (ведь изначально переменная tick неинициализирована)?
request.price=tick.ask;
Какой смысл в последующем вызове OrderSend(), если ей передаются ошибочные данные (тот самый мусор)?
Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:
Функция PositionSelect() работает с таймаутом. Если
запрашиваемые данные уже готовы, то они отдаются сразу без ожидания. В противном
случае на подготовку запрошенных данных отводится фиксированный таймаут в 3
секунды. Как только данные получены функция тут же завершает свою работу и
возвращает результат.
Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?
И в довершение, Вы в своём коде, который многие стараются брать за образец (как же, - код от разработчиков!), вставляете комментарии вида:
//--- будем считать, что позиция выбрана успешно - теперь можно получить ID розиции
А ведь совсем несложно было грамотно написать этот пример, чтобы не надо было "считать", а можно было бы в это месте, в случае, если до него дойдёт управление, иметь гарантию успешного выбора позиции, а не "будем считать".
Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.
Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:
Функция PositionSelect() работает с таймаутом. Если
запрашиваемые данные уже готовы, то они отдаются сразу без ожидания. В противном
случае на подготовку запрошенных данных отводится фиксированный таймаут в 3
секунды. Как только данные получены функция тут же завершает свою работу и
возвращает результат.
Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?
Terminal: При запуске терминала с ключом /config конфигурационный файл открывается только на чтение.
Terminal: Исправлено сканирование точек доступа при первом запуске клиентского терминала.
Terminal: Исправлено падение терминала при массовой перекомпиляции MQL5-программ.
Terminal: Исправлено рисование графического объекта Fibonacci Retracement.
Terminal: Исправлена обработка некорректного запроса в диалоге просмотра журнала терминала.
Tester: Добавлена дефрагментация файлов исторической базы.
Tester: Исправлено рисование графика результатов тестирования.
MQL5:
Исправлена и оптимизирована работа с торговой историей - устранены
конфликты при параллельной работе нескольких экспертов и их влияние на
вкладку "История" панели инструментов.
Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.
Да, я сразу предупредил, что это примерный код. Вы можете представить свой вариант со всеми проверками и комментариями. Думаю, форумяне скажут спасибо.
Для авторизации и пользования сайтом MQL5.com необходимо разрешить использование файлов Сookie.
Пожалуйста, включите в вашем браузере данную настройку, иначе вы не сможете авторизоваться.
Вы вошли в аккаунт. Двухфакторная аутентификация отключена. Настройте её заново и отсканируйте новый QR-код или продолжите с отключённой двухфакторной аутентификацией.
По исходнику можете посмотреть, что реквоты обрабатываются правильно - по крайней мере аналогичным образом, как в других пятерочных исходниках. После первой ошибки реквоты поступают новые цены, они подставляются в следующий запрос, но ошибка остается. Причем при всех последующих попытках рефреш возвращает уже одни и те же цены. Количество попыток не важно - можно пытаться отрефрешиться до бесконечности. Очень похоже на баг в тестере.
Очень похоже на баг в программе. Бегло просмотрел, по моему она находится здесь:
Ордера на покупку переквалифицируются как ордера на продажу, так как за оператором case: OP_BUY тут же выполняется case: OP_SELL_. Это же видно и из лога: устанавливается ордер OP_SELL,
а цена берётся ask.
Это же касается и отложенных ордеров.
Да, для каждого case нужен свой break. https://www.mql5.com/ru/docs/basis/operators/switch
Супер. Спасибо всем за помощь. Был невнимателен в новом фрагменте кода.
А что относительно доп. вопросов? Есть для них ответы?
2) Как в тестере просмотреть позиции на чартах? По умолчанию открывается только чарт валюты, на которой запускался эксперт, но он же многовалютный. И как на графике с результатами тестирования получить инфу, где какая сделка была проведена, где какая позиция создавалась/поменялась? Сейчас график совершенно неинформативный. Всплывающих подсказок нет. Клики на нем никакой контекстной инфы не выводят.
Дополнительные вопросы. 1) В библиотеке делается попытка получить идентификатор сделки для только что открытой позиции из result.deal, но там почему-то всегда ноль. Нужно это, чтобы в идущем следом вызове HistoryDealGetInteger(result.deal, DEAL_POSITION_ID, LID); получить идентификатор самой позиции. В общем, вопрос - как получить id позиции, "не отходя от кассы"?
Так как торговые операции выполняются асинхронно, то Вам придется подождать момента, когда позиция будет открыта (если Вам непременно нужно получить IВ позиции сразу же после отправки OrderSend()). Вот примерный код:
Вторй вариант - запросить ID позиции, к которой относится сделка. Выглядит чуть короче, но желательно все равно проверять результат выполнения HistoryDealSelect():
Так как торговые операции выполняются асинхронно, то Вам придется подождать момента, когда позиция будет открыта (если Вам непременно нужно получить IВ позиции сразу же после отправки OrderSend()). Вот примерный код:
Вот этот кусочек очень интересен:
Для чего здесь "if"?
Далее, если SymbolInfoTick() завершится неуспешно, - какой смысл в последующем присваивании мусора (ведь изначально переменная tick неинициализирована)?
Какой смысл в последующем вызове OrderSend(), если ей передаются ошибочные данные (тот самый мусор)?
Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:
Функция PositionSelect() работает с таймаутом. Если запрашиваемые данные уже готовы, то они отдаются сразу без ожидания. В противном случае на подготовку запрошенных данных отводится фиксированный таймаут в 3 секунды. Как только данные получены функция тут же завершает свою работу и возвращает результат.
Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?
И в довершение, Вы в своём коде, который многие стараются брать за образец (как же, - код от разработчиков!), вставляете комментарии вида:
//--- будем считать, что позиция выбрана успешно - теперь можно получить ID розицииА ведь совсем несложно было грамотно написать этот пример, чтобы не надо было "считать", а можно было бы в это месте, в случае, если до него дойдёт управление, иметь гарантию успешного выбора позиции, а не "будем считать".
Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.
Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:
Функция PositionSelect() работает с таймаутом. Если запрашиваемые данные уже готовы, то они отдаются сразу без ожидания. В противном случае на подготовку запрошенных данных отводится фиксированный таймаут в 3 секунды. Как только данные получены функция тут же завершает свою работу и возвращает результат.
Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?
Таймауты для торговых функций были убраны (https://www.mql5.com/ru/forum/23/page7):
MetaTrader 5 Client Terminal build 306
Вот этот кусочек очень интересен:
Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.