Может стоит причесать? - страница 2

 
Mikhail Dovbakh:
Я, откровенно говоря, не совсем понял о чем Вы говорите? Мне не нравится «разношертность» не платформ, а неряшливые отличия в языке MQL.

Ну чем они  неряшливые-то ? Они просто разные. Можно так, можно иначе. Может появиться и еще какой-то вариант.

Чтобы не зависеть от данных особенностей конкретной версии языка - существуют стандартные интерфейсы. По идее, Стандартная Библиотека - это именно такой набор классов и интерфейсов (уж очень она мне напоминает библиотеку MS MFC). Но, увы, в СБ идея стандартизации интерфейсов не доведена до логического завершения, в МТ4 и МТ5 - многие классы существенно различны. Поэтому, на мой взгляд, у каждого программиста должны существовать свои шаблоны интерфейсов, с которыми он и работает. В том числе и "обертки" для функций объединения строк, раз уж они в разных версиях разные.

Для примера, вот мой класс-интерфейс торговой позиции:

class CTradePositionI: public CMyObject
{
public:
   // Возвращает число компонент позиции внутри позиции (может быть нулевым если позиции нет) или WRONG_VALUE в случае ошибок
   virtual int Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT) = 0;

   // Получение числа компонент и интерфейс отдельной компоненты
   virtual uint GetComponentNum() = 0;
   virtual CTradePosComponentI* GetComponent(uint uiComponentIdx) = 0;

};

Моя библиотека возвращает только чисто виртуальные интерфейсы, одинаково работающие (с точки зрения советника) во всех платформах. Конкретная реализация спрятана за виртуальными функциями.

Вы запрашиваете позицию по указанному символу и магику, получаете интерфейс CTradePositionI. У этого интерфейса можете запросить число компонент, и перебрать эти компоненты. При запросе компоненты - вы опять же, получаете чисто виртуальный интерфейс CTradePosComponentI, у которого можете запросить объем, цену открытия, ТП-СЛ, и все остальное. Компонента позиции в конечном итоге эквивалентна ордеру на МТ4, и отдельной позиции на МТ5 - но для логики советника это не играет роли, он отдает торговые приказы через такой же чисто виртуальный интерфейс - и совершенно не зависит от конкретной платформы. В дальнейшем у меня есть задумка использовать WLD, и С# - весь написанный код должен будет нормально работать и там, добавятся только соответствующие классы-обертки, согласовывающие вот этот мой виртуальный интерфейс с реальным интерфейсом WLD

 

на самом деле очень мало отличий кроме работы с ордерами - работы на 30 минут через поиск и автозамену с кодом в 4к строк, изи, лениво покуривая

а строки вообще просто сложить можно, и вообще использовать приведение типов а не стринг то дабл и проч. 

 

Я еще раз повторюсь. 

Торговое окружение платформ накладывает определенные требования/ограничения, о чем говорилось в первом посте. И Ваш подход по решению проблем совместимости понятен, и думаю, что правильный.

Однако, я о другом - согласитесь, что  функции поиска почему то разные:


MT5MT4
int  ArrayMaximum( 
   const void&   array[],             // массив для поиска 
   int           start=0,             // с какого индекса начинаем поиск 
   int           count=WHOLE_ARRAY    // количество проверяемых 
   );
int  ArrayMaximum( 
   const void&   array[],             // массив для поиска 
   int           count=WHOLE_ARRAY,   // количество проверяемых 
   int           start=0              // с какого индекса начинаем поиск 
   );

 Не знаю, как подобные «мины»\различия можно чем то разумным объяснить.

 
Mikhail Dovbakh:

Я еще раз повторюсь. 

Торговое окружение платформ накладывает определенные требования/ограничения, о чем говорилось в первом посте. И Ваш подход по решению проблем совместимости понятен, и думаю, что правильный.

Однако, я о другом - согласитесь, что  функции поиска почему то разные:

 Не знаю, как подобные «мины»\различия можно чем то разумным объяснить.

Ответ видится такой: в старом терминале видать допустили логическую ошибку, но когда заметили, исправлять было очень позно или раньше считали, что так будет лучше, а в новом терминале сразу написали по-человечески.
 
Mikhail Dovbakh:

Не знаю, как подобные «мины»\различия можно чем то разумным объяснить.

Можно делать и тогда не тратить время на объяснения
// MQL4&5-code

#ifdef __MQL5__

template <typename T>
int MT4ArrayMaximum(
   const T&   array[],             // массив для поиска
   int        count=WHOLE_ARRAY,   // количество проверяемых
   int        start=0              // с какого индекса начинаем поиск
)
{
  return(ArrayMaximum(array, start, count));
}

#define ArrayMaximum MT4ArrayMaximum

#endif

void OnStart()
{
  int Array[] = {5, 4, 3, 2, 7};
  
  Print(ArrayMaximum(Array, 3));
  
  return;  
}
 
George Merts:

Ну чем они  неряшливые-то ? Они просто разные. Можно так, можно иначе. Может появиться и еще какой-то вариант.

Чтобы не зависеть от данных особенностей конкретной версии языка - существуют стандартные интерфейсы. По идее, Стандартная Библиотека - это именно такой набор классов и интерфейсов (уж очень она мне напоминает библиотеку MS MFC). Но, увы, в СБ идея стандартизации интерфейсов не доведена до логического завершения, в МТ4 и МТ5 - многие классы существенно различны. Поэтому, на мой взгляд, у каждого программиста должны существовать свои шаблоны интерфейсов, с которыми он и работает. В том числе и "обертки" для функций объединения строк, раз уж они в разных версиях разные.

СБ во многих местах - это нечто странное. Иногда возникает чувство, что ее писали, лишь бы начальник отвязался. Пример: COrderInfo. Для получения информации об ордере используется метод COrderInfo::StoreState(void), она заполняет поля, лежащие в секции protected

class COrderInfo : public CObject
  {
protected:
   ulong             m_ticket;
   ENUM_ORDER_TYPE   m_type;
   ENUM_ORDER_STATE  m_state;
   datetime          m_expiration;
   double            m_volume_curr;
   double            m_price_open;
   double            m_stop_loss;
   double            m_take_profit;

public:
// далее методы доступа к данным и др..
  };

//+------------------------------------------------------------------+
//| Stored order's current state                                     |
//+------------------------------------------------------------------+
void COrderInfo::StoreState(void)
  {
   m_type       =OrderType();
   m_state      =State();
   m_expiration =TimeExpiration();
   m_volume_curr=VolumeCurrent();
   m_price_open =PriceOpen();
   m_stop_loss  =StopLoss();
   m_take_profit=TakeProfit();
  }

 А теперь угадайте, что происходит при вызове метода для чтения значения? Думаете, оно берется из заполненного заранее поля? Нет, оно заново читается, а поля m_**** вообще в классе никак не используются!! 

//+------------------------------------------------------------------+
//| Get the property value "ORDER_SL"                                |
//+------------------------------------------------------------------+
double COrderInfo::StopLoss(void) const
  {
   return(OrderGetDouble(ORDER_SL));
  }
//+------------------------------------------------------------------+
//| Get the property value "ORDER_TP"                                |
//+------------------------------------------------------------------+
double COrderInfo::TakeProfit(void) const
  {
   return(OrderGetDouble(ORDER_TP));
  }
//+------------------------------------------------------------------+

***
 

 
Alexey Volchanskiy:

СБ во многих местах - это нечто странное. Иногда возникает чувство, что ее писали, лишь бы начальник отвязался. Пример: COrderInfo. Для получения информации об ордере используется метод COrderInfo::StoreState(void), она заполняет поля, лежащие в секции protected.

...

А  теперь угадайте, что происходит при вызове метода для чтения значения? Думаете, оно берется из заполненного заранее поля? Нет, оно заново читается, а поля m_**** вообще в классе никак не используются!!  

Да, Алексей, как я понимаю, данная  нелогичность, видимо,  объясняется тем, что классы разрабатывались не одновременно, разными людьми, причем, в основном трейдерами, а не программистами. 

Но, многие принципы, заложенные в СБ - очень даже правильные. Более того, я, скажем, практически никогда не использовал в своем коде непосредственно массивы - в первую очередь из-за отсутствия указателей и ссылок на них. Мне гораздо удобнее использовать классы-наследники CArray.

А насчет разности платформ - до введения условной компиляции приходилось мудрить со включаемыми файлами, но сейчас - никаких проблем уже нет, fxsaber совершенно верно привел иллюстрацию (правда, только половину, код МТ4 он не привел).

 
Mikhail Dovbakh:
 

Однако, я о другом - согласитесь, что  функции поиска почему то разные:

Не знаю, как подобные «мины»\различия можно чем то разумным объяснить.

