Gemeinsam lernen und schreiben in MQL5 - Seite 35

 

Wer weiß, ob ich eine Funktion an ein Nichtmitglied einer Klasse als Argument für einen Verweis (Adresse) auf eine andere Funktion übergeben kann, die überhaupt kein Mitglied einer Klasse ist?

Oder kann ich einer Funktion, die Mitglied einer Klasse ist, als Argument einen Verweis (eine Adresse) auf eine andere Funktion übergeben, die überhaupt nicht Mitglied einer Klasse ist?

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

Wer weiß, ob ich eine Funktion an ein Nichtmitglied einer Klasse als Argument für einen Verweis (Adresse) auf eine andere Funktion übergeben kann, die überhaupt kein Mitglied einer Klasse ist?

Oder kann ich einer Funktion, die Mitglied einer Klasse ist, als Argument einen Verweis (eine Adresse) auf eine andere Funktion übergeben, die überhaupt nicht Mitglied einer Klasse ist?

Nein. Nein.

Das können Sie nicht. In MQL5 gibt es keinen solchen Begriff wie "Funktionsadresse" oder "Funktionsreferenz".

 

Ich danke Ihnen!

Eine andere Frage.

Es gibt zwei Dateien mit Code in mql5.Die erste Datei ist die Hauptdatei - Indikator oder Skript. Diezweite Datei istmqh.

// f_01.mqh
double extfunc(int a);
//-------------------------------------
double example(void)
  {
  double a;
  a=extfunc(35);
  return(a);
  }
//-------------------------------------
Diezweitemqh-Datei wird ganz am Anfang mit der Hauptdatei verbunden. Die Kompilierung der Hauptdatei verläuft ohne Fehler oder Warnungen. Aber wenn ich versuche, die mqh-Datei separat zu kompilieren , erhalte ich die Meldung " Funktion muss einen Körperhaben". Meine Frage ist, wie kann ich dem Compiler mitteilen, dass mit der Funktion alles in Ordnung ist, aber ihr Körper in einer anderen Datei steht?


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

Die zweitemqh-Datei wird am Anfang der Hauptdatei eingefügt. Die Kompilierung der Hauptdatei verläuft ohne Fehler und Warnungen. Wenn wir jedoch versuchen, die mqh-Datei separat zu kompilieren , erhalten wir die Meldung: " DieFunktion muss einen Körperhaben". Meine Frage ist: Wie kann ich dem Compiler mitteilen, dass die Funktion in Ordnung ist, aber ihr Körper sich in einer anderen Datei befindet?
Das ist nicht möglich. Zerreißen Sie es nicht, das macht es beim Lesen des Codes nicht leichter zu verstehen.
 
Yedelkin:

Vielleicht reagiere ich über, aber ich habe eine andere Frage. Bevor ich eine Anfrage zur Platzierung einer Marktorder (zur Eröffnung einer Position) sende, setze ich ein Handelsticket auf Null zurück, d.h. ich mache result.deal=0. Können wir erwarten, dass der Server in der MqlTradeResult-Antwortstruktur ein Null-Handels-Ticket zurückgibt, aber etwas später wird der Handel ausgeführt und die Position eröffnet? Oder garantiert die Rückgabe eines Null-Handels-Tickets durch den Server, dass die Position nicht eröffnet werden konnte und dass sie auf der Grundlage dieser Anfrage nicht weiter eröffnet werden wird?

OK, wegen des Mangels an Antworten und aufgrund dieser Zeile

struct MqlTradeResult
{
ulong deal; // Ticket zu deal, wenn es gemacht wurde
};

Daraus schließe ich, dass die Rückgabe eines Null-Geschäfts-Tickets durch den Server garantiert, dass die Position nicht geöffnet werden kann und dass sie auf der Grundlage dieser Anfrage nicht weiter geöffnet werden wird.

 

Ich verstehe die Struktur des Forums nicht ganz, wenn nicht dort, bitte leiten Sie mich in die richtige Richtung

Da ich kein Spezialist bin, mich aber für das Programmieren interessiere und von meinen eigenen Neigungen bei der Ausbildung ausgehe, versuche ich, durch die Analyse des vorhandenen Codes zu verstehen

Der Einfachheit halber nahm ich ein Stück benutzerdefinierten Code von MA, und versuchen zu verstehen, was darin vorkommt (ich spiegelte es in Kommentaren)

Im Allgemeinen, wenn nicht schwierig, bitte kommentieren Sie den Code, ich möchte verstehen, was nach jedem Befehl passiert. Ich danke Ihnen.

void CalculateSimpleMA(int rates_total,int prev_calculated,int begin,const double &price[])//Ich habe es herausgefunden &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;
//---
  }

legen Sie es in den Ausdruck und sehen Sie, dass die Werte im ExtLineBuffer vom Index limit-1bis zum Index rates_total-1 zugewiesen werden, aber im Diagramm wird der Indikator im gesamten Raum gezeichnet, hmm, wo ist dann die Wertzuweisung an denIndikatorpuffer auf dem Intervall von 1 bis limit-1??

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

Ich verstehe die Struktur des Forums nicht ganz, wenn nicht dort, bitte leiten Sie mich in die richtige Richtung

Da ich kein Spezialist bin, mich aber für das Programmieren interessiere und von meinen eigenen Neigungen bei der Ausbildung ausgehe, versuche ich, durch die Analyse des vorhandenen Codes zu verstehen

Der Einfachheit halber habe ich einen Teil des benutzerdefinierten Codes von MA genommen und versucht zu verstehen, was darin passiert (ich habe es in Kommentaren wiedergegeben)

Ich möchte verstehen, was nach jedem Befehl passiert. Ich danke Ihnen.

Ich werde mich nicht im Detail äußern, es mag genügen, den grundlegenden Fehler in Ihrer Wahrnehmung zu korrigieren, und dann werden Sie das Puzzle selbst zusammensetzen - das ist viel nützlicher.

Der Grund für Ihre Verwirrung ist also, dass viele Indikatoren in mql5 (insbesondere dieser) ohne Indexierung der Indikatorpuffer geschrieben werden, d.h. mit dem Wert AsSeries=false.

Das bedeutet, dass der Index des ältesten Balkens in der Historie = 0 und der "frischeste" Balken = RatesTotal-1 ist.

// Ist etwas klar?

Der Sinn eines solchen Ansatzes ist ein gewisser Geschwindigkeitsgewinn, da die Indexierung beim Zugriff auf den Puffer keine [versteckte] Neuberechnung erfordert (sie bleibt "hardwaremäßig")

// Vielleicht der (irrige) Glaube, dass die Indizierung für Indikatorpuffer IMMER vom Ende der Geschichte zum Anfang erfolgt. In mql4 ist dies immer der Fall, aber in mql5 ist es nicht notwendig.

// Hier ist die Richtung der Indizierung standardmäßig immer vom Anfang der Historie zu ihrem Ende. Um die Indizierung umzukehren, sollten Sie die Funktion SetAsSeries(...) in expliziter Form verwenden.

// Hinweis: Die Entwickler empfehlen, keine Standardwerte zu verwenden (für den Fall, dass sie sich ändern) und IMMER die Funktion SetAsSeries() zu verwenden, um die Indizierungsrichtung festzulegen.

void CalculateSimpleMA(int rates_total,int prev_calculated,int begin,const double &price[])//Ich habe &price[] aussortiert

setzen Sie es auf den Ausdruck und sehen Sie, dass die Werte im ExtLineBuffer vom Index limit-1bis zum Index rates_total-1 zugewiesen sind, aber im Diagramm wird der Indikator im gesamten Raum gezeichnet, hmm, wo ist dann der Wert, der demIndikatorpuffer im Intervall von 1 bis limit-1 zugewiesen ist?

Ich denke, Sie können es selbst herausfinden, aber sicherheitshalber werde ich es morgen noch einmal überprüfen.
 
MetaDriver: ..

Vielen Dank für Ihr Feedback).

Ich habe über die Reihenfolge der Richtwirkung in Arrays und Empfehlungen zur expliziten Angabe der Richtwirkung in der Hilfe gelesen, aber ich hatte einige Zweifel, die nach der Aufhebung von Zwischendaten in den Variablen beseitigt wurden.

Bisher ist nur die Direktionalität festgelegt, d.h. der Kommentar zur Initialisierung war falsch und die Werte des Indikatorpuffers werden auf den angegebenen Bereich auf der linken Seite des Charts initialisiert.

Es gibt noch Fragen über

1. die Variable begin, ist das Terminal für ihren Wert verantwortlich, der an den Event-Handler übergeben wird?

2. Kann eine Variable vom Typ double an den Typ int übergeben werden?

3. es scheint, dass das Terminal auch für den Wert der Variablen prev_calculated verantwortlich ist

4. Es ist nicht klar, wo die Berechnung des Indikators auf dem Intervall von 0 bis Grenze-1 stattfindet.

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

Es gibt noch Fragen zu

1. die Variable begin, ist das Terminal dafür verantwortlich, dass ihr Wert an den Event-Handler gesendet wird?

3. es scheint, dass der Wert der Variablen prev_calculated auch für das Terminal verantwortlich ist

