Apprendre et écrire ensemble en MQL5 - page 35

 

Qui sait si je peux passer une fonction non membre d'une classe comme argument à une référence (adresse) à une autre fonction qui n'est pas membre d'une classe du tout ?

Ou bien, puis-je passer à une fonction membre d'une classe comme argument une référence (adresse) à une autre fonction qui n'est pas membre d'une classe du tout ?

Документация по MQL5: Основы языка / Типы данных / Структуры и классы
Документация по MQL5: Основы языка / Типы данных / Структуры и классы
  • www.mql5.com
Основы языка / Типы данных / Структуры и классы - Документация по MQL5
 
victorg:

Qui sait si je peux passer une fonction non membre d'une classe comme argument à une référence (adresse) à une autre fonction qui n'est pas membre d'une classe du tout ?

Ou, puis-je passer à une fonction membre d'une classe comme argument une référence (adresse) à une autre fonction qui n'est pas membre d'une classe du tout ?

Non. Non.

Tu ne peux pas. Dans MQL5, il n'existe pas de notion telle que "une adresse de fonction" ou "une référence de fonction".

 

Merci !

Une autre question.

Il y a deux fichiers avec du code dans mql5.Le premier fichier estle principal - indicateur ou script . Ledeuxième fichier estmqh.

// f_01.mqh
double extfunc(int a);
//-------------------------------------
double example(void)
  {
  double a;
  a=extfunc(35);
  return(a);
  }
//-------------------------------------
Lesecondfichier mqh est connecté au fichier principal au tout début. La compilation du fichier principal se déroule sans erreur ni avertissement. Mais lorsque j'essaie de compiler le fichier mqh séparément , j'obtiens ' lafonction doit avoir uncorps '.Ma question est la suivante : comment puis-je dire au compilateur qu'il n'y a aucun problème avec la fonction, mais que son corps se trouve dans un fichier différent ?


Документация по MQL5: Файловые операции / FileMove
Документация по MQL5: Файловые операции / FileMove
  • www.mql5.com
Файловые операции / FileMove - Документация по MQL5
 
victorg:

Ledeuxièmefichier mqh est inclus au début du fichier principal. La compilation du fichier principal se déroule sans erreurs ni avertissements. Mais lorsqu'on essaie de compiler le fichier mqh séparément , on obtient ' lafonction doit avoir uncorps '.Ma question est la suivante : comment dire au compilateur qu'il n'y a pas de problème avec la fonction mais que son corps se trouve dans un autre fichier ?
Il n'y a pas moyen. Ne le mettez pas en pièces, cela ne facilite pas la compréhension lors de la lecture du code.
 
Yedelkin:

Je réagis peut-être de manière excessive, mais voici une autre question. Avant d'envoyer une requête pour placer un ordre au marché (pour ouvrir une position), je remets un ticket de transaction à zéro, c'est-à-dire que je fais en sorte que result.deal=0. Peut-on s'attendre à ce que le serveur renvoie un ticket de transaction nul dans la structure de réponse MqlTradeResult, mais qu'un peu plus tard, la transaction soit exécutée et que la position soit ouverte ? Ou bien le retour d'un ticket de transaction nul par le serveur garantira-t-il que la position n'a pas pu être ouverte et qu'elle ne sera plus ouverte sur la base de cette demande ?

OK, en vertu de l'absence de réponse et en vertu de cette ligne

struct MqlTradeResult
{
ulong deal ; // Ticket pour la transaction, si elle a été effectuée
} ;

J'en conclus que le retour d'un ticket de transaction nul par le serveur garantit que la position ne peut être ouverte et qu'elle ne sera plus ouverte sur la base de cette demande.

 

Je ne comprends pas bien la structure du forum, si ce n'est pas le cas, veuillez m'orienter dans la bonne direction.

N'étant pas un spécialiste, mais intéressé par la programmation et partant de mes propres inclinations dans le processus de formation, j'essaie de comprendre en analysant le code existant

Pour simplifier, j'ai pris un morceau de code personnalisé de MA , et j'essaie de comprendre ce qui s'y passe (je l'ai reflété dans les commentaires).

En général, si ce n'est pas difficile, veuillez commenter le code, je veux comprendre ce qui se passe après chaque commande. Merci.

