Ошибки, баги, вопросы - страница 442

 
voix_kas:

Есть ли у кого готовый код вычисления количество значащих цифр для объема?
Что-то типа SymbolInfoInteger(_Symbol, SYMBOL_DIGITS), но только для объема.
Например, для случая SymbolInfoDouble(  _Symbol, SYMBOL_VOLUME_STEP) = "1.0" - ответ будет "0", для "0.1" - "1", для "0.01" - "2" и т.д.

Уточню нюанс. Для шага объема типа "0.1", "0.01", "0.001" у меня есть.

Код должен работать для следующих случаев, например, "0.2", "0.11", 0.023" и др.

Для объёма конкретно нету. Есть для чего угодно.

int CountSignedDigits(double x)
{  
  for(int i=0; i<1000; i++,x*=10) if(x-MathFloor(x)<DBL_MIN*2) return i;
  return -1;
}
Скрипт для проверки в прицепе.
Файлы:
_UniTest.mq5  2 kb
 
MetaDriver:
Скрипт для проверки в прицепе.
ты про это..., а я подумал что надо проверить допустимый лот до того, как выставить ордер.
 
sergeev:
ты про это..., а я подумал что надо проверить допустимый лот до того, как выставить ордер.

;)

Я не знаю на самом деле чего ему надо.. Посмотрим, небось отпишется.  Эт я так - в телепатии тренируюсь. ;)

 
voix_kas:

Есть ли у кого готовый код вычисления количество значащих цифр для объема?
Что-то типа SymbolInfoInteger(_Symbol, SYMBOL_DIGITS), но только для объема.
Например, для случая SymbolInfoDouble(  _Symbol, SYMBOL_VOLUME_STEP) = "1.0" - ответ будет "0", для "0.1" - "1", для "0.01" - "2" и т.д.

Уточню нюанс. Для шага объема типа "0.1", "0.01", "0.001" у меня есть.
Код должен работать для следующих случаев, например, "0.2", "0.11", 0.023" и др.

Конкретно для объёмов можно просто:

      int N=0;
      double step=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
      if(step-1.0<0)  N++;
      if(step-0.1<0)  N++;
      if(step-0.01<0) N++;
 

sergeev
MetaDriver
Valmars

Качественно сформулированный вопрос - половина ответа. :) Извиняюсь, уже ложился спать, неточно описал задачу. Попробую еще раз.

Речь идет про передачу в торговый приказ нормализированного объема.
Как мы делаем это делаем с ценой:

MqlTradeRequest TradeRequest;
...
TradeRequest.volume = NormalizeDouble(Volume, GetVolumeDigits(_Symbol));
TradeRequest.price  = NormalizeDouble(Price, SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
...

Нормализация цены ("price") - думаю, всем понятна.

В свое время (еще с МТ4), где-то в статьях МТ читал, что желательно нормализировать еще и объем.
Собственно, для того, чтобы выяснить самый младший разряд объема, который возможен по условиям брокера, написал функцию GetVolumeDigits(string Symbol). Реализации ее, как минимум, две (результат одинаковый):
Реализация №1.

int GetVolumeDigits(string Symbol) {
  int VolumeDigits = 0;
  double VolumeStep = SymbolInfoDouble(Symbol, SYMBOL_VOLUME_STEP);
  while (VolumeStep < 1) {
    VolumeStep *= 10;
    VolumeDigits++;
  }
  return VolumeDigits;
}
Реализация №2.

int GetVolumeDigits(string Symbol) {
  return (int)MathLog10(1.0 / SymbolInfoDouble(Symbol, SYMBOL_VOLUME_STEP));
}

Оба варианта отлично справляются с вариантами, при которых минимальный шаг = 1.0, 0.1, 0.01, 0.001 и т.д. Т.е. если мин.шаг равен 1.0, функция вернет 0; при шаге 0.1, функция вернет 1 и т.д.
Что делать, если минимальный шаг равен, например, 1.1 или 0.11, или 0.011? Данный алгоритм неверно покажет младший значащий разряд.
Можно, конечно, утверждать, что таких случаев в практике нет. Просто хотелось в советнике учесть такую гипотетическую возможность. Думал, может, кто поделиться наработками в этом нюансе...

 
voix_kas:
Ага, понял, нужно, чтоб результат был кратен VolumeStep. Ну, так Digits тут не причём, сначала посчитали объём с учётом  Digits, а потом уменьшили до ближайшего кратного  VolumeStep.
 
voix_kas:

Речь идет про передачу в торговый приказ нормализированного объема.
Просто хотелось в советнике учесть такую гипотетическую возможность.

а по какой "гипотетический" инструмент идёт речь?

1. Вариант от MetaDriver подходит вам. CountSignedDigits покажет количество знаков в любом лоте.

2. Зная число знаков dig нормализацию можете провести так:

double MinLot; // минимальный лот по символу
double MaxLot; // максимальный лот по символу
double LotStep; // шаг лота по символу
int dig; // знаковость лота узнали из функции CountSignedDigits

double NL(double lot)
{
  if (lot<=MinLot) return(MinLot); // проверка на минимальный
  double d=MathFloor((lot-MinLot)/StepLot); // сколько ЦЕЛЫХ шагов умещается в проверяемом лоте
  lot=MinLot+StepLot*d; // рассчитали по этому целому числу
  lot=MathMin(lot, MaxLot); lot=NormalizeDouble(lot, dig);// не забыли проверить на максимальный // нормализовали
  return(lot); // вернули
}
 

sergeev
Благодарю за функцию проверки валидности лота. Использую аналогичную конструкцию/ветвление проверок.
Мой вопрос акцентирован на определении самого младшего разряда в лоте, чтобы по нему нормализацию проводить.
В частности, MetaDriver привел свою конструкцию для "всего". :) Однако, она не лишена недостатков (либо мой компилятор глючит). Ниже привожу код и результат выполнения:

void OnStart() {
  Print(CountSignedDigits(110.0));
  Print(CountSignedDigits(11.0));
  Print(CountSignedDigits(1.1));
  Print(CountSignedDigits(0.11));
  Print(CountSignedDigits(0.011));
  Print(CountSignedDigits(0.0011));
  Print(CountSignedDigits(0.00011));
}

int CountSignedDigits(double x) {  
  for (int i = 0; i < 1000; i++, x *= 10)
    if (x - MathFloor(x) < DBL_MIN * 2)
      return i;
  return -1;
}

Результат:

2011.07.03 13:15:21     test (EURUSD,M5)        5
2011.07.03 13:15:21     test (EURUSD,M5)        4
2011.07.03 13:15:21     test (EURUSD,M5)        18      -    Здесь только у меня бяка вылазиет?
2011.07.03 13:15:21     test (EURUSD,M5)        2
2011.07.03 13:15:21     test (EURUSD,M5)        1
2011.07.03 13:15:21     test (EURUSD,M5)        0
2011.07.03 13:15:21     test (EURUSD,M5)        0

Следующий вариант (функция CountSignedDigits та же):

void OnStart() {
  double value = 110.0;
  int count = 9;
  while (count) {
    Print(DoubleToString(value), " - ", CountSignedDigits(value));
    value /= 10;
    count--;
  }
}

Результат:

2011.07.03 13:23:32     test (EURUSD,M5)        0.00000110 - 22       -   Почему-то здесь бяка...
2011.07.03 13:23:32     test (EURUSD,M5)        0.00001100 - 21       -
2011.07.03 13:23:32     test (EURUSD,M5)        0.00011000 - 5
2011.07.03 13:23:32     test (EURUSD,M5)        0.00110000 - 4
2011.07.03 13:23:32     test (EURUSD,M5)        0.01100000 - 3        - Здесь уже все нормально. Почему результаты разные?!
2011.07.03 13:23:32     test (EURUSD,M5)        0.11000000 - 2
2011.07.03 13:23:32     test (EURUSD,M5)        1.10000000 - 1
2011.07.03 13:23:32     test (EURUSD,M5)        11.00000000 - 0
2011.07.03 13:23:32     test (EURUSD,M5)        110.00000000 - 0
 

Изменил в OnStart следующую строку: 

double value = 210.0;

Результат:

2011.07.03 13:28:01     test (EURUSD,M5)        0.00000021 - 23
2011.07.03 13:28:01     test (EURUSD,M5)        0.00000210 - 22
2011.07.03 13:28:01     test (EURUSD,M5)        0.00002100 - 21
2011.07.03 13:28:01     test (EURUSD,M5)        0.00021000 - 20
2011.07.03 13:28:01     test (EURUSD,M5)        0.00210000 - 19
2011.07.03 13:28:01     test (EURUSD,M5)        0.02100000 - 3
2011.07.03 13:28:01     test (EURUSD,M5)        0.21000000 - 2
2011.07.03 13:28:01     test (EURUSD,M5)        2.10000000 - 1
2011.07.03 13:28:01     test (EURUSD,M5)        21.00000000 - 0
2011.07.03 13:28:01     test (EURUSD,M5)        210.00000000 - 0

Либо что-то я неправильно делаю (прошу поправить), либо многоуважаемый MetaDriver допустил ошибку в теории (при проектировании алгоритма). 

 
voix_kas:

Мой вопрос акцентирован на определении самого младшего разряда в лоте, чтобы по нему нормализацию проводить.

Не нужно определять dig для лота, достаточно нормализовать его до нужного шага:
   lot = NormalizeDouble( lot / lot_step, 0 ) * lot_step;
   if ( lot < lot_min ) lot = lot_min;
   if ( lot > lot_max ) lot = lot_max;


Даже если при передаче торгового запроса в переменную lot попадет мусор (в надцатом знаке после запятой), он должен будет отсеятся самим терминалом.

По крайней мере, у меня за несколько лет использования такой конструкции проблем не возникало.


А если хочется перестраховаться, можно воткнуть нормализацию до 8-го (с запасом) знака после запятой - если после "правильной" нормализации и появится мусор, то он будет намного дальше.

Документация по MQL5: Стандартные константы, перечисления и структуры / Структуры данных / Структура торгового запроса
Документация по MQL5: Стандартные константы, перечисления и структуры / Структуры данных / Структура торгового запроса
  • www.mql5.com
Стандартные константы, перечисления и структуры / Структуры данных / Структура торгового запроса - Документация по MQL5
Причина обращения: