News Einblenden

 

Hallo,


nachdem es ja jetzt den News Array gibt von MQL, hat hier schon jemand was Programmiert damit im Chart eine Linie gezeichnet wird?

will jetzt das Rad nicht neu erfinden


lg

amando

 

Der Umgang mit News-Events ist etwas unterschiedlich, je nachdem ob es live oder über den Strategietester oder Optimierer erfolgt. Auf große Teile der News-Historie lässt sich nämlich nur live zugreifen!!!

Außerdem ist zu beachten, dass sämtliche Uhrzeiten der Events GMT-Zeit sind. Dies ist ebenfalls ein kleines (aber lösbares) Problem, falls der Strategietester verwendet wird, da die GMT-Zeit ja nicht korrekt abrufbar ist, da TimeGMT dann identisch mit der Serverzeit zurückgegeben wird.

Falls(!) es Dir also nur um live-Events geht, ist es recht trivial. Wenn Du beides - also live und Tester - brauchst, lässt es sich lösen, indem die gesamte Historie einmal live (oder aus dem Debugging-Mode mit live-Daten) ausgelesen und in eine Datei gespeichert wird. Das ergibt dann etwa 90.000 historische Events. Das kann man im Live-Trading genauso machen, indem die Datei nur einmal initialisiert wird und dann immer jeweils nur um die neuen Events seit dem letzten Update ergänzt wird. Die CNews-Klasse der angehängten .mqh-Datei macht genau das (Achtung: Ganztags-Events bzw. events ohne konkrete Uhrzeitangabe wie z.B. Feiertage werden ignoriert; wer das anders möchte muss den Code halt etwas anpassen).

Wenn die Klasse aufgerufen wird mit z.B. CNews news, dann führt der Befehl news.SaveHistory() dazu, dass eine News-Datei angelegt wird mit allen historischen Daten (also ohne bekannte zukünftige Events). Falls die Datei bereits existiert wird nur seit dem letzten Update ergänzt und die Daten entsprechend angehängt. Es wird also nicht jedes Mal die komplette Datei neu geschrieben. Da die anstehenden Events i.d.R. schon Tage im Voraus bekannt sind, reicht ein Update ca. 1x pro Tag, z.B. um Mitternacht.

Die Funktion news.LoadHistory() lädt alle historischen UND (bek.) ZUKÜNFTIGEN Events in das public Array news.event[]. Rückgabewert der Funktion (vom Typ int) ist die Gesamtzahl aller Events. Bei dem Array "event" handelt es sich um eine Struktur(!), über die sämtliche Details zu dem jeweiligen Event abrufbar sind. Um ein bestimmtes event nach der Event-Zeit (news.event[].time) zu suchen, wird der Index des Arrays als eine Art Pointer verwendet. Auch hier ist der Bezug auf GMT-Zeit wichtig! Es empfiehlt sich daher, auch im Hauptprogramm und nicht nur in der Klasse CNews die include-Date Time.mqh zu verwenden. Die korrekte GMT-Zeit (=auch im Strategietester) erhält man nach Aufruf der Klasse mittels CTime time dann mit dem hierzulande üblichen Winterzeit/Sommerzeit-Offset mittels time.GMT(2,3).

Mit den Events kann man dann natürlich alles Mögliche machen... auch eine Linie in den Chart zeichnen ;-)

Dateien:
News.mqh  11 kb
Time.mqh  3 kb
 
Chris70:

Der Umgang mit News-Events ist etwas unterschiedlich, je nachdem ob es live oder über den Strategietester oder Optimierer erfolgt. Auf große Teile der News-Historie lässt sich nämlich nur live zugreifen!!!

Außerdem ist zu beachten, dass sämtliche Uhrzeiten der Events GMT-Zeit sind. Dies ist ebenfalls ein kleines (aber lösbares) Problem, falls der Strategietester verwendet wird, da die GMT-Zeit ja nicht korrekt abrufbar ist, da TimeGMT dann identisch mit der Serverzeit zurückgegeben wird.

Falls(!) es Dir also nur um live-Events geht, ist es recht trivial. Wenn Du beides - also live und Tester - brauchst, lässt es sich lösen, indem die gesamte Historie einmal live (oder aus dem Debugging-Mode mit live-Daten) ausgelesen und in eine Datei gespeichert wird. Das ergibt dann etwa 90.000 historische Events. Das kann man im Live-Trading genauso machen, indem die Datei nur einmal initialisiert wird und dann immer jeweils nur um die neuen Events seit dem letzten Update ergänzt wird. Die CNews-Klasse der angehängten .mqh-Datei macht genau das (Achtung: Ganztags-Events bzw. events ohne konkrete Uhrzeitangabe wie z.B. Feiertage werden ignoriert; wer das anders möchte muss den Code halt etwas anpassen).

Wenn die Klasse aufgerufen wird mit z.B. CNews news, dann führt der Befehl news.SaveHistory() dazu, dass eine News-Datei angelegt wird mit allen historischen Daten (also ohne bekannte zukünftige Events). Falls die Datei bereits existiert wird nur seit dem letzten Update ergänzt und die Daten entsprechend angehängt. Es wird also nicht jedes Mal die komplette Datei neu geschrieben. Da die anstehenden Events i.d.R. schon Tage im Voraus bekannt sind, reicht ein Update ca. 1x pro Tag, z.B. um Mitternacht.

Die Funktion news.LoadHistory() lädt alle historischen UND (bek.) ZUKÜNFTIGEN Events in das public Array news.event[]. Rückgabewert der Funktion (vom Typ int) ist die Gesamtzahl aller Events. Bei dem Array "event" handelt es sich um eine Struktur(!), über die sämtliche Details zu dem jeweiligen Event abrufbar sind. Um ein bestimmtes event nach der Event-Zeit (news.event[].time) zu suchen, wird der Index des Arrays als eine Art Pointer verwendet. Auch hier ist der Bezug auf GMT-Zeit wichtig! Es empfiehlt sich daher, auch im Hauptprogramm und nicht nur in der Klasse CNews die include-Date Time.mqh zu verwenden. Die korrekte GMT-Zeit (=auch im Strategietester) erhält man nach Aufruf der Klasse mittels CTime time dann mit dem hierzulande üblichen Winterzeit/Sommerzeit-Offset mittels time.GMT(2,3).

Mit den Events kann man dann natürlich alles Mögliche machen... auch eine Linie in den Chart zeichnen ;-)

danke Chris,


das geht ja wirklich easy mit deinen Files ;-) 

bin noch am rumspielen, aber das sieht wirklich gut aus, genau das was ich suche 


danke

 

Dann sag ich mal 'freut mich' und Danke für die Rückmeldung.

Noch ein Detail: Dir ist evtl. aufgefallen, dass der Name (string) der Eventbezeichnung nicht Element der Eventstruktur ist (lässt sich aber leicht ändern, falls Du es so haben willst). Du erhälst den Namen aber mit news.eventname[]. Der zu verwendende Array-Index ist identisch mit dem Index der news.event[] Struktur, auf die der String sich bezieht.

 

ich könnte da noch zwei Sachen beisteuern, die man im Kontext mit News ständig braucht:

1.: eine Liste, die der Country-Id das Land in verständlicher Sprache zuordnet

enum ENUM_COUNTRY_ID
  {
   world=0,
   EU=999,
   USA=840,
   Canada=124,
   Australia=36,
   NewZealand=554,
   Japan=392,
   China=156,
   UK=826,
   Switzerland=756,
   Germany=276,
   France=250,
   Italy=380,
   Spain=724,
   Brazil=76,
   SouthKorea=410
  };

2. eine Funktion, die für eine Country-Id die relevante Währung ausgibt:

//+------------------------------------------------------------------+
//| country id to currency                                           |
//+------------------------------------------------------------------+
string CountryIdToCurrency(ENUM_COUNTRY_ID c)
  {
   switch(c)
     {
      case 999:      return "EUR";
      case 840:      return "USD";
      case 36:       return "AUD";
      case 554:      return "NZD";
      case 156:      return "CYN";
      case 826:      return "GBP";
      case 756:      return "CHF";
      case 276:      return "EUR";
      case 250:      return "EUR";
      case 380:      return "EUR";
      case 724:      return "EUR";
      case 76:       return "BRL";
      case 410:      return "KRW";
      default:       return "";
     }
  }
 
Chris70:

Dann sag ich mal 'freut mich' und Danke für die Rückmeldung.

