Organisation des Auftragszyklus - Seite 9

 
fxsaber:

Geändert

Jetzt ohne Warnungen.

Die Antwort liegt auf der Hand: if Ticket == PrevTicket ---> return WRONG_VALUE.

Wenn die Funktion einen Wert kleiner als Null zurückgibt, sollte sie erneut aufgerufen werden.

 
Artyom Trishkin:

Die Antwort liegt auf der Hand: if Ticket == PrevTicket ---> return WRONG_VALUE.

Es handelt sich also um die Lösung eines Spezialfalls des Problems, das ich zur Verdeutlichung in Form der Gleichheit benachbarter Tickets beschrieben habe.

Das Problem ist eigentlich dasselbe - Indexierungsschwankungen während der Schleife. Dies kann dazu führen, dass ein Ticket übersprungen wird oder ein Ticket in einem Ticket wiederholt wird, usw.

Ich habe keine Alternative zu IsChange gefunden.

 
fxsaber:

Es handelt sich also um eine Lösung für einen Sonderfall des Problems, den ich zur Verdeutlichung in Form der Gleichheit benachbarter Fahrkarten beschrieben habe.

Das Problem ist eigentlich immer dasselbe: die Erschütterung der Indizierung während des Zyklus. Dies kann dazu führen, dass ein Ticket übersprungen wird oder ein Ticket in einem Ticket wiederholt wird, usw.

Ich habe keine Alternative zu IsChange gefunden.

Wir erstellen eine Liste im Timer und arbeiten mit ihr.

 
Artyom Trishkin:

Erstellen Sie eine Liste im Timer und arbeiten Sie mit ihr.

Besser im Code.

 
fxsaber:

Besser im Code.

Es ist sehr schwierig, dies im Code darzustellen - es gibt eine ganze Bibliothek von miteinander verbundenen Klassen.

Die Idee ist die folgende - wir übergeben alle Aufträge und Positionen auf dem Konto und füllen die CArrayObj Liste im Timer. Wir aktualisieren sie ständig, um aktuelle Informationen in einem Durchgang zu erhalten.

Wenn es notwendig ist, Positionen zu schließen oder Aufträge zu löschen, holen wir uns diese Liste und wählen daraus die notwendigen Auftragsobjekte und deren Tickets aus, die für die Schließungsfunktionen (Änderungen) benötigt werden. Wenn dieses Auftragsobjekt physisch nicht vorhanden ist (es wurde während dieser Aktionen geschlossen oder gelöscht), gehen wir einfach zum nächsten Objekt in der Liste über, da dieses bereits geschlossen wurde, und die Liste wird bei der nächsten Iteration des Zeitgebers aktualisiert. Das erste Problem, das mir in den Sinn kommt, ist, dass die Liste irrelevant ist, wenn sich das Handelsumfeld während der Zeit, in der die Aktionen auf der Liste durchgeführt werden, ändert. Aber wie ich es sehe, sollte uns das physische Fehlen eines Auftrags in der Liste nicht allzu sehr stören - wir erhalten einfach eine Fehlermeldung und gehen zum nächsten in der Liste über - diese Liste wird nicht wie in einer Handelsumgebung gemischt und ein Überspringen ist nicht möglich - nur eine Feststellung der Tatsache, dass ein Auftrag fehlt, der einem Eintrag in der Liste entspricht.

Das ist das, was ich mir bisher vorgestellt habe, da ich es noch nicht in meinem Code implementiert habe. Ich bin gerade dabei, mich auf die Implementierung vorzubereiten, aber zunächst muss ich einige andere Klassen fertigstellen (ich habe eine Frage zur Ersetzung von Funktionen in der Funktionsverzweigung gestellt). Wenn ich mit der Umsetzung beginne, werden dort mögliche Probleme sichtbar, und ich werde entscheiden, wie ich sie lösen und beheben kann.

 
Artyom Trishkin:

Die Antwort liegt auf der Hand: if Ticket == PrevTicket ---> return WRONG_VALUE.

Wenn die Funktion einen Wert kleiner als Null zurückgibt, müssen wir sie erneut aufrufen.

Sie müssen überhaupt nichts tun. Es genügt, der Logik zu folgen und wie ein Idiot auszusehen.

Wir haben 6 Aufträge

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

Wir beginnen mit der Durchsicht der Aufträge für, sagen wir, Änderungen,

Wir wählen 5 Tickets 105, prüfen, ob wir sie ändern wollen und ändern sie.

Zu diesem Zeitpunkt löschten unsere unsauberen Hände den Auftrag 2 Ticket 102, und die Liste änderte sich. Der Auftrag mit Ticket 105 ist nun der vierte, 4, in der Liste und wird erneut zur Änderung ausgewählt. Aber wir arbeiten nicht ohne Kontrolle... wir haben geprüft, ob er geändert werden sollte, ABER!!! Das tut es nicht... Na und? Wer wurde geschädigt, weil der Auftrag neu ausgewählt wurde?

 
Artyom Trishkin:

Es ist sehr schwierig, dies im Code darzustellen - es gibt eine ganze Bibliothek von miteinander verbundenen Klassen.

Die Idee ist die folgende - wir übergeben alle Aufträge und Positionen auf dem Konto und füllen die CArrayObj Liste im Timer. Wir aktualisieren sie ständig, um aktuelle Informationen in einem Durchgang zu erhalten.

Wenn es notwendig ist, Positionen zu schließen oder Aufträge zu löschen, holen wir uns diese Liste und wählen daraus die notwendigen Auftragsobjekte und deren Tickets aus, die für die Schließungsfunktionen (Änderungen) benötigt werden. Wenn dieses Auftragsobjekt physisch nicht vorhanden ist (geschlossen oder gelöscht während dieser Aktionen), gehen wir einfach zum nächsten Objekt in der Liste über, da dieses bereits geschlossen wurde, und die Liste wird bei der nächsten Iteration des Zeitgebers aktualisiert. Das erste Problem, das mir in den Sinn kommt, ist, dass die Liste irrelevant ist, wenn sich das Handelsumfeld während der Zeit, in der die Aktionen auf der Liste stattfinden, ändert. Aber wie ich es sehe, sollte uns das physische Fehlen eines Auftrags in der Liste nicht allzu sehr stören - wir erhalten einfach eine Fehlermeldung und gehen zum nächsten in der Liste über - diese Liste wird nicht wie in einer Handelsumgebung gemischt und ein Überspringen ist nicht möglich - nur eine Feststellung der Tatsache, dass ein Auftrag fehlt, der einem Eintrag in der Liste entspricht.

Das ist das, was ich bis jetzt denke, da ich es noch nicht in meinen Code implementiert habe. Ich bin gerade dabei, mich auf die Implementierung vorzubereiten, aber zunächst muss ich einige andere Klassen fertigstellen (ich habe eine Frage zur Ersetzung von Funktionen in der Funktionsverzweigung gestellt). Wenn ich mit der Umsetzung beginne, werden mögliche Probleme sichtbar, und ich werde entscheiden, wie sie zu lösen und zu beheben sind.

Hier ist eine Umsetzung dieser Idee

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Organisieren einer Auftragsschleife

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


Nach dem Senden eines Handelsauftrags ändert sich die Handelsumgebung, daher ist es ratsam, die gesamte Handelslogik des TS unmittelbar nach der Antwort des Handelsservers von Grund auf neu auszuführen.

Nur ist dafür immer noch IsChange erforderlich. Der Timer ist überhaupt keine Option. Auch Sleep(1) verdirbt das Gesamtbild.

 
Alexey Viktorov:

Es muss absolut nichts getan werden. Es reicht, wenn man mit dem Blick eines Idioten durch die Logik geht.

Taki, ja, das ist kein Problem, wenn das Schließen/Aktivieren eines Auftrags angekreuzt ist.
Nun, und wenn seine eigene Reihe von Ticks, dann wird der Auftrag nur verpassen.

ps. Ich möchte noch einen weiteren Fall anführen: Wenn ein schwebender Auftrag so eingestellt ist, dass er den echten Auftrag stoppt (für einen Rollover), dann kann die Öffnung des schwebenden Auftrags für eine unbestimmte Zeit verzögert werden, wenn der Stopp ausgelöst wird. Das heißt, ein Auftrag wird durch den Markt ausgelöst, während der andere für eine bestimmte Anzahl von Ticks hängen bleibt...

 
fxsaber:

Hier ist eine Umsetzung dieser Idee

Nur ist dafür immer noch IsChange erforderlich. Der Timer ist überhaupt keine Option. Auch Sleep(1) verdirbt das Gesamtbild.

IsChange() ist im Timer genau implementiert (die Testversion ist noch nicht fertig):

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

Die Kontrollklasse kann die Änderung entweder durch die von Refresh() zurückgegebene Zahl beider Klassen (im Tester) erfassen:

//+------------------------------------------------------------------+
//| Таймер                                                           |
//+------------------------------------------------------------------+
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();
  }
//+------------------------------------------------------------------+

oder in einem Benutzerereignis, die noch nicht implementiert sind (Demo, Real).

 
Artyom Trishkin:

IsChange() ist genau das, was im Timer implementiert ist (noch nicht fertiggestellte Testversion):

Warum, wenn IsChange fünf Zeilen beträgt?