void CalculateSimpleMA(int rates_total,int prev_calculated,int begin,const double &price[])//Je l'ai compris &price[]

  {
   int i,limit;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)// first calculation
     {
      limit=InpMAPeriod+begin;                                               //почему переменная begin=0 ???
      //--- set empty value for first limit bars
      for(i=0;i<limit-1;i++) ExtLineBuffer[i]=0.0;                            //здесь инициализируются значения индикатора на барах с индексами от 0 до limit-1 ??? крайне правых на графике???
      //--- calculate first visible value
      double firstValue=0;                                                    //при инициализации переменной имеющей тип double не обязательно использовать значения типа double???
      for(i=begin;i<limit;i++)
         firstValue+=price[i];                                               //разобрался, здесь идет накопление переданной цены
      firstValue/=InpMAPeriod;
      ExtLineBuffer[limit-1]=firstValue;                                      
     }
   else limit=prev_calculated-1;                                              //в результате чего prev_calcutated не должно равняться 0, если индикатор поместили на оффлайн график?
//--- main loop
   for(i=limit;i<rates_total && !IsStopped();i++)                              //цикл для индикатора на баре с индексами от limit до последнего на графике
      ExtLineBuffer[i]=ExtLineBuffer[i-1]+(price[i]-price[i-InpMAPeriod])/InpMAPeriod;
//---
  }

mettez-le à l'impression et voyez que les valeurs dans le ExtLineBuffer sont assignées de l'index limit-1à l'index rates_total-1, mais dans le graphique l'indicateur est dessiné dans l'espace entier, hmm, alors où est l'assignation de valeur autampon de l'indicateur sur l'intervalle de 1 à limit-1? ??

Документация по MQL5: Основы языка / Операции и выражения / Операции присваивания
Документация по MQL5: Основы языка / Операции и выражения / Операции присваивания
  • www.mql5.com
Основы языка / Операции и выражения / Операции присваивания - Документация по MQL5
 
Profi_R:

Je ne comprends pas bien la structure du forum, si ce n'est pas le cas, veuillez m'orienter dans la bonne direction.

N'étant pas un spécialiste, mais intéressé par la programmation et partant de mes propres inclinations dans le processus de formation, j'essaie de comprendre en analysant le code existant

Pour simplifier, j'ai pris un morceau de code personnalisé de MA , et j'essaie de comprendre ce qui s'y passe (je l'ai reflété dans les commentaires).

Je veux comprendre ce qui se passe après chaque commande. Merci.

Je ne ferai pas de commentaires détaillés, cela peut suffire à corriger l'erreur de base de votre perception, et ensuite vous reconstituerez vous-même le puzzle - c'est beaucoup plus utile.

Ainsi, la base de votre confusion est que de nombreux indicateurs dans mql5 (celui-ci en particulier) sont écrits sans indexation des tampons d'indicateurs, c'est-à-dire avec la valeur AsSeries=false.

Cela signifie que l'indice de la barre la plus ancienne de l'historique = 0 et la plus "fraîche" = RatesTotal-1.

// Quelque chose est clair ?

L'intérêt d'une telle approche est un certain gain de vitesse, car l'indexation ne nécessite pas de recalcul [caché] lors de l'accès au tampon (il reste "matériel").

// Peut-être la croyance (erronée) que l'indexation des tampons indicateurs se produit TOUJOURS de la fin de l'histoire au début. C'est toujours vrai dans mql4, mais ce n'est pas nécessaire dans mql5.

// Ici, le sens de l'indexation va toujours du début de l'historique à sa fin par défaut. Pour inverser l'indexation, vous devez utiliser la fonction SetAsSeries(...) sous une forme explicite.

// Remarque, les développeurs ne recommandent pas d'utiliser les valeurs par défaut (au cas où elles changeraient) et utilisent TOUJOURS la fonction SetAsSeries() pour définir la direction de l'indexation.

void CalculateSimpleMA(int rates_total,int prev_calculated,int begin,const double &price[])//J'ai trié &price[]

mettez-le à l'impression et voyez que les valeurs dans le ExtLineBuffer sont assignées de l'index limit-1à l'index rates_total-1, mais dans le graphique l'indicateur est dessiné dans l'espace entier, hmm, alors où est la valeur assignée autampon de l'indicateur dans l'intervalle de 1 à limit-1?

Je pense que tu peux le découvrir par toi-même, mais juste au cas où, je vérifierai demain.
 
MetaDriver: ..

Merci pour vos commentaires).

J'ai lu des articles sur l'ordre de la directivité dans les tableaux et des recommandations pour spécifier explicitement la directivité dans l'aide, mais j'avais quelques doutes, qui ont été éliminés après le déblocage des données intermédiaires dans les variables.

Jusqu'à présent, seule la directionnalité est déterminée, c'est-à-dire que le commentaire sur l'initialisation était incorrect et que les valeurs de l'indicateur tampon sont initialisées sur la plage spécifiée sur le côté gauche du graphique.

Il y a encore des questions sur

1. la variable begin, le terminal est-il responsable de sa valeur passée au gestionnaire d'événement ?

2. Une variable de type double peut-elle être passée au type int ?

3. il semble que le terminal soit également responsable de la valeur de la variable prev_calculated

4. Il n'est pas clair où a lieu le calcul de l'indicateur sur l'intervalle de 0 à la limite-1 ?

Документация по MQL5: Основы языка / Функции / Функции обработки событий
Документация по MQL5: Основы языка / Функции / Функции обработки событий
  • www.mql5.com
Основы языка / Функции / Функции обработки событий - Документация по MQL5
 
Profi_R:

Il y a encore des questions sur

1. variable begin, le terminal est-il responsable de sa valeur envoyée au gestionnaire d'événements ?

3. il semble que la valeur de la variable prev_calculated soit également responsable du terminal

Très probablement, la fonction en question a été écrite pour la première forme d'appel de la fonction OnCalculate(). Voir la référence.

Profi_R:

Nous avons encore des questions sur

2. une variable de type double peut-elle être remplacée par une valeur de type int ?

Oui, vous pouvez. Voir la section sur la conversion implicite des types. Le compilateur émet souvent un avertissement concernant la perte possible de données lors de l'utilisation de la conversion implicite des types.

Profi_R:

Il y a encore des questions sur

4. je ne comprends pas où l'indicateur est calculé sur l'intervalle de 0 à la limite-1.

Ces lignes répondent-elles à votre question ?

//--- set empty value for first limit bars
      for(i=0;i<limit-1;i++) ExtLineBuffer[i]=0.0;                            
//--- calculate first visible value
... и далее по коду
?
 
Profi_R:

Merci pour vos commentaires).

J'ai lu des articles sur l'ordre de la directivité dans les tableaux et des recommandations pour spécifier explicitement la directivité dans l'aide, mais j'avais quelques doutes, qui ont été éliminés après le déblocage des données intermédiaires dans les variables.

Jusqu'à présent, seule la directionnalité est déterminée, c'est-à-dire que le commentaire sur l'initialisation était incorrect et que les valeurs de l'indicateur tampon sont initialisées sur la plage spécifiée sur le côté gauche du graphique.

OK.

Il y a encore des questions sur

1. la variable begin, le terminal est-il responsable de sa valeur envoyée au gestionnaire d'événements ?

Oui, le terminal est responsable de sa transmission à l'indicateur.


Ce paramètre indique à l'indicateur combien de valeurs historiques initiales de la série d'entrée doivent être ignorées (sautées), car elles sont incorrectes et ne doivent pas participer aux calculs. D'où peut venir une telle incorrection, quelle est son origine ? C'est lié à la possibilité de créer des indicateurs qui sont calculés non pas sur les données de prix, mais sur les données fournies par d'autres indicateurs. Dans MT5, il existe trois mécanismes qui permettent de recevoir les données d'un autre indicateur pour une entrée d'indicateur.

Méthode 1. Séquence d'étapes :

Créez un handle pour l'indicateur d'entrée en utilisant une des fonctions iIndicator(...) ou IndicatorCreate(...).

2. si nécessaire, prenez ses valeurs dans ses tampons à l'aide de la fonction CopyBuffer(...).

La deuxième voie. C'est nécessaire si dans le premier cas nous voulons passer à l'indicateur d'entrée non pas une série de prix, mais une série d'indicateurs. C'est-à-dire que dans ce cas nous allons recevoir des valeurs calculées par l'indicateur d'entrée (2) qui prend les données d'un autre indicateur (1) sur sa propre entrée. C'est-à-dire que nous voulons construire la chaîne indicateur-totalement-indicateur.

Séquence des étapes :

1. Créez un handle pour le premier (1) indicateur d'entrée en utilisant l'une des fonctions iIndicator(...) ou IndicatorCreate(...).

2. créer un handle du second indicateur (2) en utilisant la même méthode, mais en spécifiant le handle du premier (1) comme dernier paramètre(applied_price) lors de sa création.

Utilisez la fonction CopyBuffer(...) pour récupérer ses valeurs dans les tampons d'indicateurs, selon les besoins.

La troisième méthode est également utilisée pour construire des chaînes d'indicateurs, mais, contrairement à la méthode précédente, la source de données (séquence d'entrée) n'est pas fixée avant la compilation, elle peut être définie par un utilisateur directement dans le terminal, en spécifiant le paramètre approprié au moment du démarrage de l'indicateur.

Je vous laisse le soin de comprendre ces mécanismes par vous-même. J'ai fourni de nombreux liens directs dans le texte précédent vers les endroits clés de la documentation qui vous aideront à le faire.

Concentrons-nous uniquement sur les paramètres de la forme courte de l'appel de OnCalculate() :

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])

