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

 

Зачем Warning ?!  Когда вместо него достаточно разрешить в MQL цивилизованную запись (*) 

#ifdef __MQL__
#define MACRO( x1, x2 )        x2
#else 
#define MACRO( x1, x2, ...)    x2 //(*)
#endif
void OnStart()
{
#ifdef __MQL__
    Print(MACRO( 1, 2, 3 )); //Warning: too many arguments for function-like macro 'MACRO'
#else
    Print(MACRO( 1, 2, 3 )); //нормально
#endif
}
 

Представим себе функцию, вычисляющую и проверяющую объем.
Перед этим ему нужны эти значения с сервера брокера: SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEP.
Обычно нет необходимости запрашивать их снова и снова при каждом вызове функции.
вы просто можете объявить их как статические переменные в начале этой функции:

   static double vMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN),
                 vMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX),
                 vStp = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

Ноуууу, эти объявления выполняются первыми при запуске советника, еще до OnInit.
Просто нажмите F9 в строке «static double..» и запустите отладчик, чтобы увидеть это.
Что делать, если эти (и другие) данные еще не пришли с сервера?
Из-за параллельной обработки выполнение советника (имхо!) НЕ останавливается до тех пор, пока все полученные данные не станут доступны локально.

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

Кто-нибудь знает другое решение?

Let's imagine a function that calculates and checks the volume.
Before that, it needs these values from the broker's server: SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEP.
Normally there is no need to query these again and again with every function call,
you just could declare them as static variables at the beginning of this function:

   static double vMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN),
                 vMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX),
                 vStp = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

Buuuuut, these declarations are executed first when the EA is started, even before OnInit.
Just press F9 at the line "static double .." and start the debugger to see this.
What if this (and other) data has not yet arrived from the server?
Because of the parallel processing, the execution of the EA is (imho!) NOT stopped until all retrieved data is available locally.

Too bad, this partly invalidates the concept of local static variables.
My first solution would be to use instead of them normal global variables which are assigned in OnInit in a loop until all are non-zero.

Does anyone know another solution?

 
Carl Schreiber #:

Кто-нибудь знает другое решение?

struct STRUCT_SYMBOL_INFO_DOUBLE
{
  double Prop[100];
  
  double Get( const ENUM_SYMBOL_INFO_DOUBLE Prop_ID )
  {
    return(this.Prop[Prop_ID] ? this.Prop[Prop_ID]
                              : this.Prop[Prop_ID] = ::SymbolInfoDouble(_Symbol, Prop_ID));        
  }
} SymbolDouble = {};


void OnInit()
{
  Print(SymbolDouble.Get(SYMBOL_VOLUME_MIN));
  Print(SymbolDouble.Get(SYMBOL_VOLUME_MAX));
  Print(SymbolDouble.Get(SYMBOL_VOLUME_STEP));
}
 
Спасибо, но меня больше интересует решение проблемы, как можно лучше обеспечить

что все данные поступили с сервера после запуска советника, вживую или в тестере.

Действительно ли выдается ошибка, если запрошенных данных еще нет во внутреннем кеше?

Thanks, but I'm more interested in the solution to the problem, how can you best ensure

that all data has arrived from the server after starting an EA, live or in the tester.

Is an error actually thrown if the requested data is not yet there - in the internal cache?

 
Carl Schreiber #:
Спасибо, но меня больше интересует решение проблемы, как можно лучше обеспечить

что все данные поступили с сервера после запуска советника, вживую или в тестере.

Действительно ли выдается ошибка, если запрошенных данных еще нет во внутреннем кеше?

Thanks, but I'm more interested in the solution to the problem, how can you best ensure

that all data has arrived from the server after starting an EA, live or in the tester.

Is an error actually thrown if the requested data is not yet there - in the internal cache?

Я сегодня первый раз запустил МТ и прилетело обновление. После обновления такой код

class CF
 {
public:
  double vMin,
         vMax,
         vStp;
                     CF(void);
 };
/****************************Конструкторы****************************/
CF :: CF(void) :
  vMin(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)),
  vMax(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX)),
  vStp(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP))
 {};/****************************************************************/
CF cf();
/*******************Expert initialization function*******************/
int OnInit()
 {
  Print(cf.vMax, "\n", cf.vMin, "\n", cf.vStp);
  return(INIT_SUCCEEDED);
 }/******************************************************************/

даёт такой результат

2024.01.01 23:19:30.818 !00 (EURUSD,H1) 500.0
2024.01.01 23:19:30.818 !00 (EURUSD,H1) 0.01
2024.01.01 23:19:30.818 !00 (EURUSD,H1) 0.01

Не знаю в кеше что-то было или нет, но результат есть.

 
Alexey Viktorov # :

