Organising the order cycle - page 9

 
fxsaber:

Changed

Now without alerts.

The answer is obvious - if Ticket == PrevTicket ---> return WRONG_VALUE.

If function returns value less than zero, then it should be called again.

 
Artyom Trishkin:

The answer is obvious - if Ticket == PrevTicket ---> return WRONG_VALUE.

So, this is a solution of a special case of the problem which I described for clarity in the form of equality of neighboring tickets.

The problem is actually the same - indexing shakeout during the loop. This can lead to a situation where some ticket is skipped, or a ticket is repeated in one, etc.

I haven't found an alternative to IsChange.

 
fxsaber:

So this is a solution to a particular case of the problem, which I described for clarity in the form of equality of neighbouring tickets.

The problem is actually all the same - shaking of indexing during the cycle. This can lead to a situation where some ticket is skipped, or a ticket is repeated in one, etc.

I haven't found an alternative to IsChange.

We create a list in the timer and work with it.

 
Artyom Trishkin:

Create a list in the timer and work with it.

Better in code.

 
fxsaber:

Better in code.

It is very difficult to show in code - there is a whole library of interrelated classes.

The idea is the following - we pass all orders and positions on the account and fill the CArrayObj list in the timer. We constantly update it to get actual information in one pass.

If there is a need to close positions or to delete orders, we obtain this list and select from it the necessary order objects and their tickets that are needed for the closing (modification) functions. If this order-object is physically absent (it was closed or deleted during these actions), we simply move on to the next object in the list, since this one has already been closed, and the list will be updated at the next iteration of the timer. The first problem that comes to mind is that the list is irrelevant when the trading environment changes during the time the actions are performed on the list. But as I see it, physical absence of an order from the list should not bother us too much - we just get an error and go to the next one in the list - this list is not shuffled like in a trading environment and skipping is impossible - only a statement of the fact of absence of an order corresponding to an entry in the list.

This is what I think so far, since I haven't implemented it in my code yet. I am just getting ready for implementation, but initially I need to finish some other classes (I asked a question about substitution of functions in Features branch). When I start the implementation, possible problems will be visible there, and I will decide how to solve them and fix them.

 
Artyom Trishkin:

The answer is obvious - if Ticket == PrevTicket ---> return WRONG_VALUE.

If the function returns a value less than zero, we need to call it again.

You don't have to do anything at all. It is enough to follow the logic looking like an idiot.

We have 6 orders

  • 0 ticket 100
  • 1 ticket 101
  • 2 ticket 102
  • 3 ticket 103
  • 4 ticket 104
  • 5 ticket 105

We start going through the orders for, let's say, modification,

We choose 5 ticket 105, check if we want to modify it and modify it.

At this time, our unclean hands deleted order 2 ticket 102, and the list was changed. Now the order with ticket 105 is fourth in the list, and it is again selected for modification. But we do not work without checking... we checked if it should be modified, BUT!!! It doesn't... so what??? Who got hurt because the order was re-selected?

 
Artyom Trishkin:

It is very difficult to show in code - there is a whole library of interrelated classes.

The idea is the following - we pass all orders and positions on the account and fill the CArrayObj list in the timer. We constantly update it to get actual information in one pass.

If there is a need to close positions or to delete orders, we obtain this list and select from it the necessary order objects and their tickets that are needed for the closing (modification) functions. If this order-object is physically absent (closed or deleted during these actions), we simply switch to the next object in the list, since this one has already been closed, and the list will be updated at the next iteration of the timer. The first problem that comes to mind is that the list is irrelevant when the trading environment changes over the time of the actions on the list. But as I see it, physical absence of an order from the list should not bother us too much - we just get an error and go to the next one in the list - this list is not shuffled like in a trading environment and skipping is impossible - only a statement of the fact of absence of an order corresponding to an entry in the list.

This is what I think so far, since I haven't implemented it in my code yet. I am just getting ready for implementation, but initially I need to finish some other classes (I asked a question about substitution of functions in Features branch). When I start the implementation, possible problems will be visible there and I will decide how to solve them and fix them.

Here is an implementation of this

Forum on trading, automated trading systems and trading strategies testing

Organizing an order loop

fxsaber, 2017.09.11 20:29

// Редкий, но правильный костяк модификации ордеров
for (int i = OrdersTotal() - 1; i >= 0; i--)
  if (OrderSelect(i, SELECT_BY_POS))
    if (OrderModify(OrderTicket(), Price, SL, TP, OrderExpiration()))     
    {
      i = OrdersTotal(); // Хотя бы так
      
      // А лучше так
//      OnTick(); break; // вместо строки выше лучше делать такой вызов (переполнения стека от рекурсивных вызовов быть не должно)
    }