Leur objectif est très clairement documenté. Ici, je veux juste expliquer la nécessité (le caractère raisonnable) de les passer dans cette fonction. Avec le premier et le dernier paramètre, j'espère que tout est assez clair. Pour pouvoir effectuer des calculs, nous devons disposer d'un tampon contenant des données d'entrée (prix[]) et connaître sa longueur actuelle . (n'oubliez pas que sa longueur augmente à mesure que les guillemets remplissent la borne).

Mais en outre, nous devons également savoir dès le début de la ligne d'entrée que ses données sont strictement correctes ou que les valeurs initiales doivent être ignorées en raison de leur caractère incorrect (possible ou garanti). Dans la plupart des cas, l'inexactitude est garantie lorsque les données d'entrée sont la sortie d'un autre indicateur, mais comment faire autrement ? La plupart des indicateurs, pour calculer la valeur de n'importe quelle barre, doivent utiliser une certaine quantité de données historiques. Mais où peut-on les trouver "au début du temps" ? Elles n'y sont pas présentes, et elles sont donc obligées de commencer à générer leurs valeurs de sortie non pas à partir de la barre historique de départ, mais plus tard (à droite), à partir de la barre à gauche de laquelle la quantité nécessaire de données historiques existe déjà.

Maintenant, grâce aux détails que j'ai décrits ci-dessus, la réponse à la question

d'où vient sa valeur ? // nous parlons du paramètre begin

La réponse est la suivante : bien que ce paramètre soit passé dans la fonction par le terminal, l'indicateur d'entrée doit s'occuper de son contenu! Le terminal lui-même ne peut vérifier que les lignes d'entrée de prix (dans ce cas, la valeur de begin sera 0 et c'est une valeur correcte).Par conséquent, lorsque vous écrivez un indicateur (à l'exception des indicateurs purement expérimentaux), vous devez vous assurer qu' il informe le terminal de l'indice du début des données correctes dans son tampon de sortie. Est-ce clair ? Sinon, les "descendants" de cet indicateur peuvent manger des données incorrectes très désagréables, et dans certains cas, ils peuvent même tomber malades... :) Maintenant, comment faire, on utilise la fonction PlotIndexSetInteger(), en spécifiant l'identifiant de la propriété PLOT_DRAW_BEGIN. Important ! Pour que la propriété de l'indicateur généré soit 100% correcte, un seul appel de PlotIndexSetInteger(....PLOT_DRAW_BEGIN, ...) in OnInit() ! Pourquoi ? Parce que notre indicateur peut être lui-même formé sur les données d'un autre indicateur, qui a un retrait initial sur l'historique. C'est-à-dire que nous avons une valeur non nulle de begin sur l'historique d'entrée, et il n'y a aucune possibilité de la recevoir dans OnInit().

  PlotIndexSetInteger(MySymbol,PLOT_DRAW_BEGIN,MyBeginPeriod-1+begin);

Et nous devons le faire (de préférence une fois) dans OnCalculate(), car dans OnInit la valeur de begin est inconnue.

Ce qui nous laisse bien sûr le droit de faire un appel préliminaire (bien que peu significatif) également

  PlotIndexSetInteger(MySymbol,PLOT_DRAW_BEGIN,MyBeginPeriod);

Dans OnInit().

C'est exactement ce qui est fait dans cet indicateur (Custom Moving Average.mq5) duquel vous avez pris votre échantillon pour l'étudier.

2. Une variable de type double peut-elle être de type int ?

Oui, une variable de type double peut être initialisée sans problème avec une valeur de type int, si elle est définie par une constante. // ce qui est exactement ce que nous pouvons faire dans votre exemple.

3. il semble que le terminal soit également responsable de la valeur de la variable prev_calculated

Il y a une subtilité ici. Dans la plupart des cas, cette valeur sera égale à la valeur renvoyée par la fonction OnCalculate() de l'appel précédent. En d'autres termes, en fait, elle est entre vos mains. D'autre part, au premier appel, il y aura une valeur nulle. De plus, la valeur peut être remise à zéro (par le terminal) quand le terminal le souhaite. Par exemple, cela peut se produire lors de la correction des cours par un courtier, lors du redémarrage de la communication après une interruption, lors de la réinitialisation d'un indicateur (d'entrée) précédent, etc.

4. il n'est pas clair où dans l'intervalle de 0 à la limite-1 l'indicateur est calculé

Dans ce cas, ces valeurs ne peuvent pas être calculées correctement (nous n'avons pas assez d'historique pour les calculs), c'est pourquoi on leur attribue simplement des valeurs nulles.

// Je préférerais leur attribuer des données d'entrée correspondantes, mais cela ne change pas l'essence de la question.