Organizzazione del ciclo dell'ordine - pagina 9

 
fxsaber:

Cambiato

Ora senza avvisi.

La risposta è ovvia - se Ticket == PrevTicket ---> restituisce WRONG_VALUE.

Se la funzione restituisce un valore inferiore a zero, allora deve essere richiamata.

 
Artyom Trishkin:

La risposta è ovvia - se Ticket == PrevTicket ---> restituisce WRONG_VALUE.

Quindi, questa è una soluzione di un caso speciale del problema che ho descritto per chiarezza sotto forma di uguaglianza di biglietti vicini.

Il problema è in realtà lo stesso: lo shakeout dell'indicizzazione durante il ciclo. Questo può portare a una situazione in cui qualche biglietto viene saltato, o un biglietto viene ripetuto in uno, ecc.

Non ho trovato un'alternativa a IsChange.

 
fxsaber:

Quindi questa è una soluzione ad un caso particolare del problema, che ho descritto per chiarezza sotto forma di uguaglianza di biglietti vicini.

Il problema è in realtà lo stesso: il tremolio dell'indicizzazione durante il ciclo. Questo può portare a una situazione in cui qualche biglietto viene saltato, o un biglietto viene ripetuto in uno, ecc.

Non ho trovato un'alternativa a IsChange.

Creiamo una lista nel timer e lavoriamo con essa.

 
Artyom Trishkin:

Crea una lista nel timer e lavora con essa.

Meglio nel codice.

 
fxsaber:

Meglio nel codice.

È molto difficile da mostrare nel codice - c'è un'intera libreria di classi interconnesse.

L'idea è la seguente: passiamo tutti gli ordini e le posizioni sul conto e riempiamo la lista CArrayObj nel timer. Lo aggiorniamo costantemente per ottenere informazioni reali in un solo passaggio.

Se c'è bisogno di chiudere posizioni o eliminare ordini, otteniamo questa lista e selezioniamo da essa gli oggetti ordine necessari e i loro ticket che servono per le funzioni di chiusura (modifica). Se questo oggetto-ordine è fisicamente assente (è stato chiuso o cancellato durante queste azioni), passiamo semplicemente al prossimo oggetto della lista, poiché questo è già stato chiuso, e la lista sarà aggiornata alla prossima iterazione del timer. Il primo problema che mi viene in mente è che la lista è irrilevante quando l'ambiente di trading cambia durante il tempo in cui le azioni vengono eseguite sulla lista. Ma per come la vedo io, l'assenza fisica di un ordine dalla lista non dovrebbe preoccuparci troppo - otteniamo solo un errore e andiamo al prossimo nella lista - questa lista non è mescolata come in un ambiente di trading e saltare è impossibile - solo una dichiarazione del fatto di assenza di un ordine corrispondente a una voce nella lista.

Questo è quello che ho immaginato finora, dato che non l'ho ancora implementato nel mio codice. Mi sto preparando per l'implementazione, ma inizialmente ho bisogno di finire alcune altre classi (ho fatto una domanda sulla sostituzione di funzioni in Features branch). Quando inizierò l'implementazione, i possibili problemi saranno visibili lì, e deciderò come risolverli e sistemarli.

 
Artyom Trishkin:

La risposta è ovvia - se Ticket == PrevTicket ---> restituisce WRONG_VALUE.

Se la funzione restituisce un valore inferiore a zero, dobbiamo chiamarla di nuovo.

Non devi fare assolutamente nulla. È sufficiente seguire la logica sembrando un idiota.

Abbiamo 6 ordini

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

Cominciamo a scorrere gli ordini per, diciamo, la modifica,

Scegliamo 5 biglietti 105, controlliamo se vogliamo modificarli e li modifichiamo.