Во-во, хорошую иллюстрацию привели. Я даже не в курсе, что, оказывается, в МТ4 и МТ5 функции поиска максимума различны - я всегда пользуюсь только универсальным и переносимым CArrayInt, интерфейс которого одинаков для МТ4 и МТ5. Когда же выясняется разница в классах МТ4 и МТ5 - тут же пишу "обертку", которая приводит оба интерфейса к одному, используя условную компиляцию и темплейты, примерно, как предложил fxsaber
 

Неожиданная для меня, но видимо очевидная для авторов  доктрины неожиданного применения "терминального нуля" или реакции на его наличие в string, мина различного поведения в MT4  и 5 "подорвала" мое время на поиски. Проиллюстрирую ее кодом.

//+------------------------------------------------------------------+
void OnStart()
  {
  //---
  string Txt0=AccountInfoString(ACCOUNT_COMPANY)+"\0",
         Txt= AccountInfoString(ACCOUNT_COMPANY);
  uchar signed[];  int len,size; 
  //--- 
  printf ("------------ txt ");
  len = StringLen(Txt);
  size=StringToCharArray(Txt,signed,0,len);
  printf ("Txt      ='%s' Len=%i SizeArray=%i",Txt,len ,size);
  Txt+="\0"+" Add text";  // Add '00'& text
  len = StringLen(Txt);
  size=StringToCharArray(Txt,signed,0,len);
  printf ("Txt      ='%s' Len=%i SizeArray=%i",Txt,len ,size);
  Txt+="\0"+" Add Next text";  // Add '00'+Next text
  len = StringLen(Txt);
  size=StringToCharArray(Txt,signed,0,len);
  printf ("Txt      ='%s' Len=%i SizeArray=%i",Txt,len ,size);
  //=================================
  printf ("------------ txt+'0x00' ");
  len = StringLen(Txt0);
  size=StringToCharArray(Txt0,signed,0,len);
  printf ("Txt0      ='%s' Len=%i SizeArray=%i",Txt0,len ,size);
  Txt0+="\0"+" Add text";  // Add '00'& text
  len = StringLen(Txt0);
  size=StringToCharArray(Txt0,signed,0,len);
  printf ("Txt0      ='%s' Len=%i SizeArray=%i",Txt0,len ,size);
  Txt0+="\0"+" Add Next text";  // Add '00'+Next text
  len = StringLen(Txt0);
  size=StringToCharArray(Txt0,signed,0,len);
  printf ("Txt0      ='%s' Len=%i SizeArray=%i",Txt0,len ,size);
 }

Результат выполнения в МТ5 ожидаем и, на мой взгляд, верный:

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) ------------ txt 

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt      ='MetaQuotes Software Corp.' Len=25 SizeArray=25

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt      ='MetaQuotes Software Corp.' Len=35 SizeArray=35

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt      ='MetaQuotes Software Corp.' Len=50 SizeArray=50

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) ------------ txt+'0x00' 

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt0      ='MetaQuotes Software Corp.' Len=26 SizeArray=26

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt0      ='MetaQuotes Software Corp.' Len=36 SizeArray=36

2021.10.03 22:45:14.506 BugAdd_zero (EURUSD,M1) Txt0      ='MetaQuotes Software Corp.' Len=51 SizeArray=51

MT4  настойчиво убежден при использовании StringToCharArray, что терминальный ноль должен присутствовать только в конце string.

StringLen при этом так не считает... )

2021.10.03 22:46:32.442 Script BugAdd_zero EURGBP,M1: removed

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: uninit reason 0

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt0      ='MetaQuotes Software Corp.' Len=51 SizeArray=26

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt0      ='MetaQuotes Software Corp.' Len=36 SizeArray=26

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt0      ='MetaQuotes Software Corp.' Len=26 SizeArray=26

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: ------------ txt+'0x00' 

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt      ='MetaQuotes Software Corp.' Len=50 SizeArray=26

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt      ='MetaQuotes Software Corp.' Len=35 SizeArray=26

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: Txt      ='MetaQuotes Software Corp.' Len=25 SizeArray=25

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: ------------ txt 

2021.10.03 22:46:32.426 BugAdd_zero EURGBP,M1: initialized

2021.10.03 22:46:32.411 Script testbug\BugAdd_zero EURGBP,M1: loaded successfully


Это баг или так спроектировано?

 
Mikhail Dovbakh #:

Это баг или так спроектировано?

в MQL5 поведение StringToCharArray относительно \0 только относительно недавно поменяли

Причина обращения: