Files lesen - Seite 3

 
Erster Meilenstein erreich: Die Daten können aus der Datenbank ausgelesen und weiterverarbeitet werden. Als nächsten Schritt versuche ich daraus einen Indikator zu generieren.

Hier der Code:

//+------------------------------------------------------------------+
//|                                                       SQL_EA.mq5 |
//|                                  Copyright 2021, claudius Walter |
//|                               https://www.walter.claudius@aol.de |
//+------------------------------------------------------------------+
double quoteAssetVolume;
int numberOfTrades;
double takerBuyBaseAssetVolume;
double takerBuyQuoteAssetVolume;
datetime candleOne;
datetime lastM1Bar;
datetime newM1Bar;
int db;
string filename="AAVEUSDT.db"; 


int OnInit()
  {
   return(INIT_SUCCEEDED);
  }

void OnTick()
  {
   if(CheckNewM1Bar(_Symbol))
   {  
    //--- Öffnen einer Datenbank im Verzeichnis Common des Terminals
    db=DatabaseOpen(filename, DATABASE_OPEN_READONLY | DATABASE_OPEN_COMMON);
    if(db==INVALID_HANDLE)
     {
      Print("DB: ", filename, " open failed with code Database open ", GetLastError());
     }
    
    //--- Zeit und Datum der 1. Kerze abfragen und in eine String variable convertieren
    candleOne = iTime(_Symbol,PERIOD_CURRENT,1);
    string sqlCommand = " SELECT * FROM test3 WHERE OpenTime='";
    StringAdd(sqlCommand,TimeToString(candleOne));
    StringAdd(sqlCommand,":00'");
    
    //---Handle für DatabaseRead() erzeugen
    int request=DatabasePrepare(db, sqlCommand);  
    if(request==INVALID_HANDLE)
     {
      Print("DB: ", filename, " request failed with code Database prepare ", GetLastError());
      DatabaseClose(db);    
     }

    //--- Printe die Spalte mit dem candleOne Datum
    for(int i=0; DatabaseRead(request); i++)
     {
     //--- read the values of each field from the obtained entry
      if(DatabaseColumnDouble(request, 1, quoteAssetVolume)       && 
         DatabaseColumnInteger(request, 2, numberOfTrades)        &&
         DatabaseColumnDouble(request, 3, takerBuyBaseAssetVolume)&&
         DatabaseColumnDouble(request, 4, takerBuyQuoteAssetVolume))
          {
           Print(quoteAssetVolume," ",numberOfTrades," ",takerBuyBaseAssetVolume," ",takerBuyQuoteAssetVolume);
          }
      else
          {
          Print(i, ": DatabaseRead() failed with code database read ", GetLastError());
          DatabaseFinalize(request);
          DatabaseClose(db);
          }
      }
    //--- Anfrage beenden
    DatabaseFinalize(request);

    //--- Datenbank schließen
    DatabaseClose(db);
   }
  }
  
//---Gibt true aus, sobald eine neue Kerze erscheint
bool CheckNewM1Bar(string CurrentSymbol)
  {    
   datetime lastM1Bar²[];
   
   //--- Get the opening time of the current bar
   //    If an error occurred when getting the time, print the relevant message
   if(CopyTime(CurrentSymbol,PERIOD_M1,0,1,lastM1Bar²)==-1)
      Print(__FUNCTION__,": Error copying the opening time of the bar: "+IntegerToString(GetLastError()));
   
   //--- If this is a first function call
   lastM1Bar = lastM1Bar²[0];
   if(newM1Bar==NULL)
     {
      //--- Set the time
      newM1Bar=lastM1Bar;
      Print(__FUNCTION__,": Initialization ["+CurrentSymbol+"]["
            +TimeToString(lastM1Bar,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"]");
      return(false);
     }
   //--- If the time is different
   if(newM1Bar!=lastM1Bar)
     {
      //--- Set the time and exit
      newM1Bar=lastM1Bar;
      return(true);
     }
   //--- If we have reached this line, then the bar is not new, so return false
   return(false);
  }
Beispielhaft noch die verwendete Tabelle:



Ein großes Dankeschön für eure Ideen und Ratschläge!
 
Schön wenn jemand die Arbeit aufbringt und eine Lösung erarbeitet.

Jetzt kannst du einen Service oder ein Script programmieren und mit diesem die Datenbank füttern, während der Indikator aus der DB liest.

Schon bist du bei Multiinstanz-Lösungen...


 
Dominik Egert:
Schön wenn jemand die Arbeit aufbringt und eine Lösung erarbeitet.

Jetzt kannst du einen Service oder ein Script programmieren und mit diesem die Datenbank füttern, während der Indikator aus der DB liest.

Schon bist du bei Multiinstanz-Lösungen...


Fürs Forum!

Möglicherweise werde ich das auch benötigen, mal sehen. Momentan sind diese Daten nur für Backtests ausgelegt. Wenn ich allerdings live gehe, müsste ich den Indikator oder die Datenbank mit echtzeitdaten speisen. Wenn das ohne andere Programmierebenen (bspw. Python) funktioniert, wäre das eine elegante und saubere Lösung.
 

Habe versucht, die Datenbankabfrage in einen Indikator umzusetzen. Leider zeigt mir das Journal folgenden Fehler an:



der Error steht dafür, dass die Datei der  Datenbank blockiert ist. Was auch immer genau damit gemeint ist.

Laut Debugger wird mir der Buffer mit werten befüllt. Nur zeigt das Indikatorfenster nichts an.



Das hier ist der Indikator

#property copyright "Copyright 2021, Claudius Walter & Timo Amtsberg"
#property link      "walter.claudius@aol.de & a.timo@web.de"
#property version   "1.00"
#property indicator_separate_window

//---Indikator Einstellungen
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_label1  "Number of trades"

double    tradesBuffer[];
double quoteAssetVolume;
int numberOfTrades;
double takerBuyBaseAssetVolume;
double takerBuyQuoteAssetVolume;
datetime candleOne;
datetime lastM1Bar;
datetime newM1Bar;
int db;
string filename="AAVEUSDT.db"; 

int OnInit()
  {
   //--- indicator buffers mapping
   SetIndexBuffer(0,tradesBuffer,INDICATOR_DATA);
   ArraySetAsSeries(tradesBuffer,true);

   //--- sets first bar from what index will be drawn
   
   return(INIT_SUCCEEDED);
  }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

int limit = rates_total - prev_calculated;
   if(limit == 0) limit++;
    
    
   for(int i = 0; i < limit; i++)
      {   
       //--- Öffnen einer Datenbank im Verzeichnis Common des Terminals
       db=DatabaseOpen(filename, DATABASE_OPEN_READONLY | DATABASE_OPEN_COMMON);
       if(db==INVALID_HANDLE)
        {
         Print("DB: ", filename, " open failed with code Database open ", GetLastError());
        }
       
       //--- Zeit und Datum der 1. Kerze abfragen und in eine String variable convertieren
       candleOne = time[i];
      
       string sqlCommand = " SELECT * FROM test3 WHERE OpenTime='";
       StringAdd(sqlCommand,TimeToString(candleOne));
       StringAdd(sqlCommand,":00'");
       
       //---Handle für DatabaseRead() erzeugen
       int request=DatabasePrepare(db, sqlCommand);  
       if(request==INVALID_HANDLE)
        {
         Print("DB: ", filename, " request failed with code Database prepare ", GetLastError());
         DatabaseClose(db);    
        }
   
       //--- Printe die Spalte mit dem candleOne Datum
       for(int j=0; DatabaseRead(request); j++)
        {
        //--- read the values of each field from the obtained entry
         if(DatabaseColumnDouble(request, 1, quoteAssetVolume)       && 
            DatabaseColumnInteger(request, 2, numberOfTrades)        &&
            DatabaseColumnDouble(request, 3, takerBuyBaseAssetVolume)&&
            DatabaseColumnDouble(request, 4, takerBuyQuoteAssetVolume))
             {
              tradesBuffer[i] = numberOfTrades;
             }
         else
             {
             Print(i, ": DatabaseRead() failed with code database read ", GetLastError());
             DatabaseFinalize(request);
             DatabaseClose(db);
             }
         }
       //--- Anfrage beenden
       DatabaseFinalize(request);
   
       //--- Datenbank schließen
       DatabaseClose(db);
      }
   return(rates_total);
  }

Was sagt ihr dazu? Ich habe noch nicht so oft mit Indikatoren gearbeitet . Ich vermute allerdings, dass es mit der for_Schleife zusammenhängt

 
Claudius Marius Walter:

Habe versucht, die Datenbankabfrage in einen Indikator umzusetzen. Leider zeigt mir das Journal folgenden Fehler an:



der Error steht dafür, dass die Datei der  Datenbank blockiert ist. Was auch immer genau damit gemeint ist.

Laut Debugger wird mir der Buffer mit werten befüllt. Nur zeigt das Indikatorfenster nichts an.



Das hier ist der Indikator

Was sagt ihr dazu? Ich habe noch nicht so oft mit Indikatoren gearbeitet . Ich vermute allerdings, dass es mit der for_Schleife zusammenhängt

IndikatorBarney


Nein Spaß, aber das habe ich mich wirklich gefragt... Du möchtest Zahlen aus der Tabelle holen und in einem "Oszillatorfenster" anzeigen lassen.

Du müsstest dazu mit der Schleife den tradesBuffer[] befüllen. Jedoch nicht immer mit dem selben Wert numberOfTrades. Auch numberOfTrades müsstest Du mit dem Index aus der Tabelle holen, indem Du "Select" wie einen Index verwendest. Dadurch gibst Du die Zeile an. Nur wo das geht ist mir nicht klar. 

Das ginge aber erstmal nur für M1 TF. Für M15 müsstest Du immer 15 beieinanderliegende Werte addieren.

Warum hast Du den Index i durch j ersetzt? Der Index im Kopf der Schleife muss der selbe sein wie im Körper.

Dann zählt die Schleife durch:

tradesBuffer[0]= numberOfTrades[0];
tradesBuffer[1]= numberOfTrades[1];
tradesBuffer[2]= numberOfTrades[2];
tradesBuffer[3]= numberOfTrades[3];
tradesBuffer[4]= numberOfTrades[4]; und so weiter. Das macht Alles die Schleife für Dich, wenn Du sie richtig einrichtest. Du musst das halt irgendwie mit dem Databasekram hinbekommen, dass Du mit dem Index die Werte in der Tabelle selektierst. Select wäre die Zeile und die Spalten(Collumn) haben ja Namen. Aber wie das genau geht, weiß ich nicht. Noch nicht. Das Thema SQL ist neu für mich, aber auch interessant.

Du bist da an was dran, aber Du müsstest erstmal noch ein Bisschen sicherer in Schleifen, Arrays und Indikatoren werden. Hast Du schon mal einen MACrossover EA gebaut? Oder wenn Du einen EA machen würdest, der als Kaufbedingung prüft ob der Preis für mindestens dreißig Bars über einem 200er Durchschnitt bleibt.

https://www.mql5.com/de/articles/567  Der ist gut fürs Verständnis von Arrays.

https://www.mql5.com/de/articles/4828  Der ist vielleicht ein Bisschen schwierig aber zeigt gut was man mit Indikatoren Alles machen kann. Der Autor nimmt hier auch einen Count und lässt ihn als Linie im Oszillatorfenster anzeigen, Abschnitt "Buffer für Signalzähler".

Grundlagen der Programmierung in MQL5: Arrays
Grundlagen der Programmierung in MQL5: Arrays
  • www.mql5.com
Arrays sind zusammen mit Variablen und Funktionen ein wesentlicher Bestandteil so gut wie jeder Programmiersprache. Dieser Beitrag dürfte vor allem für Neueinsteiger in der Programmierung mit MQL5 interessant sein, bietet erfahrenen Programmierern aber gleichzeitig eine gute Gelegenheit, ihr Wissen zusammenzufassen und zu systematisieren.
 
Für die sqlite kannst du auch eine Desktop App benutzen. Damit kannst du sie dir genau anschauen.

Such Mal nach SQLite Browser.

Die Datenbank solltest du in OnInit öffnen und in OnDeinit schließen.

Wenn du dich mit SQL weiter auseinandersetzt, dann wirst du bald sehen, dass es hier sehr versatile Abfragemöglichkeiten gibt um die gewünschten Daten zu erhalten.

Auch kumulieren ist damit möglich.

Allerdings bist du auf den Satz der SQLite beschränkt, dieser ist nicht der gesamte SQL Umfang, leider.

Jedoch kannst du Recht einfach, später eine Anbindung an einen richtigen SQL Server umsetzen.

Ich werde dir eine MySQL Anbindung für MQL verlinken, wenn ich diese in der CodeBase veröffentlicht habe.

Ansonsten, gute Fortschritte.



 
pennyhunter:


Nein Spaß, aber das habe ich mich wirklich gefragt... Du möchtest Zahlen aus der Tabelle holen und in einem "Oszillatorfenster" anzeigen lassen.

Du müsstest dazu mit der Schleife den tradesBuffer[] befüllen. Jedoch nicht immer mit dem selben Wert numberOfTrades. Auch numberOfTrades müsstest Du mit dem Index aus der Tabelle holen, indem Du "Select" wie einen Index verwendest. Dadurch gibst Du die Zeile an. Nur wo das geht ist mir nicht klar. 

Das ginge aber erstmal nur für M1 TF. Für M15 müsstest Du immer 15 beieinanderliegende Werte addieren.

Warum hast Du den Index i durch j ersetzt? Der Index im Kopf der Schleife muss der selbe sein wie im Körper.

Dann zählt die Schleife durch:

tradesBuffer[0]= numberOfTrades[0];
tradesBuffer[1]= numberOfTrades[1];
tradesBuffer[2]= numberOfTrades[2];
tradesBuffer[3]= numberOfTrades[3];
tradesBuffer[4]= numberOfTrades[4]; und so weiter. Das macht Alles die Schleife für Dich, wenn Du sie richtig einrichtest. Du musst das halt irgendwie mit dem Databasekram hinbekommen, dass Du mit dem Index die Werte in der Tabelle selektierst. Select wäre die Zeile und die Spalten(Collumn) haben ja Namen. Aber wie das genau geht, weiß ich nicht. Noch nicht. Das Thema SQL ist neu für mich, aber auch interessant.

Du bist da an was dran, aber Du müsstest erstmal noch ein Bisschen sicherer in Schleifen, Arrays und Indikatoren werden. Hast Du schon mal einen MACrossover EA gebaut? Oder wenn Du einen EA machen würdest, der als Kaufbedingung prüft ob der Preis für mindestens dreißig Bars über einem 200er Durchschnitt bleibt.

https://www.mql5.com/de/articles/567  Der ist gut fürs Verständnis von Arrays.

https://www.mql5.com/de/articles/4828  Der ist vielleicht ein Bisschen schwierig aber zeigt gut was man mit Indikatoren Alles machen kann. Der Autor nimmt hier auch einen Count und lässt ihn als Linie im Oszillatorfenster anzeigen, Abschnitt "Buffer für Signalzähler".

Danke für deine Tipps. Werde ich mir direkt ansehen. An sich würd ich aber sagen, läuft:

Tatsächlich bin ich mit dem Indikator weiter gekommen. Allerdings frisst das Auslesen der Datenbank enorm viel Zeit.
In einem anderen Beitrag habe ich dies nochmal etwas genauer erörtert: https://www.mql5.com/de/forum/369221

  for(int j=0; DatabaseRead(request); j++)
        {
        //--- read the values of each field from the obtained entry
         if(DatabaseColumnDouble(request, 1, quoteAssetVolume)       && 
            DatabaseColumnInteger(request, 2, numberOfTrades)        &&
            DatabaseColumnDouble(request, 3, takerBuyBaseAssetVolume)&&
            DatabaseColumnDouble(request, 4, takerBuyQuoteAssetVolume))
             {
              tradesBuffer[i] = numberOfTrades;
             }

das j hängt in diesem Fall nicht mit dem i zusammen. Das j wird nur hochgezählt, solange die Datenbank den eingetragenen Wert noch nicht gefunden hat. Der Indikator zeigt mir nur im M1 (wie du auch schon erwähnt hast) die Werte korrekt an, was aber ersteinmal nicht das Problem ist.
Um die Performance des programms zu erhöhen stehen mir zwei Optionen zur Verfügung:

1. Ich lese nur die letzten 20-30 Balken aus, sodass nicht der ganze chart bis 1840 v.Ch. geladen werden muss.

2. Ich speichere bereits in der OnInit() eine gesamt Spalte aus der Datenbank in ein Array ab, sodass es schneller abgerufen werden kann.
Hierzu dachte ich, dass die Funktion DatabaseColumnBlob() eventuell dienlich sein könnte. Bin mir aber bezüglich der Doku garnicht so recht sicher..

bool  DatabaseColumnBlob( 
   int    request,     // Handle der Anfrage, das durch DatabasePrepare erhalten wurde 
   int    column,      // Feldindex in der Anfrage  
   void&  data[]       // die Referenz der Variablen, der der Wert zugewiesen wird 
   );
DatabaseColumnBlob

request

[in]  Handle der Anfrage, das von DatabasePrepare() erhalten wurde.

column

[in]  Feldindex der Anfrage. Die Feldnummerierung beginnt bei Null und darf DatenbankColumnsCount() - 1. nicht überschreiten.

data[]

[out]  Referenz des Arrays, dem der Feldwert zugewiesen wird.


Vielen Dank Dominik! Denkst du mit der DatabaseColumnBlob () Funktion kann ich mein Vorhaben durchführen?

spezifische Frage zur OnCalculate()
spezifische Frage zur OnCalculate()
  • 2021.05.13
  • www.mql5.com
Hallo miteinander, ich programmiere gerade einen Indikator und bin mir bezüglich der Berechnung der OnCalculate() unschlüssig...
 
Claudius Marius Walter:



das j hängt in diesem Fall nicht mit dem i zusammen. Das j wird nur hochgezählt, solange die Datenbank den eingetragenen Wert noch nicht gefunden hat. Der Indikator zeigt mir nur im M1 (wie du auch schon erwähnt hast) die Werte korrekt an, was aber ersteinmal nicht das Problem ist.
Um die Performance des programms zu erhöhen stehen mir zwei Optionen zur Verfügung:

1. Ich lese nur die letzten 20-30 Balken aus, sodass nicht der ganze chart bis 1840 v.Ch. geladen werden muss.

2. Ich speichere bereits in der OnInit() eine gesamt Spalte aus der Datenbank in ein Array ab, sodass es schneller abgerufen werden kann.
Hierzu dachte ich, dass die Funktion DatabaseColumnBlob() eventuell dienlich sein könnte. Bin mir aber bezüglich der Doku garnicht so recht sicher..

DatabaseColumnBlob

request

[in]  Handle der Anfrage, das von DatabasePrepare() erhalten wurde.

column

[in]  Feldindex der Anfrage. Die Feldnummerierung beginnt bei Null und darf DatenbankColumnsCount() - 1. nicht überschreiten.

data[]

[out]  Referenz des Arrays, dem der Feldwert zugewiesen wird.

Also ich habe mir mal den Artikel über SQLite angesehen und er ist mir nicht so reingelaufen...

Jetzt habe ich auch das i gesehen weiter oben.
Also durch das j wird bewerkstelligt, dass die Anfrage läuft bis der Wert gelesen wurde DatabaseRead(request).

Jetzt sehe ich auch, dass Du durch den Index die Balkenzeit aussuchst, welche in sqlcommand einfließt, wodurch DatabasePrepare verändert wird...

Oh das wird interessant, vergiss einfach das was ich über Schleifen, Arrays und Indikatoren gesagt habe und mach einfach weiter was Du machst :D

Könntest Du nicht db=DatabaseOpen() vor die Schleife stellen, denn sie wird ja durch den Index nicht verändert und müsste daher auch nicht mehrmals neu berechnet werden.
 

Huch, da gabs wohl einen Bug beim absenden..

Jedenfalls hast du voll und ganz recht. Die DatabasOpen() muss(!) in die OnInit(), sowie die DatabaseClose() in die OnDeInit() muss. Das erhöht die performance eindeutig, trotzdem scheint mir mein Indikator noch etwas zu träge.

Hier ist nun die Version, indem dies berücksichtig wurde. Außerdem ist nun auch die Unterscheidung der einzelnen Timeframes enthalten.

Selbst der Metatrader bittet darum, den indikator umzuschreiben..

Wie wäre es, wenn ich bereits in der OnInit() alle werte in eine Struct packe?

//---Indikator Einstellungen
#property indicator_buffers 2
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_label1  "Number of trades"

double    tradesBuffer[];
double    quoteAssetVolume;
int       numberOfTrades;
int       sumNumberOfTrades;
double    takerBuyBaseAssetVolume;
double    takerBuyQuoteAssetVolume;
datetime  lastM1Bar;
datetime  newM1Bar;
datetime  candleTwo;
int       db;
string    filename="AAVEUSDT.db"; 


int OnInit()
  {
   //--- Open a database in Terminal/Common
   db=DatabaseOpen(filename, DATABASE_OPEN_READONLY | DATABASE_OPEN_COMMON);
    if(db==INVALID_HANDLE)
     {
      Print("DB: ", filename, " open failed with code Database open ", GetLastError());
     }
   //--- indicator buffers mapping
   SetIndexBuffer(0,tradesBuffer,INDICATOR_DATA);

   return(INIT_SUCCEEDED);
  }
  
void OnDeinit(const int reason)
  {
   //--- close database
   DatabaseClose(db);
  
  }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {



//int limit =rates_total ;
   
   int i = rates_total - 30; // Calculate only the last 30 bars
   
   for(i ; i < rates_total; i++)
      {   
       datetime BarTime = time[i];
       if(Period() == PERIOD_M1)calcIndicator(1,i,BarTime);
       if(Period() == PERIOD_M5)calcIndicator(5,i,BarTime);
       if(Period() == PERIOD_M15)calcIndicator(15,i,BarTime);
       if(Period() == PERIOD_H1)calcIndicator(60,i,BarTime);
       if(Period() == PERIOD_H4)calcIndicator(240,i,BarTime);
       if(Period() == PERIOD_D1)calcIndicator(1440,i,BarTime);
      }
   return(rates_total);
  }



void calcIndicator(int timeframeMulitplier,int i, datetime BarTime)
   {
    for(int j = 0; j <= timeframeMulitplier-1; j++)
      { 
       //--- Ask for date and time for the 1.candle and convert it into a string value
       datetime  candleOne[];
       ArrayResize(candleOne,j+1);
       candleOne[j] = (BarTime + (60 * j));
       
       // Print("Timestamp: ",time[i]);
       
       //--- create an SQL command
       string sqlCommand = " SELECT * FROM test3 WHERE OpenTime='"; 
       StringAdd(sqlCommand,TimeToString(candleOne[j]));
       StringAdd(sqlCommand,":00'");
       
       //---create handle for DatabaseRead()
       int request=DatabasePrepare(db, sqlCommand);  
       if(request==INVALID_HANDLE)
        {
         Print("DB: ", filename, " request failed with code Database prepare ", GetLastError());
         DatabaseClose(db);    
        }

       //--- read the values of each field from the obtained entry
       for(int k=0; DatabaseRead(request); k++)
        {
         if(//DatabaseColumnDouble(request, 1, quoteAssetVolume)       && 
            DatabaseColumnInteger(request, 2, numberOfTrades)    
            //DatabaseColumnDouble(request, 3, takerBuyBaseAssetVolume)&&
            //DatabaseColumnDouble(request, 4, takerBuyQuoteAssetVolume)
            )
             {
              sumNumberOfTrades += numberOfTrades;
              tradesBuffer[i] = sumNumberOfTrades;
              //Print("numberOfTrades: ",numberOfTrades);
             }
         else
             {
             Print(j, ": DatabaseRead() failed with code database read ", GetLastError());
             DatabaseFinalize(request);
             DatabaseClose(db);
             }
         }
      
       //--- quit the request
       DatabaseFinalize(request);
     }
     sumNumberOfTrades = 0;
   }
 
Claudius Marius Walter:

Huch, da gabs wohl einen Bug beim absenden..

Jedenfalls hast du voll und ganz recht. Die DatabasOpen() muss(!) in die OnInit(), sowie die DatabaseClose() in die OnDeInit() muss. Das erhöht die performance eindeutig, trotzdem scheint mir mein Indikator noch etwas zu träge.

Hier ist nun die Version, indem dies berücksichtig wurde. Außerdem ist nun auch die Unterscheidung der einzelnen Timeframes enthalten.

Selbst der Metatrader bittet darum, den indikator umzuschreiben..

Wie wäre es, wenn ich bereits in der OnInit() alle werte in eine Struct packe?

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

bool newBar()
  {
   static datetime TimeBar=0;              
   bool flag=false;
   if(TimeBar!=iTime(Symbol(),Period(),0))
     {
      TimeBar=iTime(Symbol(),PERIOD_CURRENT,0);
      flag=true;
      Print(">>>newBar");
     }

// return true if you are in new bar.
   return (flag);
  }

 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.

Grund der Beschwerde: