Files lesen - Seite 4

 
Ok, erstmal fang bitte an den Dritten Parameter von ArrayResize zu nutzen.

Besonders in schleifen mit inkrementellem Resize.

Die for() kannst du mit < XYX statt mit <= XYZ -1 ersetzen.

Dann zu den Datentypen in der DB.

Blob ist der bzw ein Datentyp der Column.

Eventuell kannst du die time column in einen numerischen Wert ändern. Das bringt viele Vorteile.

Außerdem kannst du einen Index auf der column erstellen. Das beschleunigt deine WHERE Bedingung ungemein, besonders bei großen Tabellen.


 
Check doch bitte ob du die SQL so machen kannst:

SELECT SUM(number of trades) FROM tbl WHERE ....

Für einen Durchschnitt kannst du zB auch:

SELECT SUM(number of trades)/COUNT(number of trades) AS avg FROM tbl WHERE ....

nutzen.

 
pennyhunter:

Würde sich eine newBar Funktion hier lohnen oder brauchst Du die Informationen neu bei jedem Tick?

 Du nimmst newBar==true als Bedingung für das Starten der SQL-Rechnerei, somit wird diese auf den ersten Tick innerhalb eines Balkens beschränkt.

ein guter Hinweis! Allerdings ist die Datenbank mit M1 Daten hinterlegt, welche ich auch benötige. Sollte der Indikator einmal in einen EA implementiert werden, müsste ich aufjedenfall dafür sorgen, nicht jeden Tick abzufragen. Danke!

Dominik Egert:
Ok, erstmal fang bitte an den Dritten Parameter von ArrayResize zu nutzen.

Besonders in schleifen mit inkrementellem Resize.

Die for() kannst du mit < XYX statt mit <= XYZ -1 ersetzen.

Dann zu den Datentypen in der DB.

Blob ist der bzw ein Datentyp der Column.

Eventuell kannst du die time column in einen numerischen Wert ändern. Das bringt viele Vorteile.

Außerdem kannst du einen Index auf der column erstellen. Das beschleunigt deine WHERE Bedingung ungemein, besonders bei großen Tabellen.


Danke Dominik, deine Datenbankkenntnisse helfen mir sehr!

Arrayresize:
Kannst du mir erklären, wie ich den 3. Parameter in meinem Kopf zuordnen soll? Die Doku spricht zwar von einer reduzierung der Zahl von physikalischen speicherhäufigkeiten, aber trotzdem weiß ich nicht, welchen Wert dieser denn benötigt.

Datenbanken:
Es scheint, als wäre es mir gelungen. Ich habe mich dafür entschieden, den columns "NumberOfTrades" und "Datetime" einen Index zu vergeben. Mein Indikator ist nun genauso schnell berechnet wie jeder andere auch. Herzlichen Dank, das hat mir sehr weiter geholfen.
Trotzdem erscheint der "Allgemeine Fehler" error: 5601, wenn die DatabaseExecute() ausgeführt wird.
Ich habe sie wie folgt in der Oninit() hinterlegt und finde den Fehler leider nicht.

int OnInit()
  {
   //--- Open a database in Terminal/Common
   db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_COMMON);
    if(db==INVALID_HANDLE)
     {
      Print("DB: ", filename, " open failed with code Database open ", GetLastError());
     }
        
    bool dbExecute = DatabaseExecute(db,"CREATE INDEX idx ON test3 (OpenTime, NumberOfTrades)");
     if(!dbExecute)
     {
      Print("DB: "," Database execute failed with code ", GetLastError());
     }

   //--- indicator buffers mapping
   SetIndexBuffer(0,tradesBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,stdDeviation,INDICATOR_DATA);

   return(INIT_SUCCEEDED);
  }


Deine anderen Tipps habe ich bisher nicht weiter nachverfolgt, was angesichts der jetzigen performance nicht mehr nötig sein wird.
 
Ich vermute der Index existiert bereits. Diesen musst du nur ein Mal anlegen.

Lies Mal bitte "CREATE INDEX IF NOT EXIST"
Benenne die Indizes besser. Hier zB idx_opentime_numoftrades.


Die Abfrage mit der SUM() wäre die richtige Verwendung der DB. Sie dient nicht nur als Datenspeicher, sondern auch um Daten aufzuwerten.

Der dritte Parameter ist für eine vorbereitende Speicherallokation gedacht. Wenn du bereits im Vorfeld weißt, dass sich das Array erweitert, so kannst du hier deine "prediction" abgeben.

In deinem Fall ist es die Menge an Läufen durch die Loop.

Dadurch erlaubst du eine größere Speicherzuteilung zu deinem Array, ohne das Array bereits auf diese Größe zu erweitern. Die MemoryUnit muss dann bei einer Erweiterung das Array nicht im Speicher an eine Stelle kopieren an der genug Platz für die Erweiterung ist.

Wird den Indikator sicher nochmal schneller machen.

BTW, nutze eine SQLite Software um deine SQL Queries zu entwickeln und zu testen.

Allgemein gilt:

Wenn du ein Projekt mit Datenbanken hast, nutze die Möglichkeiten um deine von der Applikation genutzten Daten vorzubereiten.

Wenn du dann eine andere Software schreibst, zB einen EA, dann kannst du die SQLs einfach kopieren, ohne den aufwertenden Code auch mitkopieren zu müssen.

Dadurch kannst du dann die Daten von der Programmlogik getrennt handhaben.

Später könntest du mit "Stored Procedures" diese sogar im Schema der DB hinterlegen.

Damit ist deine Applikation dann nicht mehr mit der Aufwertung der Daten beschäftigt, sondern mit der Verarbeitung.

Das ist jedenfalls die übliche Herangehensweise.

Du kannst sogar SQLs schreiben, die dir aus den M1 Daten die Daten für höhere TFs bauen und direkt liefern.

Eine Stored Procedure die als Parameter den TF nimmt und dir dann die bereits aufbereiteten Daten liefert.


 
Claudius Marius Walter:

Arrayresize:
Kannst du mir erklären, wie ich den 3. Parameter in meinem Kopf zuordnen soll? Die Doku spricht zwar von einer reduzierung der Zahl von physikalischen speicherhäufigkeiten, aber trotzdem weiß ich nicht, welchen Wert dieser denn benötigt.
Wenn man in ein Array ein weiteres Element eintragen will, muss im Ram der Speicher dafür jedes mal von Windows extra reserviert werden. Mit dieser Option wird im 'Betriebssystem' von MQL5 nur ein Wert oder Pointer verändert, bis das vorab-reservierte Maximum erreicht werden würde - es ist also schneller.
 
Dominik Egert:
Ich vermute der Index existiert bereits. Diesen musst du nur ein Mal anlegen.

Die Abfrage mit der SUM() wäre die richtige Verwendung der DB. Sie dient nicht nur als Datenspeicher, sondern auch um Daten aufzuwerten.

Der dritte Parameter ist für eine vorbereitende Speicherallokation gedacht. Wenn du bereits im Vorfeld weißt, dass sich das Array erweitert, so kannst du hier deine "prediction" abgeben.

In deinem Fall ist es die Menge an Läufen durch die Loop.

Dadurch erlaubst du eine größere Speicherzuteilung zu deinem Array, ohne das Array bereits auf diese Größe zu erweitern. Die MemoryUnit muss dann bei einer Erweiterung das Array nicht im Speicher an eine Stelle kopieren an der genug Platz für die Erweiterung ist.

Wird den Indikator sicher nochmal schneller machen.

BTW, nutze eine SQLite Software um deine SQL Queries zu entwickeln und zu testen.

Allgemein gilt:

Wenn du ein Projekt mit Datenbanken hast, nutze die Möglichkeiten um deine von der Applikation genutzten Daten vorzubereiten.

Wenn du dann eine andere Software schreibst, zB einen EA, dann kannst du die SQLs einfach kopieren, ohne den aufwertenden Code auch mitkopieren zu müssen.

Dadurch kannst du dann die Daten von der Programmlogik getrennt handhaben.

Später könntest du mit "Stored Procedures" diese sogar im Schema der DB hinterlegen.

Damit ist deine Applikation dann nicht mehr mit der Aufwertung der Daten beschäftigt, sondern mit der Verarbeitung.

Das ist jedenfalls die übliche Herangehensweise.

Du kannst sogar SQLs schreiben, die dir aus den M1 Daten die Daten für höhere TFs bauen und direkt liefern.

Eine Stored Procedure die als Parameter den TF nimmt und dir dann die bereits aufbereiteten Daten liefert.


Habs tatsächlich selbst rausgefunden, Danke trotzdem! Zum testen meiner DB-Befehle benutze ich die interne DB Funktion des metatraders, aber wenn sich das Thema so langsam ausweiten sollte, werde ich wohl deine Ratschläge weiter vertiefen. Gehe das nun nach und nach an.

Hier erstmal die korrigierte Indexbelegung:

int OnInit()
  {
   //--- Open a database in Terminal/Common
   db=DatabaseOpen(filename, DATABASE_OPEN_READWRITE | DATABASE_OPEN_COMMON);// Open database
    if(db==INVALID_HANDLE)
     {
      Print("DB: ", filename, " open failed with code Database open ", GetLastError());
     }
    
    bool dbDropIndex = DatabaseExecute(db,"DROP INDEX idx;"); //delete previous index
     if(dbDropIndex == false)
     {
      Print("DB: "," Database drop Index failed with code ", GetLastError());
     }
   
    bool dbCreateIndex = DatabaseExecute(db,"CREATE INDEX idx ON test3 (OpenTime, NumberOfTrades)"); // create new index
     if(dbCreateIndex == false)
     {
      Print("DB: "," Database create index failed with code ", GetLastError());
     }

   //--- indicator buffers mapping
   SetIndexBuffer(0,tradesBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,stdDeviation,INDICATOR_DATA);

   return(INIT_SUCCEEDED);
  }

 
Check Mal bitte "CREATE INDEX IF NOT EXIST".

Jedes Mal den Index bauen ist nicht effizient.

Mag jetzt noch schnell sein, bei vielen Daten dann aber nicht mehr.

Ein Index ist eine Art virtuelle Spalte in der Tabelle. Diese wird generiert aus den Quellspalten, die du für den Index angibst.