Höchstwahrscheinlich wurde die diskutierte Funktion für die erste Form des OnCalculate()-Funktionsaufrufs geschrieben. Siehe Referenz.

Profi_R:

Wir haben noch Fragen zu

2) Kann eine Variable vom Typ double durch einen Wert vom Typ int ersetzt werden?

Ja, das können Sie. Siehe den Abschnitt über implizite Typkonvertierung. Der Compiler gibt oft eine Warnung über den möglichen Verlust von Daten aus, wenn eine implizite Typkonvertierung verwendet wird.

Profi_R:

Dennoch gibt es Fragen über

4. ich verstehe nicht, wo der Indikator auf dem Intervall von 0 bis Grenze-1 berechnet wird.

Beantworten diese Zeilen Ihre Frage:

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

Vielen Dank für Ihr Feedback).

Ich habe über die Reihenfolge der Richtwirkung in Arrays und Empfehlungen zur expliziten Angabe der Richtwirkung in der Hilfe gelesen, aber ich hatte einige Zweifel, die nach der Aufhebung von Zwischendaten in den Variablen beseitigt wurden.

Bisher ist nur die Direktionalität festgelegt, d.h. der Kommentar zur Initialisierung war falsch und die Werte des Indikatorpuffers werden auf den angegebenen Bereich auf der linken Seite des Charts initialisiert.

GUT.

Es gibt noch Fragen zu

1. die Variable begin, ist das Terminal dafür verantwortlich, dass ihr Wert an den Event-Handler gesendet wird?

Ja, das Terminal ist für die Übermittlung an den Indikator verantwortlich.


Dieser Parameter gibt dem Indikator an, wie viele anfängliche historische Werte der Eingabereihen ignoriert (übersprungen) werden sollen, weil sie falsch sind und nicht an den Berechnungen teilnehmen sollen. Woher kann eine solche Unrichtigkeit kommen, was ist ihr Ursprung? Dies hängt mit der Möglichkeit zusammen, Indikatoren zu erstellen, die nicht auf der Grundlage von Preisdaten, sondern auf der Grundlage von Daten anderer Indikatoren berechnet werden. In MT5 gibt es drei Mechanismen, die es ermöglichen, Daten eines anderen Indikators für die Eingabe eines Indikators zu erhalten.

Methode 1. Abfolge der Schritte:

Erstellen Sie ein Handle für den Eingabe-Indikator mit einem der iIndicator(...)-Funktionen oder IndicatorCreate(...).

2. bei Bedarf die Werte aus den Puffern mit der Funktion CopyBuffer(...) übernehmen.

Der zweite Weg. Sie ist notwendig, wenn wir im ersten Fall nicht eine Preisreihe, sondern eine Indikatorreihe an den Eingangsindikator weitergeben wollen. D.h., in diesem Fall werden wir Werte erhalten, die vom Eingangsindikator (2) berechnet werden, der Daten eines anderen Indikators (1) auf seinem eigenen Input nimmt. D.h., wir wollen die Indikator-aus-Indikator-Kette aufbauen.

Abfolge der Schritte:

1. Erstellen Sie ein Handle für den ersten (1) Eingangsindikator mit einem der iIndicator(...)-Funktionen oder der Funktion IndicatorCreate(...).

2. Erstellen Sie ein Handle des zweiten (2) Indikators mit der gleichen Methode, aber geben Sie das Handle des ersten (1) als letzten Parameter an(applied_price), wenn Sie es erstellen.

Verwenden Sie die Funktion CopyBuffer(...), um die Werte aus den Indikatorpuffern nach Bedarf abzurufen.

Die dritte Methode wird auch für die Bildung von Indikatorenketten verwendet, aber im Gegensatz zur vorherigen Methode ist die Datenquelle (Eingabereihenfolge) nicht vor der Kompilierung festgelegt, sondern kann vom Benutzer direkt im Terminal eingestellt werden, indem der entsprechende Parameter beim Start des Indikators angegeben wird.

Ich werde es Ihnen überlassen, diese Mechanismen selbst zu verstehen. Ich habe im vorangegangenen Text viele direkte Links zu den wichtigsten Stellen in der Dokumentation angegeben, die Ihnen dabei helfen werden.

Konzentrieren wir uns nur auf die Parameter der Kurzform des Aufrufs von OnCalculate():

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

Ihr Zweck ist ganz klar dokumentiert. Hier möchte ich nur die Notwendigkeit (Sinnhaftigkeit) der Übergabe in diese Funktion erklären. Mit dem ersten und letzten Parameter ist hoffentlich alles klar genug. Um Berechnungen durchführen zu können, müssen wir über einen Puffer mit Eingabedaten (price[]) verfügen und dessen aktuelle Länge kennen. (Vergessen Sie nicht, dass die Länge des Textes zunimmt, wenn die Anführungszeichen das Terminal ausfüllen).

Darüber hinaus müssen wir aber auch von Anfang an wissen, dass die Daten der Eingabezeile absolut korrekt sind, oder die Anfangswerte sollten aufgrund ihrer (möglichen oder garantierten) Unkorrektheit ignoriert werden. In den meisten Fällen ist die Unrichtigkeit garantiert, wenn die Eingabedaten die Ausgabe eines anderen Indikators sind, aber wie sonst? Die meisten Indikatoren müssen zur Berechnung des Wertes eines beliebigen Balkens eine bestimmte Menge an historischen Daten verwenden. Aber wo sind diese "am Anfang der Zeit" zu finden? Sie sind dort nicht vorhanden, und daher sind sie gezwungen, ihre Ausgabewerte nicht vom Startbalken der Historie aus zu generieren, sondern später (nach rechts), von dem Balken aus, der links davon liegt und für den die erforderliche Menge an historischen Daten bereits existiert.

Dank der oben beschriebenen Details kann die Frage nun beantwortet werden

woher kommt sein Wert? // es handelt sich um den Parameter begin

Die Antwort lautet: Obwohl dieser Parameter vom Terminal an die Funktion übergeben wird, muss sich der Eingabe-Indikator um seinen Inhalt kümmern! Das Terminal selbst kann nur Preiseingabezeilen überprüfen (in diesem Fall wird der Wert von begin 0 sein und das ist ein korrekter Wert). Wenn Sie also einen Indikator schreiben (außer den rein experimentellen), sollten Sie sicherstellen, dass er dem Terminal den Index des Beginns der richtigen Daten in seinem Ausgabepuffer mitteilt. Ist das klar? Andernfalls können die "Nachkommen" dieses Indikators sehr unangenehme falsche Daten essen, und in einigen Fällen können sie sogar krank werden... :) Jetzt wird die Funktion PlotIndexSetInteger() verwendet, indem der Bezeichner der PLOT_DRAW_BEGIN-Eigenschaft angegeben wird. Wichtig! Für eine 100%ige Korrektheit der generierten Indikatoreigenschaft muss ein einziger Aufruf von PlotIndexSetInteger(....PLOT_DRAW_BEGIN, ...) in OnInit()! Warum? Weil unser Indikator selbst auf den Daten eines anderen Indikators gebildet werden kann, der einen anfänglichen Einzug in der Historie hat. Das heißt, wir haben einen Nicht-Null-Wert von begin in der Eingabe-Historie, und es gibt keine Möglichkeit, ihn in OnInit() zu empfangen.

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

Und wir müssen es (vorzugsweise einmal) in OnCalculate() machen, denn in OnInit ist der Wert von begin unbekannt.

Damit haben wir natürlich auch das Recht, eine vorläufige (wenn auch nicht sehr aussagekräftige) Forderung zu stellen

  PlotIndexSetInteger(MySymbol,PLOT_DRAW_BEGIN,MyBeginPeriod);

in OnInit().

Dies ist genau das, was in dem Indikator (Custom Moving Average.mq5) geschieht, aus dem Sie Ihr Beispiel für die Untersuchung entnommen haben.

2. Kann eine Variable vom Typ double auch vom Typ int sein?

Ja, eine Variable vom Typ double kann problemlos mit einem Wert vom Typ int initialisiert werden, wenn sie durch eine Konstante definiert ist. // was genau das ist, was wir in Ihrem Beispiel tun können.

3. es scheint, dass das Terminal auch für den Wert der Variablen prev_calculated verantwortlich ist

Es gibt hier eine gewisse Subtilität. In den meisten Fällen entspricht dieser Wert dem Wert, der von der Funktion OnCalculate() im vorherigen Aufruf zurückgegeben wurde. Mit anderen Worten, Sie haben es in der Hand. Außerdem kann der Wert (vom Terminal) immer auf Null zurückgesetzt werden, wenn das Terminal dies wünscht. Dies kann z.B. bei der Kurskorrektur durch einen Broker, beim Neustart der Kommunikation nach einer Unterbrechung, bei der Neuinitialisierung eines früheren (Eingabe-)Indikators usw. geschehen.

4. es ist nicht klar, wo im Intervall von 0 bis Grenze-1 der Indikator berechnet wird

In diesem Fall können diese Werte nicht korrekt berechnet werden (wir haben nicht genug Historie für die Berechnungen), deshalb werden ihnen einfach Nullwerte zugewiesen.

// Ich würde es vorziehen, ihnen entsprechende Eingabedaten zuzuordnen, aber das ändert nichts am Kern der Sache.