A questo punto, le nostre mani impure hanno cancellato l'ordine 2 del biglietto 102, e la lista è stata cambiata. Ora l'ordine con il biglietto 105 è quarto nella lista, ed è di nuovo selezionato per la modifica. Ma non lavoriamo senza controllare... abbiamo controllato se deve essere modificato, MA !!! Non lo fa... E allora? Chi si è fatto male perché l'ordine è stato riselezionato?

 
Artyom Trishkin:

È molto difficile da mostrare nel codice - c'è un'intera libreria di classi interconnesse.

L'idea è la seguente: passiamo tutti gli ordini e le posizioni sul conto e riempiamo la lista CArrayObj nel timer. Lo aggiorniamo costantemente per ottenere informazioni reali in un solo passaggio.

Se c'è bisogno di chiudere posizioni o eliminare ordini, otteniamo questa lista e selezioniamo da essa gli oggetti ordine necessari e i loro ticket che servono per le funzioni di chiusura (modifica). Se questo oggetto-ordine è fisicamente assente (chiuso o cancellato durante queste azioni), passiamo semplicemente al prossimo oggetto della lista, poiché questo è già stato chiuso, e la lista sarà aggiornata alla prossima iterazione del timer. Il primo problema che mi viene in mente è che la lista è irrilevante quando l'ambiente di trading cambia nel tempo delle azioni sulla lista. Ma per come la vedo io, l'assenza fisica di un ordine dalla lista non dovrebbe preoccuparci troppo - otteniamo semplicemente un errore e passiamo al prossimo nella lista - questa lista non è mescolata come in un ambiente di trading e saltare è impossibile - solo una dichiarazione del fatto di assenza di un ordine corrispondente a una voce nella lista.

Questo è quello che penso finora, dato che non l'ho ancora implementato nel mio codice. Mi sto preparando per l'implementazione, ma inizialmente ho bisogno di finire alcune altre classi (ho fatto una domanda sulla sostituzione di funzioni in Features branch). Quando inizio l'implementazione, i possibili problemi saranno visibili lì e deciderò come risolverli e sistemarli.

Ecco un'implementazione di questo

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Organizzare un ciclo di ordini

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; // вместо строки выше лучше делать такой вызов (переполнения стека от рекурсивных вызовов быть не должно)
    }


Dopo aver inviato un ordine di compravendita, l'ambiente di compravendita cambia, quindi è consigliabile eseguire tutta la logica di compravendita del TS da zero immediatamente dopo la risposta del server di compravendita.

Solo che richiede ancora IsChange. Il timer non è affatto un'opzione. Anche Sleep(1) rovina tutto il quadro.

 
Alexey Viktorov:

Non c'è assolutamente nulla da fare. È sufficiente attraversare la logica con lo sguardo di un idiota.

Taki, sì, non è un problema se la chiusura/attivazione di un ordine è controllata.
Bene e se il suo proprio array di tick, allora l'ordine mancherà.

ps. Lasciatemi aggiungere un altro caso - se un ordine pendente è impostato per fermare un ordine reale (per un rollover), allora quando lo stop viene attivato, l'ordine pendente può essere ritardato nell'apertura per un tempo indefinito. Cioè, un ordine sarà attivato dal mercato, mentre l'altro resterà appeso per un certo numero di tick...

 
fxsaber:

Ecco un'implementazione di questo

Solo che richiede ancora IsChange. Il timer non è affatto un'opzione. Anche Sleep(1) rovina tutto il quadro.

IsChange() è esattamente implementato nel timer (la versione di prova non è ancora stata terminata):

//+------------------------------------------------------------------+
//| Обновляет список ордеров                                         |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

La classe di controllo può catturare il cambiamento sia dal numero restituito da Refresh() di entrambe le classi (nel 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();
  }
//+------------------------------------------------------------------+

o in un evento utente, che non sono ancora implementati (demo, reale).

 
Artyom Trishkin:

IsChange() è esattamente ciò che è implementato nel timer (versione di prova non ancora completata):

Perché, se IsChange è di cinque righe?