Errors, bugs, questions - page 442

 
voix_kas:

Does anyone have ready code to calculate the number of significant digits for a volume?
Something like SymbolInfoInteger(_Symbol, SYMBOL_DIGITS), but only for volume.
For example, for the case SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP) = "1.0" - the answer would be "0", for "0.1" - "1", for "0.01" - "2" etc.

Let me clarify a nuance. For a volume step like "0.1", "0.01", "0.001" I have.

The code should work for the following cases like "0.2", "0.11", 0.023" etc.

There is no code specificallyfor volume. There is for anything.

int CountSignedDigits(double x)
{  
  for(int i=0; i<1000; i++,x*=10) if(x-MathFloor(x)<DBL_MIN*2) return i;
  return -1;
}
The script is for checking in the trailer.
Files:
_UniTest.mq5  2 kb
 
MetaDriver:
A script to check in the trailer.
You mean that..., I thought I should check the acceptable lot before placing an order.
 
sergeev:
You mean that..., and I thought I should check the allowable lot before placing an order.

;)

I don't really know what he wants. We'll see what he says. I'm just practising my telepathy. ;)

 
voix_kas:

Does anyone have ready-made code for calculating the number of significant digits for a volume?
Something like SymbolInfoInteger(_Symbol, SYMBOL_DIGITS), but only for volume.
For example, for the case SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP) = "1.0" - the answer would be "0", for "0.1" - "1", for "0.01" - "2" etc.

Let me clarify a nuance. For a volume step like "0.1", "0.01", "0.001" I have.
The code should work for the following cases like "0.2", "0.11", 0.023" etc.

Specifically for volumes can be simple:

      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

Well-formulated question is half the answer. :) Sorry, I went to bed already, I failed to describe the task accurately. I will try again.

I'm talking about passing a normalized volume to a trade order.
It is what we do with the price:

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

Price normalisation - I think it's clear to everyone.

At my time (since MT4), I read somewhere in MT articles that it would be desirable to normalize the volume as well.
Actually, I wrote the functionGetVolumeDigits(string Symbol) to find the smallest possible value of volume according to broker's conditions. There are at least two implementations (the result is the same):
Implementation #1.

int GetVolumeDigits(string Symbol) {
  int VolumeDigits = 0;
  double VolumeStep = SymbolInfoDouble(Symbol, SYMBOL_VOLUME_STEP);
  while (VolumeStep < 1) {
    VolumeStep *= 10;
    VolumeDigits++;
  }
  return VolumeDigits;
}
Implementation №2.

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

Both of them perfectly work for variants with min step = 1.0, 0.1, 0.01, 0.001, etc. That is, if the minimum step is 1.0, the function will return 0; if the step is 0.1, the function will return 1, etc.
What if the minimum step is 1.1, or 0.11, or 0.011, for example? This algorithm will incorrectly show the least significant digit.
Of course, you can assert that there are no such cases in practice. I want just to consider such a hypothetical possibility in my Expert Advisor. I thought that maybe someone would share their experience in this matter...

 
voix_kas:
Yeah, I get it, you want the result to be a multiple of VolumeStep. Well, it has nothing to do with Digits, first calculate the volume with Digits and then reduce it to the nearest multiple of VolumeStep.
 
voix_kas:

It's about sending the normalized volume to the trade order.
I just want to consider this hypothetical possibility in our Expert Advisor.

which "hypothetical" tool are we talking about?

1. The variant from MetaDriver is suitable for you. CountSignedDigits will show the number of characters in any lot.

2. Knowing the number of dig dig its you can do the normalisation like this:

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
Thanks for the lot validation function. I'm using a similar construction/branching of checks.
My question is focused on finding the youngest place in the lot, to normalize it.
In particular, MetaDriver gave his construction for "everything". :) However, it is not without flaws (or my compiler is glitchy). Below is the code and execution result:

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;
}

Result:

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

Next option (CountSignedDigits function is the same):

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

Result:

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
 

Changed the following line in OnStart:

double value = 210.0;

Result:

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

Either I'm doing something wrong (please correct), or MetaDriver made a mistake in theory (when designing the algorithm).

 
voix_kas:

My question is focused on determining the lowest place in the lot to normalize it.

You don't need to define dig for the lot, just normalise it to the right step:
   lot = NormalizeDouble( lot / lot_step, 0 ) * lot_step;
   if ( lot < lot_min ) lot = lot_min;
   if ( lot > lot_max ) lot = lot_max;


Even if when sending a trade request, the variable lot will get rubbish (in the second decimal place), it will be rejected by the terminal itself.

At least, I haven't had any problems during several years of using this design.


And if you want to reinsure, you can normalize it to 8th decimal place (with reserve) - if after "correct" normalization trash appears, it will be much further.

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