Noch ein Detail: Dir ist evtl. aufgefallen, dass der Name (string) der Eventbezeichnung nicht Element der Eventstruktur ist (lässt sich aber leicht ändern, falls Du es so haben willst). Du erhälst den Namen aber mit news.eventname[]. Der zu verwendende Array-Index ist identisch mit dem Index der news.event[] Struktur, auf die der String sich bezieht.

stimmt ist mir aufgefallen, das hab ich aber sofort gefunden.

Was mir eher aufgefallen ist, das die Eventbezeichnung nur bei vergangenen Events vorhanden ist. Bevor ich deinen Post hier gelesen hab, hab ich überlegt ob das eventuell sein könnte, das ja ein String nicht in einem Numerischen Struct stehen kann, aber die Idee gleich wieder verworfen.


ich hab mir das mal so angesehen

hab das mal zum testen in die OnInit gestellt

ews.SaveHistory(true);                // Speichern der News in File von @Chris70 aus MQL5Forum, siehe 50_News und 51_Time.mqh

   news.LoadHistory(true);                                                                                           // Lesen der News
   
   int totalnews=ArraySize(news.event);
   for(int i=0;i<totalnews;i++)
     {
      
      if(news.event[i].country_id != 0 && news.event[i].time > TimeCurrent() && news.event[i].time < TimeCurrent() + 96*60*60 )
      {
      Print(news.event[i].country_id," ", 
      news.eventname[i]," ", 
      news.event[i].sector," ", 
      news.event[i].time," ",
      news.event[i].timemode," ", 
      news.event[i].event_type
      );}
     }

also, ich hab hier auf die zukünftigen Events gefiltert, nachdem die vergangenen viele sind und da alles funkt

dann bekomme ich das raus

warum hier der Eventname Numerisch ist, hab ich noch nicht verstanden

 

die totalnews-Zeile kannst Du einfacher haben

   int totalnews=news.LoadHistory(true);

denn das ist ja wie beschrieben der Rückgabewert der Funktion (analog dazu gibt die SaveHistory-Funktion die Anzahl der neu gespeicherten Elemente zurück).

warum Du den string nicht erhältst, verstehe ich auf die Schnelle nicht; ich bin 100% sicher, dass es bei mir funktioniert hat (und zwar auch für zukünftige Events) und ich jeweils einen korrekten Text (string mit 30 Zeichen; siehe Code-Zeile 120) erhalten habe. Es ist allerdings schon ein paar Wochen her, dass ich das programmiert habe; müsste mich dazu erst in Ruhe wieder neu eindenken, um zu verstehen, weshalb das bei Dir nicht klappt.

Was evtl.(!) eine Rolle spielen könnte sind Schreib-/Lesezeiten, da das Programm ja weiter ausgeführt wird bevor die Schreibvorgänge abgeschlossen sind (siehe Dokumentation zu den FileWrite-Funktionen) [gelöscht]

 
Chris70:

die totalnews-Zeile kannst Du einfacher haben

denn das ist ja wie beschrieben der Rückgabewert der Funktion (analog dazu gibt die SaveHistory-Funktion die Anzahl der neu gespeicherten Elemente zurück).

warum Du den string nicht erhältst, verstehe ich auf die Schnelle nicht; ich bin 100% sicher, dass es bei mir funktioniert hat (und zwar auch für zukünftige Events) und ich jeweils einen korrekten Text (string mit 30 Zeichen; siehe Code-Zeile 120) erhalten habe. Es ist allerdings schon ein paar Wochen her, dass ich das programmiert habe; müsste mich dazu erst in Ruhe wieder neu eindenken, um zu verstehen, weshalb das bei Dir nicht klappt.

Was evtl.(!) eine Rolle spielen könnte sind Schreib-/Lesezeiten, da das Programm ja weiter ausgeführt wird bevor die Schreibvorgänge abgeschlossen sind (siehe Dokumentation zu den FileWrite-Funktionen). Das ist übrigens auch der Grund für das vordergründig seltsame Vorgehen, weshalb ich den String nicht mit in die Eventstruktur gepackt habe. Ich hatte festgestellt, dass durch die separaten Befehle für die Struktur und die Strings der Schreibvorgang (warum auch immer) schneller abgeschlossen ist.

Hallo Chris,


gaube nicht das der Eventname etwas mit der Verabreitungszeit zu tun hat, auffällig ist, das es wirklich genau der Stichtag "heute" ist, welcher das ganze auslöst

 

