Developers! Do you even test what you create? - page 10

 
Mikalas:

Oh, my God! Is it valid in the history?

papaklass probably meant that OnTradeTransaction returns errors?

If the information in OnTradeTransaction may not be valid, we have to take it from the history to make sure it is valid.

If onTradeTransaction information is not always reliable, we have to take it from the history to make sure the information was processed.

The question is why the hell do we need OnTradeTransaction if we have to take the information from the history anyway? - It only needs it for error checking. The broker rejected the order and we received the answer why it was rejected in OnTradeTransaction and analyzed it.

 
sergeev:
but why drool over 9 pages?

Please don't be rude! By the way, it's already 10!

And you are within your rights not to read what is written here at all!

 
Mikalas:

C-4, will be processed, of course, but why the need for OnRefresh()?

Many events -> one handler.
 
C-4:
Many events -> one handler.
Errors from all corners in one pile! :)
 
Mikalas:
Errors from all corners in one pile! :)

It is not the errors that are sent, but the data. Errors may be in the handler, but they are easy to fix because there is only one handler.

papaklass:
That's exactly what I mean. You need event separation.
You don't need a separation of events, you need a separation of handlers. Events generate data. Each type of data is handled by its own handler. It doesn't matter who received the data, the important thing is that there is a unique handler for each type of data.
 
C-4:

It is not the errors that are sent, but the data. Errors may be in the handler, but they are easy to fix because there is only one handler.

You don't need to separate events, you need to separate handlers. Events generate data. Each data type handles its own handler. It doesn't matter who received the data, the important thing is that there is a unique handler for each data type.

What is not separated here?

void OnTradeTransaction( const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result )
{
 // Print( "Ticket = ", string( trans.order ), " --> ", EnumToString( trans.type ), " --> ", EnumToString(trans.order_state) );
  
  switch( trans.type )
  {
    TRADE_TRANSACTION_ORDER_DELETE:      switch( trans.order_state )
                                         {
                                           Удаление ордера из списка открытых.
                                           Ордер может быть удален из открытых в результате выставления
                                           соответствующего запроса либо в результате исполнения (заливки) и переноса в историю.
 
                                         } 
                                         break;
    
    TRADE_TRANSACTION_ORDER_ADD:         switch( trans.order_state )
                                         {
                                           Добавление нового открытого ордера.
                                         } 
                                         break;
                                          
    TRADE_TRANSACTION_DEAL_ADD:          switch( trans.order_state )
                                         {
                                           Добавление сделки в историю. Осуществляется в результате исполнения ордера или проведения операций с балансом счета.
                                         }
                                         break;
                                                    
    case TRADE_TRANSACTION_HISTORY_ADD:  switch( trans.order_state )
                                         {
                                           Добавление ордера в историю в результате исполнения или отмены.
                                         }
                                         break;
    
    case TRADE_TRANSACTION_ORDER_DELETE:  switch( trans.order_state )
                                         {
                                           Удаление ордера из списка открытых.
                                           Ордер может быть удален из открытых в результате выставления
                                           соответствующего запроса либо в результате исполнения (заливки) и переноса в историю.
                                         }
                                         break;
                                         
    case TRADE_TRANSACTION_ORDER_UPDATE: switch( trans.order_state )
                                         {
                                           Изменение открытого ордера. 
                                           К данным изменениям относятся не только явные изменения
                                           со стороны клиентского терминала или торгового сервера,
                                           но также и изменение его состояния при выставлении
                                           (например, переход из состояния ORDER_STATE_STARTED в ORDER_STATE_PLACED или
                                           из ORDER_STATE_PLACED в ORDER_STATE_PARTIAL и т.д.).
                                         }
                                         break;
                                         
    case TRADE_TRANSACTION_DEAL_UPDATE:  switch( trans.order_state )
                                         {
                                           Изменение сделки в истории. Возможны ситуации, 
                                           когда ранее исполненная сделка изменяется на сервере.
                                           Например, сделка была изменена во внешней торговой системе (бирже),
                                           куда она была выведена брокером.
                                         }
                                         break;
                                         
    case TRADE_TRANSACTION_DEAL_DELETE: switch( trans.order_state )
                                        {
                                          Удаление сделки из истории.
                                          Возможны ситуации, когда ранее исполненная сделка удаляется на сервере.
                                          Например, сделка была удалена во внешней торговой системе (бирже), куда она была выведена брокером.
                                        }
                                        break; 
             
    case TRADE_TRANSACTION_HISTORY_UPDATE: switch( trans.order_state )
                                           {
                                             Изменение ордера, находящегося в истории ордеров.
                                             Данный тип предусмотрен для расширения функциональности на стороне торгового сервера.
                                           }
                                           break;
                                          
    case TRADE_TRANSACTION_HISTORY_DELETE: switch( trans.order_state )
                                           {
                                             Удаление ордера из истории ордеров.
                                             Данный тип предусмотрен для расширения функциональности на стороне торгового сервера.
                                           }
                                           break;
                                                                                 
    case TRADE_TRANSACTION_POSITION:       switch( trans.order_state )
                                           {
                                            Изменение позиции, не связанное с исполнением сделки. 
                                            Данный тип транзакции свидетельствует именно о том,
                                            что позиция была изменена на стороне торгового сервера.
                                            У позиции может быть изменен объем, цена открытия,
                                            а также уровни Stop Loss и Take Profit.
                                            Информация об изменениях передается в структуре MqlTradeTransaction
                                            через обработчик OnTradeTransaction.
                                            Изменение позиции (добавление, изменение или ликвидация) в результате совершения
                                            сделки не влечет за собой появление транзакции TRADE_TRANSACTION_POSITION.
                                           }
                                           break;                                                                                                                                                                                  
  case TRADE_TRANSACTION_REQUEST:  Уведомление о том, что торговый запрос обработан сервером,
                                     и результат его обработки получен.
                                      Для транзакций данного типа в структуре MqlTradeTransaction
                                      необходимо анализировать только одно поле - type (тип транзакции).
                                      Для получения дополнительной информации необходимо анализировать второй
                                      и третий параметры функции OnTradeTransaction (request и result).
                                    break;
}
 

And then there are

const MqlTradeRequest &request, const MqlTradeResult &result
 
Mikalas:

What's not shared here?

A lot of combinatorics. Bottom line: giant sheet in OnTradeTransaction and complicated logic. I can't answer how I would do it, because I don't know the task. In any case case->case->case... is a bit suspicious.
 
papaklass:

What you suggest (processing of data types) is what MK has at the moment. The OnTradeTransaction handler handles a certain MqlTradeTransaction data type. It's true, they put a lot of things into this data type, i.e. data types corresponding to different events.

I suggest that every event should have its own data and its own handler. As many events, as many handlers. The division of events (opening a position, closing a position, placing an order, modifying an order, modifying a position, etc.). And it is up to the developers to decide what data types to assign to which events.

By the word "handler", I do not mean a system function that receives some event, but some Expert Advisor module that analyzes this event. To multiply the number of functions On... Each of them for its own event - it makes no sense, all the more so it is elementary to create a necessary number of custom handlers. This is how it is done in my case:

///
/// Принимаем событие.
///
void OnEvent(Event* event)
{
   switch(event.EventId())
   {
       case EVENT_MOUSE_MOVE:
           OnMouseMove(event);
           break;
       case EVENT_KEY_DOWN:
           OnKeyDown(event);
           break;
       case EVENT_ORDER_CHANGE:
           OnOrderChange(event);
           break;
       //etc...
   }
}

It may seem strange that one and the same Event class is passed to completely different handlers which require completely different types of data. For example, OnMouseMove requires a mask of keys pressed on the mouse and its coordinates, OnKeyDown() requires the code of a pressed key, OnOrderChange requires a ticket of the order which was changed and probably an enum describing the exact change. You might think that the event class contains fields for all possible events. But that's not the case. In fact, the object of the event class can't even exist, since its constructor is hidden in the protected area. But its descendants exist in abundance - each descendant to handle only a different event. However, for any event, there is an identifier that indicates what type it belongs to. Knowing this identifier you can perform a safe type conversion from a larger to a smaller type. This is the type of the child that the implicit conversion is performed to when the handler is passed. Let's see how our handlers actually see the event:

///
/// Реагируем на перемещение мыши.
///
OnMouseMove(EventMouseMove* event)
{
   int yCoord = event.YCoord();
   int xCoord = event.XCoord();
   printf("X координата: " + xCoord + "; Y координата: " + yCoord);
}

///
/// Реагируем на перемещение мыши.
///
OnOrderChange(EventOrderChange* event)
{
   int ticket = event.Ticket();
   ENUM_ORDER_STATE state = event.OrderState();
   printf("Ордер с тикетом " + ticket + " изменил свое состояние на " + EnumToString(state));
}

//etc...
Beautiful... It looks like there is only one event, but in fact there could be dozens of them. The event seems to contain almost no information, except its type, but in fact, handlers freely refer to methods known only to them.
 

There are no "external" and "internal" events, just events. And the number of these events is potentially infinite. An event can be anything. An event can contain all kinds of data. By following this philosophy we reach a new, higher level of data abstraction. Why create restrictions in your head, why impose a classification limiting abstraction!

papaklass:

The essential difference between internal and external events is the execution time. Internal events have practically zero execution time, while external events have hundreds of milliseconds to seconds.

Events do not have an execution time. If an event has arrived, it's already executed. This is how asynchronous mode works. So it is wrong to classify events into internal and external because of how fast they are executed. It is correct not to classify at all, but to think very abstractly from concrete implementation.

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