Неожиданный результат в PositionGetDouble(POSITION_VOLUME) - страница 2

 
Rich:

Можно делать так:

Проведём небольшой эксперимент с PositionSelect() для случая отсутствия позиции:

void OnStart()
{
  Print("PositionSelect(Symbol() = ", Symbol(), ") = ", PositionSelect(Symbol()));
  Print("GetLastError() = ", GetLastError());
}

/* Вывод в лог (хронология - сверху вниз):
MJ      0       1 (EURUSD,M15)  23:06:14        PositionSelect(Symbol() = EURUSD) = false
PL      0       1 (EURUSD,M15)  23:06:14        GetLastError() = 4753
*/

Коду 4753 соответствует ERR_TRADE_POSITION_NOT_FOUND. Можно написать свою функцию-обёртку, эмулирующую этот случай как наличие позиции нулевого размера.

И вообще, - написать обёртки ко многим функциям библиотеки MQL5. И пользоваться только обёртками.

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

/* Получаем размер позиции в удобной нам парадигме (позиция есть всегда) */
bool PositionGetVolume(string sym, double &vol)
{
  ResetLastError(); /* Убираем глупости */

  if(PositionSelect(sym)) /* Теперь 1 раз можно вызвать PositionGetDouble() */
  { /* Здесь ResetLastError() вызывать не нужно, потому что PositionSelect() выполнилась успешно */
    if(!PositionGetDouble(POSITION_VOLUME, vol))
      return false;
  }
  else
  {
    if(GetLastError() == ERR_TRADE_POSITION_NOT_FOUND)
      vol = 0; /* Смена парадигмы: эмуляция наличия позиции нулевого размера */
    else
      return false;
  }

  return true;
}

/* Получаем максимальный размер позиции в удобной нам парадигме (неограниченный = DBL_MAX) */
bool SymbolInfoVolumeLimit(string sym, double &lim)
{
  ResetLastError(); /* Убираем глупости */

  if(!SymbolInfoDouble(sym, SYMBOL_VOLUME_LIMIT, lim))
    return false;

  if(lim == 0) /* Корректируем глупости */
    lim = DBL_MAX;

  return true;
}

/* Эта функция должна быть серьёзно переработана, данный вариант - лишь затравка */
bool UpdatePositionOneStep()
{
  MqlTradeRequest     Request = { /* Сюда поместить правильные значения */ };
  MqlTradeCheckResult Check   = { /* Сюда поместить правильные значения */ };
  MqlTradeResult      Result  = { /* Сюда поместить правильные значения */ };

  ResetLastError(); /* Убираем глупости */

  if(!OrderCheck(Request, Check) || !OrderSend(Request, Result))
  {
    Print("Не удалось навалить в позицию столько, сколько хотелось, код ошибки: ", GetLastError());
    return false;
  }

  /* Здесь нужно дождаться результата OrderSend(), но нормального решения нет */
  if(! /* IsOrderProcessesSuccessfully() */ true)
  {
    Print("Сервер не дал навалить в позицию столько, сколько хотелось");
    return false;
  }

  return true;
}

bool UpdatePosition(double req)
{
  double cur = 0;
  double lim = 0;

  /* Не следует пытаться увеличить позицию сверх возможного */
  if(!SymbolInfoVolumeLimit(Symbol(), lim) || req > lim)
    return false;

  if(!PositionGetVolume(Symbol(), cur))
  {
    Print("Не получается узнать размер позиции");
    return false;
  }

  while(cur < req)
  {
    if(!UpdatePositionOneStep())
    {
      Print("Не получается выполнить шаг увеличения позиции");
      return false;
    }

    if(!PositionGetVolume(Symbol(), cur))
    {
      Print("Не получается узнать размер позиции");
      return false;
    }
  }

  return true;
}

void OnStart()
{
  if(/* Условие открытия сделки */ true)
  {
    double req = 5;

    if(UpdatePosition(req))
    {
      /* ... */
      Print("Updated OK");
    }
    else
    {
      /* ... */
      Print("Updating FAILED");
    }
  }
}

/* Вывод в лог (хронология - сверху вниз):
CP      0       1 (EURUSD,M15)  23:17:40        Не удалось навалить в позицию столько, сколько хотелось, код ошибки: 4753
OE      0       1 (EURUSD,M15)  23:17:40        Не получается выполнить шаг увеличения позиции
MF      0       1 (EURUSD,M15)  23:17:40        Updating FAILED
*/

Для UpdatePositionOneStep() нормального решения нет даже от разработчиков. Модель исполнения - асинхронная, то есть, тот факт, что OrderSend() выполнилась успешно, означает лишь, что запрос сервером принят (или только лишь принят терминалом для последующей отправки серверу) успешно. Нормальных удобных механизмов для отслеживания судьбы подобного запроса разработчиками не предусмотрено. Предлагаются какие-то костыли, вроде цикла ожидания-проверки не очевидных параметров с вызовом Sleep(), да с течением времени наблюдаются метания между полностью асинхронной и полуасинхронной моделями (то timeout скроют от пользователя и увеличат, то вообще уберут).

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

 
simpleton:

Проведём небольшой эксперимент с PositionSelect() для случая отсутствия позиции:

Коду 4753 соответствует ERR_TRADE_POSITION_NOT_FOUND. Можно написать свою функцию-обёртку, эмулирующую этот случай как наличие позиции нулевого размера.

И вообще, - написать обёртки ко многим функциям библиотеки MQL5. И пользоваться только обёртками.

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

Для UpdatePositionOneStep() нормального решения нет даже от разработчиков. Модель исполнения - асинхронная, то есть, тот факт, что OrderSend() выполнилась успешно, означает лишь, что запрос сервером принят (или только лишь принят терминалом для последующей отправки серверу) успешно. Нормальных удобных механизмов для отслеживания судьбы подобного запроса разработчиками не предусмотрено. Предлагаются какие-то костыли, вроде цикла ожидания-проверки не очевидных параметров с вызовом Sleep(), да с течением времени наблюдаются метания между полностью асинхронной и полуасинхронной моделями (то timeout скроют от пользователя и увеличат, то вообще уберут).

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

Обратите внимание на функцию OnTrade , через неё решаются задачи с отслеживанием судьбы запроса.
 
simpleton, спасибо за ценные идеи!
Причина обращения: