Erreurs, bugs, questions - page 2452

 
Sergey Dzyublik:

L'ont-ils inventé eux-mêmes ou est-ce écrit quelque part ?
Je vous rappelle que c'est le travail de l'opérateur d'affectation implicite pour les structures avec des tableaux dynamiques.

Ce n'était pas mon idée, c'était celle des développeurs.

        uchar a[], b[]; a = b; //Error: invalid array access
Pourquoi y a-t-il une erreur ? Vous l'avez enveloppé dans une structure et l'erreur a disparu ? Et pourquoi ? Qu'est-ce qui a fondamentalement changé ? Mes réponses ci-dessus
 
Alexey Viktorov:

Il s'agit seulement d'organiser la séquence des actions et des événements.

Vous avez vous-même cité le manuel, qui dit que la cohérence n'est pas garantie. C'est pourquoi il est risqué.

J'ai déjà commencé à réécrire le code selon les conseils de Vladimir, mais je suis tombé sur un cas où la fermeture est plus longue qu'un tick - double comptage à nouveau (le nœud de filtre dans le comptage est très lourd). Jusqu'à présent, je n'ai rien trouvé de mieux que de s'arrêter avant la fermeture complète pour faire un compromis avec la vitesse d'optimisation.

C'est vendredi :) Peut-être qu'après un peu de repos, je trouverai quelque chose.

En tout cas, merci pour les idées - elles ne seront pas perdues !

 
A100:

Ce n'était pas mon idée, c'était celle des développeurs.

Je n'ai jamais compris où c'était écrit, mais peu importe...
Merci pour le cholivar.

Il l'a soutenu avec une béquille et a continué à courir :

struct MyArray{
   uchar data[];
   
   void operator=(MyArray &bytes){
      ArrayCopy(this.data, bytes.data);
      ArrayResize(this.data, ArraySize(bytes.data));
   }
};


MyArray GetArray(int i){
   MyArray arr;
   
   if (i%2 == 0){
      ArrayResize(arr.data, 8);
      ArrayInitialize(arr.data, 0x8);
   }else{
      ArrayResize(arr.data, 4);
      ArrayInitialize(arr.data, 0x4);
   }
   return arr;
}


void OnStart(){
   MyArray arr_1 = GetArray(1);
   ArrayPrint(arr_1.data);        // 4 4 4 4
   
   MyArray arr_2 = GetArray(2);
   ArrayPrint(arr_2.data);        // 8 8 8 8 8 8 8 8
   
   arr_2 = arr_1;
   ArrayPrint(arr_2.data);        // 4 4 4 4            
}
 
Igor Zakharov:

Vous avez vous-même cité le manuel, qui dit que la cohérence n'est pas garantie. C'est pourquoi il est risqué.

J'ai déjà commencé à réécrire le code selon les conseils de Vladimir, mais je suis tombé sur un cas où la fermeture est plus longue qu'un tick - double comptage à nouveau (le nœud de filtre dans le comptage est très lourd). Jusqu'à présent, je n'ai rien trouvé de mieux que de s'arrêter avant la fermeture complète pour faire un compromis avec la vitesse d'optimisation.

C'est vendredi :) Peut-être qu'après un peu de repos, je trouverai quelque chose.

Quoi qu'il en soit, merci pour ces idées - elles ne seront pas gâchées !

Je parlais de ma propre cohérence.

D'après mes observations, il s'avère qu'après OnTick, lorsque la transaction se produit, l'exécution du code est transmise à la fonction OnTradeTransaction sans attendre le prochain tick. Par conséquent, il n'y a aucune différence entre le traitement de la clôture par ses propres fonctions ou par OnTradeTransaction. Mais je préfère travailler avec OnTradeTransaction. L'essentiel est d'organiser correctement la séquence des opérations sans dépendre de la séquence des transactions provenant du serveur. Et il est important de bien comprendre cette séquence. Encore une fois, selon mes propres observations, la séquence peut être divisée en type de transaction. C'est-à-dire que TRADE_TRANSACTION_DEAL_ADD peut être exécuté en premier , et ensuite TRADE_TRANSACTION_HISTORY_ADD, alors que logiquement un ordre devrait d'abord être ajouté à l'historique et ensuite une transaction.

ps ; Ensuite, comme je l'ai dit, en contrôlant la transaction TRADE_TRANSACTION_DEAL_ADD vous pouvez contrôler par ouverture de position et par fermeture de position. Après tout, nous parlons d'un conseiller expert pour le marché des changes et d'un compte, n'est-ce pas ? Il n'est donc pas nécessaire de recalculer toutes les positions à chaque éternuement. Il suffit d'en ajouter un s'il a été ouvert, ou d'en supprimer un parmi ceux comptabilisés s'il a été fermé.
 
Alexey Viktorov:

du marché des changes et du compte, non ?

Grille :) Oui.

La logique actuelle est la suivante : il y a une structure qui stocke toutes les informations sur chaque grille : symbole-nombre de positions-bénéfice du lot et quelques autres choses sans importance... Le bénéfice est recalculé par le timer, s'il y a des ordres (robot multi-symboles). Mais les lots et la quantité étaient recalculés dans OnTradeTransaction (au cas où l'utilisateur "aidait").

Je voulais vérifier un cas où une grille, par exemple, est en profit de 100$, et l'autre est en perte de 50$ - pour fermer les deux avec un profit de 50$ pour l'empêcher de croître.

Pour l'instant, c'est ce que j'ai fait :

void  OnTradeTransaction(
   const MqlTradeTransaction&    trans,     // trade transaction structure 
   const MqlTradeRequest&        reqst,     // request structure 
   const MqlTradeResult&         reslt      // response structure 
    )
{
 int index=-1;
 for(index=0;index<symbols_total;index++)
  if(ARRAY[index].symbol==trans.symbol) break; //нашли индекс символа по которому прошла трансакция в массиве структур
 
 if(index>=0) CountOrders(index); //пересчитали элемент
}

Jusqu'à présent, j'ai ajoutéCountOrders()après avoir fermé quelques grilles. Pour un testeur de stratégie, ça marche. Pour un compte réel, je vais utiliser le schéma de Vladimir (avec un tableau de tickets fermés).

D'ailleurs, la fermeture de la paire ne s'est pas justifiée - le drawdown ne diminue pas considérablement, alors que le profit diminue décemment.

 
Vladimir Karputov:

Je renoncerais à TOUTES les fonctions while, Sleep et OnTimer pour la tâche de fermeture des positions. Je ferais la chose suivante : lancer des ordres de clôture - sortie OnTick, au prochain tick vérifier : si les positions avec les tickets nécessaires sont toujours en vie - lancer des ordres de clôture à nouveau et ainsi de suite en cercle par l'entrée/sortie à OnTick.

La logique est la suivante : la fermeture d'une position est la première priorité, donc la boucle de fermeture est au tout début de OnTick. Et la formation d'un tableau de tickets de fermeture peut se faire à n'importe quel endroit de OnTick - même à la toute fin.

Tôt ou tard, vous vous retrouverez dans la situation suivante : vous devez clôturer une position, un ordre de clôture est envoyé (MQL5), c'est-à-dire qu'un ordre du type opposé est envoyé, puisque vous ne suivez pas les actions de trading dans le gestionnaire approprié (ou que vous ne sauvegardez pas l'état de la position dans votre EA) et au tick suivant, un ordre de clôture peut être en train d'être envoyé et vous enverrez un autre ordre. Le résultat est une position dans la direction opposée.

 
Alexey Kozitsyn:

Tôt ou tard, vous vous retrouverez dans la situation suivante : vous devez fermer une position, vous envoyez un ordre de fermeture (MQL5), c'est-à-dire que vous envoyez un ordre du type opposé, puisque vous ne suivez pas les actions commerciales dans le gestionnaire correspondant (ou que vous ne sauvegardez pas l'état de la position dans votre EA) et au tick suivant, un ordre de fermeture est peut-être en train d'être envoyé, mais vous envoyez un autre ordre. Le résultat est une position dans la direction opposée.

Pour un tel cas, nous avons :

10036

TRADE_RETCODE_POSITION_CLOSED

Laposition avec le POSITION_IDENTIFIERspécifié a déjà été fermée.

La position de fermeture est envoyée avec le ticket de la position à fermer, il est donc peu probable que votre description se produise.

 
Sergey Dzyublik:

Je n'ai jamais compris où c'était écrit, mais peu importe...
Merci pour le cholivar.

Il l'a soutenu avec une béquille et a continué à courir :

Eh bien, c'est étrange la façon dont les tableaux sont copiés, mais certaines personnes aiment ça...

J'ai fait un enveloppement plus ou moins adéquat sur un tableau et je n'ai aucun problème.

https://www.mql5.com/ru/forum/221917/page26#comment_11233214

 
A100:

Ce n'était pas mon idée, c'était celle des développeurs.

Je ne me souviens pas qu'ils aient jamais dit ça.

L'opérateur d'assignation est destiné à créer une copie identique d'un objet. C'est son but. Lorsque vous assimilez quelque chose à quelque chose, vous devriez évidemment obtenir une copie complète du côté gauche, et pas autre chose. Il y a donc manifestement un bug ici.

 
Alexey Navoykov:

L'opérateur d'assignation est destiné à créer une copie identique d'un objet. C'est sa signification. Lorsque vous assimilez quelque chose à quelque chose, vous devriez évidemment obtenir une copie complète du côté gauche, et non une fichue chose. Il y a donc un bug évident ici.

Le fait est que l'opérateur d'affectation n'est pas défini pour un tableau :

void OnStart()
{
        uchar  a[], b[];
        a = b; ////Error: invalid array access
}

Ça n'existe pas... ...donc tous les arguments sur son utilité, son bon fonctionnement ou non, sont sans intérêt.