Ошибка, связанная с точностью представления данных. Прошу разработчиков обратить внимание!

 
Уважаемые разработчики ПО и коллеги-трейдеры!
В последних версиях торгового терминала MetaTrader4 (4.00 build 210) часто сталкиваюсь со следующей ошибкой. При выполнении команды
OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,Ask-Point*StopLoss,Ask+Point*TakeProfit,"",16384,0,CLR_NONE);


либо

OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,Bid+Point*StopLoss,Bid-Point*TakeProfit,"",16384,0,CLR_NONE);


в ряде случаев возникает ошибка


2007.10.10 11:10:09 2005.07.21 01:56 proba EURUSD,M1: OrderSend error 4107
2007.10.10 11:10:09 2005.07.21 01:56 proba EURUSD,M1: invalid price 1.21405002 for OrderSend function

а при выполнении команды

OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,CLR_NONE);


либо

OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,CLR_NONE);


возникает ошибка


2007.10.10 11:09:56 2005.01.13 04:00 proba EURUSD,M1: OrderClose error 4107
2007.10.10 11:09:56 2005.01.13 04:00 proba EURUSD,M1: invalid price 1.32475007 for OrderClose function

Исходя из этого, можно предположить, что предопределенные переменные Ask и Bid иногда принимают значение с точностью 8 знаков после десятичной точки, вместо четырех, несмотря на то, что в исторических данных все котировки имеют четыре знака после десятичной точки (и количество цифр после десятичной точки в цене финансового инструмента согласно его свойствам тоже равно четрем).

При выполнении следующего фрагмента программы

            if(Bid>=OrderOpenPrice()+Point*Level1 && OrderOpenPrice()>OrderStopLoss())
              {
               Print("Buy order, OpenPrice: ",OrderOpenPrice(),", StopLoss: ",OrderStopLoss());
               OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0);
               return(0);
              }


либо

            if(Ask<=OrderOpenPrice()-Point*Level1 && OrderOpenPrice()<OrderStopLoss())
              {
               Print("Sell order, OpenPrice: ",OrderOpenPrice(),", StopLoss: ",OrderStopLoss());
               OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0);
               return(0);
              }


в log-файле видим следующее


2007.10.10 11:30:47 2004.09.09 09:21 proba EURUSD,M1: OrderModify error 1
2007.10.10 11:30:47 2004.09.09 09:21 proba EURUSD,M1: Buy order, OpenPrice: 1.2172, StopLoss: 1.2172

либо

2007.10.10 11:34:40 2005.01.06 16:14 proba EURUSD,M1: OrderModify error 1
2007.10.10 11:34:40 2005.01.06 16:14 proba EURUSD,M1: Sell order, OpenPrice: 1.3206, StopLoss: 1.3206

То есть, выполняется условие OrderOpenPrice() БОЛЬШЕ OrderStopLoss() или OrderOpenPrice() МЕНЬШЕ OrderStopLoss(), а команда Print() выводит одинаковые значения для них и команда OrderModify() воспринимает их как равные и дает ошибку.

По этой проблеме я обращался в службу поддержки MetaQuotes при помощи формы на сайте, но ответа так и не получил. Прошу разобраться и устранить указанную выше ошибку.
С уважением, Денис Дмитриевич.

 
Если Вы подозреваете, что точность значений,выводимых в лог, больше 4, то используйте не просто
Print(A);

, а

Print(DoubleToString(A,8));


Кроме того, ошибка с кодом один возникает, когда новое и старое значение StopLoss или TakeProfit равны с точностью до пункта. Почитайте ветку "MQL4: Automated Trading Championship 2007: распространенные ошибки в экспертах"

 
Так как MarketInfo(symbol,MODE_DIGITS) = 4, то и значения OrderOpenPrice(), OrderStopLoss() и OrderTakeProfit() должны иметь точность до 4-х знаков после десятичной точки. Откуда берутся значения значения более высокой точности, откуда берутся дробные пункты?

Логично предположить, что при подаче команды
Print(A);

результат будет выводиться с точностью переменной A, то есть, если A имеет 8 значащих знаков после десятичной точки - будут выводиться все восемь.

 
Вы проверьте, у меня есть своя теория на сей счет.
 
Меня больше волнует проблема с ошибкой "invalid price 1.21405002 for OrderSend " при комманде "OrderSend(...,Bid,...);" и "invalid price 1.32475007 for OrderClose" при комманде "OrderClose(...,Bid,...);", но ответа я пока так и не получил...
Может быть это MetaTrader4 так иммитирует Requote? :-)
 
какая-то логика в твоих суждениях есть, но еще есть другие технические аспекты касающиеся хранения вещественных чисел, если тебе интересно можно хотябы этот форум покопать, вот недавно, показывал как правильно обрабатывать твою ситуацию, на первой страничке еще висит, а если порыть, то наверно уже немерянно раз отвечали по этому поводу
"OrderModify error 1"
 
Проблема в том, что хранятся не нормализованные данные, которые не нравятся тестеру. При этом автор сначала делал проверку простым выводом подозрительного значения в Print(). После того, как вывод стал делаться через DoubleToStr() с точностью до восьми занков, это стало очевидно. Следующий шаг :

- либо номализовать предварительно свою историю
- либо загрузить нормализованную историю
- либо предварительно нормализовать в эксперте все исторические данные перед вызовом торговых функций.
 