After sending a trade order, the trade environment changes, so it is advisable to execute all the trade logic of the TS from scratch immediately after the trade server response.

Only it still requires IsChange. The timer is not an option at all. Even Sleep(1) spoils the whole picture.

 
Alexey Viktorov:

Absolutely nothing needs to be done. It's enough to walk through the logic with the look of an idiot.

Taki, yes, not a problem if closing/activation of an order is checked.
Well and if its own array of ticks, then the order will just miss.

ps. Let me throw in another case - if a pending order is set to stop a real order (for a rollover), then when the stop is triggered, the pending order may be delayed in opening for an indefinite amount of time. That is, one order will be triggered by the market, while the other will hang for a certain amount of ticks...

 
fxsaber:

Here is an implementation of this

Only it still requires IsChange. The timer is not an option at all. Even Sleep(1) spoils the whole picture.

IsChange() is exactly implemented in the timer (the test version has not been finished yet):

//+------------------------------------------------------------------+
//| Обновляет список ордеров                                         |
//+------------------------------------------------------------------+
int CMarketCollection::Refresh(void)
  {
   ::ZeroMemory(m_struct_market);
   int number_new=0, total=::OrdersTotal();
   m_list_all_orders.Clear();
   for(int i=0; i<total; i++){
      if(!::OrderSelect(i,SELECT_BY_POS)) continue;
      long ticket=::OrderTicket();
      m_struct_market.hash_sum_acc+=ticket;
      m_struct_market.total_volumes+=::OrderLots();
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderType();
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL){
         CMarketOrder* order=new CMarketOrder();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_positions++;
         }
      else{
         CMarketPending* order=new CMarketPending();
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
         m_struct_market.total_pending++;
         }
      }
   //--- Первый запуск
   if(m_hash_sum_acc_prev==WRONG_VALUE){
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   if(m_struct_market.hash_sum_acc!=m_hash_sum_acc_prev){
      number_new=(m_struct_market.total_pending+m_struct_market.total_positions)-(m_total_positions_prev+m_total_pending_prev);
      Print(FUNC,"Хэш-сумма всех ордеров и позиций изменилась");
      //--- Увеличисля общий объём
      if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)>0){
         Print(FUNC,"Общий объём увеличился");
         if(m_struct_market.total_positions>m_total_positions_prev) Print(FUNC,"Количество позиций увеличилось");
         if(m_struct_market.total_pending>m_total_pending_prev) Print(FUNC,"Количество ордеров увеличилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      //--- Уменьшился общий объём
      else if(::NormalizeDouble(m_struct_market.total_volumes-m_total_volume_prev,3)<0){
         Print(FUNC,"Общий объём уменьшился");
         if(m_struct_market.total_positions<m_total_positions_prev) Print(FUNC,"Количество позиций уменьшилось");
         if(m_struct_market.total_pending<m_total_pending_prev) Print(FUNC,"Количество ордеров уменьшилось");
         //--- Отправка EVENT в управляющий класс CEngine
         // сделать!
         }
      else{
         // что-то ещё, не пойму пока что именно - не было претендентов ещё
         }
      //---
      m_hash_sum_acc_prev=m_struct_market.hash_sum_acc;
      m_total_positions_prev=m_struct_market.total_positions;
      m_total_pending_prev=m_struct_market.total_pending;
      m_total_volume_prev=m_struct_market.total_volumes;
      }
   //---
   //---
   return number_new;
  }
//+------------------------------------------------------------------+

The control class can catch the change either by the number returned from Refresh() of both classes (in the tester):

//+------------------------------------------------------------------+
//| Таймер                                                           |
//+------------------------------------------------------------------+
void CEngine::OnTimer(void)
  {
   //--- Обновление списка исторических ордеров и позиций
   m_new_history=History.Refresh();
   if(m_new_history>0){
      Print(FUNC,"Изменение в исторических на ",m_new_history);
      //--- реакция
      }
   //--- Обновление списка рыночных ордеров и позиций
   m_new_market=Market.Refresh();
   if(m_new_market!=0){
      Print(FUNC,"Изменение в активных на ",m_new_market);
      //--- реакция
      }
   //---
   Sym.OnTimer();
  }
//+------------------------------------------------------------------+

or in a user event, which are not yet implemented (demo, real).

 
Artyom Trishkin:

IsChange() is exactly what is implemented in the timer (not yet completed test version):

Why, if IsChange is five lines?