Я сегодня первый раз запустил МТ и прилетело обновление. После обновления такой код

даёт такой результат

Не знаю в кеше что-то было или нет, но результат есть.

Однако это не значит, что так будет всегда. С другим брокером, возможно, с большей задержкой, менее быстрым сервером для более простых учетных записей... эти данные могут прийти не сразу. Думаю, если спросить напрямую у MQ, то они ответят, что не могут этого гарантировать.

Можно видеть, что ваш класс, как и структура fxsaber или статические переменные в функциях, инициализируются и заполняются до запуска OnInit(). А что, если эти данные поступят немного позже? Помню, в тестере исторические котировки индикаторов могли запаздывать и приходилось делать дополнительную проверку в основной функции...

Следовательно, как убедиться ? «Сон (1000)» в OnInit()?

However, this does not mean that it will always be like this. With another broker, with maybe more latency, a less fast server for simpler accounts, ..., this data may not arrive immediately. I think if you ask MQ directly, they will answer that they cannot guarantee that.

One can see that your class, like the structure of fxsaber or the static variables in the functions, are initialized and filled before OnInit() is started. But what if this data arrives a little later? I remember that in the tester the historic quotes for the indicators might come to late and I had to do an extra check in the main function...

Ergo, how to make sure? A "Sleep(1000)" in OnInit()?

 
Carl Schreiber #:

Однако это не значит, что так будет всегда. С другим брокером, возможно, с большей задержкой, менее быстрым сервером для более простых учетных записей... эти данные могут прийти не сразу. Думаю, если спросить напрямую у MQ, то они ответят, что не могут этого гарантировать.

Можно видеть, что ваш класс, как и структура fxsaber или статические переменные в функциях, инициализируются и заполняются до запуска OnInit(). А что, если эти данные поступят немного позже? Помню, в тестере исторические котировки индикаторов могли запаздывать и приходилось делать дополнительную проверку в основной функции...

Следовательно, как убедиться ? «Сон (1000)» в OnInit()?

However, this does not mean that it will always be like this. With another broker, with maybe more latency, a less fast server for simpler accounts, ..., this data may not arrive immediately. I think if you ask MQ directly, they will answer that they cannot guarantee that.

One can see that your class, like the structure of fxsaber or the static variables in the functions, are initialized and filled before OnInit() is started. But what if this data arrives a little later? I remember that in the tester the historic quotes for the indicators might come to late and I had to do an extra check in the main function...

Ergo, how to make sure? A "Sleep(1000)" in OnInit()?

Если данные не получены - повторить запрос. Если опять нет, то вписать их при старте. 
 
Carl Schreiber #:

Однако это не значит, что так будет всегда. С другим брокером, возможно, с большей задержкой, менее быстрым сервером для более простых учетных записей... эти данные могут прийти не сразу. Думаю, если спросить напрямую у MQ, то они ответят, что не могут этого гарантировать.

Можно видеть, что ваш класс, как и структура fxsaber или статические переменные в функциях, инициализируются и заполняются до запуска OnInit(). А что, если эти данные поступят немного позже? Помню, в тестере исторические котировки индикаторов могли запаздывать и приходилось делать дополнительную проверку в основной функции...

Следовательно, как убедиться ? «Сон (1000)» в OnInit()?

However, this does not mean that it will always be like this. With another broker, with maybe more latency, a less fast server for simpler accounts, ..., this data may not arrive immediately. I think if you ask MQ directly, they will answer that they cannot guarantee that.

One can see that your class, like the structure of fxsaber or the static variables in the functions, are initialized and filled before OnInit() is started. But what if this data arrives a little later? I remember that in the tester the historic quotes for the indicators might come to late and I had to do an extra check in the main function...

Ergo, how to make sure? A "Sleep(1000)" in OnInit()?

Вы упускаете ещё один важный момент в статических переменных. Согласно документации статическая переменная может быть инициализирована «соответствующей ее типу константой или константным выражением» но функция не является ни константой, ни константным выражением и соответственно переменной присваивается значение при каждом выполнении функции. То-есть точно так же как и для обычной переменной.

Sleep(1000)" in OnInit() никак не поможет. Полностью загружен советник только после выполнения инициализации.

А вот с инициализацией в конструкторе класса надо экспериментировать. Конечно есть подозрение, что может быть ошибка, но без экспериментов не понять…

 
Alexey Viktorov # :

Вы упускаете ещё один важный момент в статических переменных. Согласно документации статическая переменная может быть инициализирована «соответствующей ее типу константой или константным выражением» но функция не является ни константой, ни константным выражением и соответственно переменной присваивается значение при каждом выполнении функции. То-есть точно так же как и для обычной переменной.

Sleep(1000)" in OnInit() никак не поможет. Полностью загружен советник только после выполнения инициализации.

А вот с инициализацией в конструкторе класса надо экспериментировать. Конечно есть подозрение, что может быть ошибка, но без экспериментов не понять…

Сначала я хотел использовать такие значения, как SYMBOL_TRADE_TICK_SIZE, SYMBOL_VOLUME_STEP,... в качестве статических переменных только в тех функциях, где они необходимы. Но что, если при запуске им не присвоено никакого значения? Затем я возвращаюсь к запросу или проверке при каждом вызове функции :(
Это также применимо к глобальным структурам и классам.

Поэтому теперь я решил сохранить эти ключевые значения в глобальных переменных, которые назначаются в дополнительной функции в OnInit(). Наверняка сон там сработает?

At first I wanted to use values like SYMBOL_TRADE_TICK_SIZE, SYMBOL_VOLUME_STEP, ... as static variables only in the functions where they are needed. But what if no value is assigned to them at startup? Then I'm back to a query or check with every function call :(
This would also apply to global structures and classes.

So now I decided to store these key values in global variables, which are assigned in an extra function in OnInit(). Surely a sleep will work there?

#define _d2D(p)               (fabs(p)>0.00000001 ? DoubleToString(p,_Digits) : DoubleToString(p,1)) // to get 0.0 instead of 0.00000
...
double         DELTA,dDEVI,LevSTP,LevFRZ,VolMin,VolMax,VolStp,ValTCK,SzeTCK;
...

bool setGlobVars() {
   // It is very likely that the values will be filled the very first time, but this is not guaranteed.
   // And due to the importance of theses values for the trading ...
   
   dDEVI   = LevSTP  = LevFRZ  = DELTA = VolMin = VolMax = VolStp = 0.0;
   
   int i=100;
   while (i-->0) {   // no endless loop
      dDEVI   = 10 * _Point;
      LevSTP  = _Point * SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
      LevFRZ  = _Point * SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);
      SzeTCK  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
      ValTCK  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
      VolMin  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
      VolMax  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
      VolStp  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
      
      if ( dDEVI>FLT_MIN && LevSTP>FLT_MIN && LevFRZ>FLT_MIN && ValTCK>FLT_MIN && SzeTCK>FLT_MIN && VolMin>FLT_MIN && VolMax>FLT_MIN && VolStp>FLT_MIN )
      break;    // ready fine
      Sleep(100);  // next round
   }
   if (i>1) {
      DELTA = ValTCK / SzeTCK;  // SzeTCK must be != 0.0
      return(true);
   }
   logNewErr(FunLine,0,StringFormat("IMPORTANT trade values are ZERO, did not arrive from the server, last Ping: %i!!"+
                                    "%sdDEVI:%s LevSTP:%s LevFRZ:%s ValTCK:%s SzeTCK:%s VolMin:%s VolMax:%s VolStp:%s",TerminalInfoInteger(TERMINAL_PING_LAST),
                                    _newL, _d2D(dDEVI), _d2D(LevSTP), _d2D(LevFRZ), _d2D(ValTCK), _d2D(SzeTCK), _d2D(VolMin), _d2D(VolMax), _d2D(VolStp)));
   logSndTrd(FunLine,0);
   return(false);
}
int OnInit()
   {
      bool ok = setGlobVars();
   }
 
Carl Schreiber #:

Сначала я хотел использовать такие значения, как SYMBOL_TRADE_TICK_SIZE, SYMBOL_VOLUME_STEP,... в качестве статических переменных только в тех функциях, где они необходимы. Но что, если при запуске им не присвоено никакого значения? Затем я возвращаюсь к запросу или проверке при каждом вызове функции :(
Это также применимо к глобальным структурам и классам.

Поэтому теперь я решил сохранить эти ключевые значения в глобальных переменных, которые назначаются в дополнительной функции в OnInit(). Наверняка сон там сработает?

At first I wanted to use values like SYMBOL_TRADE_TICK_SIZE, SYMBOL_VOLUME_STEP, ... as static variables only in the functions where they are needed. But what if no value is assigned to them at startup? Then I'm back to a query or check with every function call :(
This would also apply to global structures and classes.

So now I decided to store these key values in global variables, which are assigned in an extra function in OnInit(). Surely a sleep will work there?

во первых при OnInit может вообще не быть связи с торговым сервером, то есть придётся самому генерировать событие OnConnect и уже там инициализировать эти переменные

во вторых STOP_LEVEL меняется часто, и даже VOLUME_MIN, VOLUME_STEP, LEVERAGE (точнее MARGIN_INITIAL, для открытия позиций) могут быть изменены динамически.