Это мы сейчас проверим.
Напишем простой скрипт, читающий данные из файла EURUSD1.hst и записывающий их в текстовый файл:
int start()
  {
   int handle_rd,handle_wr,cnt;
   
   handle_wr=FileOpen("OutHistory.txt",FILE_BIN|FILE_WRITE);
   handle_rd=FileOpenHistory("EURUSD1.hst",FILE_BIN);

   FileWrite(handle_wr,"Version: "+FileReadInteger(handle_rd,LONG_VALUE));
   FileWrite(handle_wr,"Copyright: "+FileReadString(handle_rd,64));
   FileWrite(handle_wr,"Symbol: "+FileReadString(handle_rd,12));
   FileWrite(handle_wr,"Period: "+FileReadInteger(handle_rd,LONG_VALUE));
   FileWrite(handle_wr,"Digits: "+FileReadInteger(handle_rd,LONG_VALUE));
   FileWrite(handle_wr,"TimeSign: "+TimeToStr(FileReadInteger(handle_rd,LONG_VALUE)));
   FileWrite(handle_wr,"LastSync: "+TimeToStr(FileReadInteger(handle_rd,LONG_VALUE)));

   for(cnt=1;cnt<=13;cnt++)
     {FileReadInteger(handle_rd,LONG_VALUE);}

   FileWrite(handle_wr,"   Date    Time     Open       Low        High       Close      Volume");

   for(;FileIsEnding(handle_rd)==0;)
     {FileWrite(handle_wr,TimeToStr(FileReadInteger(handle_rd,LONG_VALUE))+" "+FileReadDouble(handle_rd,DOUBLE_VALUE)+" "+FileReadDouble(handle_rd,DOUBLE_VALUE)+" "+FileReadDouble(handle_rd,DOUBLE_VALUE)+" "+FileReadDouble(handle_rd,DOUBLE_VALUE)+" "+FileReadDouble(handle_rd,DOUBLE_VALUE));}


   FileClose(handle_rd);
   FileClose(handle_wr);
   return(0);
  }


Запускаем. Смотрим результат:

Version: 400
Copyright: (C)opyright 2003, MetaQuotes Software Corp.
Symbol: EURUSD
Period: 1
Digits: 4
TimeSign: 2007.10.09 20:47
LastSync: 1970.01.01 00:00
   Date    Time     Open       Low        High       Close      Volume
2004.06.16 10:55 1.21130002 1.21120000 1.21150005 1.21149993 15.00000000
2004.06.16 10:56 1.21149993 1.21140003 1.21160007 1.21149993 10.00000000
2004.06.16 10:57 1.21149993 1.21089995 1.21150005 1.21089995 21.00000000
2004.06.16 10:58 1.21099997 1.21010005 1.21100008 1.21019995 23.00000000
2004.06.16 10:59 1.21009994 1.21000004 1.21040010 1.21019995 15.00000000
2004.06.16 11:00 1.21019995 1.20990002 1.21030009 1.21009994 24.00000000
2004.06.16 11:01 1.20999992 1.20990002 1.21040010 1.21039999 21.00000000
2004.06.16 11:02 1.21039999 1.21019995 1.21050000 1.21050000 15.00000000
2004.06.16 11:03 1.21039999 1.21019995 1.21060002 1.21019995 14.00000000 


Действительно, вы правы, Rosh. Интересно, почему известный ДЦ выкладывает историю в таком виде (ненормализированно). Кстати, текущие данные и данные, загружаемые с сервера при перемещении по графику, нормализированные:

Version: 400
Copyright: (C)opyright 2003, MetaQuotes Software Corp.
Symbol: EURUSD
Period: 1
Digits: 4
TimeSign: 2007.10.12 18:30
LastSync: 1970.01.01 00:00
   Date    Time     Open       Low        High       Close      Volume
2007.10.10 07:23 1.41080000 1.41070000 1.41080000 1.41080000 5.00000000
2007.10.10 07:25 1.41070000 1.41070000 1.41080000 1.41080000 2.00000000
2007.10.10 07:26 1.41070000 1.41070000 1.41090000 1.41090000 5.00000000
2007.10.10 07:27 1.41080000 1.41080000 1.41090000 1.41090000 2.00000000
2007.10.10 07:28 1.41100000 1.41090000 1.41110000 1.41110000 4.00000000
2007.10.10 07:29 1.41120000 1.41110000 1.41120000 1.41110000 6.00000000


Было бы разумно, чтобы значения предопределенных переменных и функций, содержащих цену (Ask, Bid, OrderOpenPrice(), OrderStopLoss(), OrderTakeProfit(), ...) округлялись путем
NormalizeToDouble(переменная,Digits);
автоматически.

 
 
Почитайте про Ask, Bid , и по каким ценам открываются отложенные ордера и закрываются рыночные. Лучше самостоятельно.
 
Уважаемый Rosh.
Обратите, пожалуйста, внимание на то, что на прилагаемом рисунке цена Bid=0.6567, Ask=0.6569. TakeProfit короткой позиции (#4) имеет значение 0.6569 и при этой цене он должен был исполнен. Цена открытия ордера BuyLimit (#5) имеет значение 0.6569, при указаной выше цене он тоже должен был открыться.