ich glaube, ich habe den Bug gefunden: es kann sein, dass "zukünftig" bei mir nur funktioniert hatte, falls das Ereignis "zukünftig" relativ zu einem historischen Datum war (im Strategietester), aber nicht zukünftig zum Stichtag heute. Es fehlte die Zuordnung des Event-Namens in der Load-History-Funktion. Habe das gerade geändert; schau mal, ob das so mit Deiner OnInit funktioniert:

edit: nach Zeile 185 noch ergänzt:

ArrayResize(eventname,number_of_events+future_events);
Dateien:
News.mqh  11 kb
 
Chris70:

ich glaube, ich habe den Bug gefunden: es kann sein, dass "zukünftig" bei mir nur funktioniert hatte, falls das Ereignis "zukünftig" relativ zu einem historischen Datum war (im Strategietester), aber nicht zukünftig zum Stichtag heute. Es fehlte die Zuordnung des Event-Namens in der Load-History-Funktion. Habe das gerade geändert; schau mal, ob das so mit Deiner OnInit funktioniert:

edit: nach Zeile 185 noch ergänzt:

Ja jetzt gehts, 

danke@@chris70

 

für die Neulinge hier,


ich hab das ganze noch ergänzt um 2 Funktionen zum ein und ausblenden der News

void NewsCreate(const int hours)
  {

   int totalnews=ArraySize(news.event);
   for(int i=0;i<totalnews;i++)
     {
      string curr=CountryIdToCurrency((ENUM_COUNTRY_ID)news.event[i].country_id);

      string sym1 = StringSubstr(_Symbol,0,3);
      string sym2 = StringSubstr(_Symbol,3,3);

      if(news.event[i].time>TimeCurrent()-hours*60*60 && news.event[i].time<TimeCurrent()+hours*60*60
         && (curr==sym1 || curr==sym2)
         )
        {
         VLineCreate(0,curr+" "+news.eventname[i],0,news.event[i].time-TimeGMTOffset(),clrGray,STYLE_DOT,1,false,false,true,true,0);
        }

     }
     }

   void NewsDelete(const int hours)
     {
      int totalnews=ArraySize(news.event);
      for(int i=0;i<totalnews;i++)
        {
         string curr=CountryIdToCurrency((ENUM_COUNTRY_ID)news.event[i].country_id);

         string sym1 = StringSubstr(_Symbol,0,3);
         string sym2 = StringSubstr(_Symbol,3,3);


         if(news.event[i].time>TimeCurrent()-hours*60*60 && news.event[i].time<TimeCurrent()+hours*60*60
            && (curr==sym1 || curr==sym2)
            )
           {
            ObjectDelete(0,curr+" "+news.eventname[i]);
           }
        }

     }


das VlineCreate habe ich hier aus der Doku und ein wenig modifiziert


bool VLineCreate(const long            chart_ID=0,        // ID des Charts 
                 const string          name="VLine",      // Linienname 
                 const int             sub_window=0,      // Nummer des Unterfensters 
                 datetime              time=0,            // Linienzeit 
                 const color           clr=clrRed,        // Linienfarbe 
                 const ENUM_LINE_STYLE style=STYLE_SOLID, // Linienstil 
                 const int             width=1,           // Linienbreite 
                 const bool            back=false,        // Im Hintergrund 
                 const bool            selection=true,    // Wählen um zu bewegen 
                 const bool            ray=true,          // Fortsetzung der Linie nach unten 
                 const bool            hidden=true,       // Ausgeblendet in der Objektliste 
                 const long            z_order=0)         // Priorität auf Mausklick 
  { 
//--- wenn die Zeit der Linie nicht angegeben ist, wird sie auf den letzten Balken liegen 
   if(!time) 
      time=TimeCurrent(); 

   ResetLastError(); 

   if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0)
      && GetLastError() != 5040) 
     { 
      Print(__FUNCTION__, 
            ": Vertikale Linie konnte nicht erstellt werden! Fehlercode = "+name,GetLastError()); 
      return(false); 
     } 

   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); 
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width); 
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); 
   ObjectSetInteger(chart_ID,name,OBJPROP_RAY,ray); 
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); 
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); 
 
   return(true); 
  } 

den Fehler 5040 blende ich aus, um keinen Fehler zu bekommen wenn mal news keinen Namen haben, was oft genug vorkommt

Grund der Beschwerde: