English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
Das MQL5-Kochbuch: Signaltöne für Handelsereignisse in MetaTrader 5

Das MQL5-Kochbuch: Signaltöne für Handelsereignisse in MetaTrader 5

MetaTrader 5Beispiele | 27 Juni 2016, 13:02
2 732 0
Anatoli Kazharski
Anatoli Kazharski

Einleitung

In diesem Beitrag betrachten wir, wie Sound-Dateien in die Datei des Expert Advisors hinzugefügt werden, um so Signaltöne zu Handelsereignissen hinzuzufügen. Die Tatsache, dass die Dateien eingearbeitet werden, bedeutet, dass die Sound-Dateien sich innerhalb des Expert Advisors befinden werden. Wenn Sie also die kompilierte Version des Expert Advisors (*.ex5) an einen anderen Benutzer übergeben, müssen Sie ihm die Sound-Dateien nicht separat zur Verfügung stellen und erklären, wo sie abzulegen sind.

 

Entwicklung

Für unsere Testzwecke nehmen wir den Expert Advisor aus dem vorhergehenden Beitrag "Das MQL5-Kochbuch: Speichern der Optimierungsergebnisse eines Expert Advisors auf Basis bestimmter Kriterien". Zur Vereinfachung habe ich alles entfernt, was für das aktuelle Thema nicht relevant ist.

Um mithilfe von MQL5-Ressourcen Signaltöne zu einem Handelsereignis hinzuzufügen, können wir die Funktionen Alert() und PlaySound() nutzen. Wenn Sie sich für die Funktion Alert() entscheiden, wird immer der gleiche Signalton abgespielt und ein Fenster mit der jeweiligen Nachricht geöffnet. Sie sehen die Funktion in Aktion im Beitrag "Das MQL5-Kochbuch: Verwendung unterschiedlicher Druckmodi".

Der Warnton kann in den Einstellungen des Terminals festgelegt werden: Tools -> Options oder Strg+O. Außerdem müssen wir in der Registerkarte Events die Option "Enable" aktivieren, um Signaltöne für Ereignisse zu aktiveren, und in der Dropdown-Liste der Warntöne die entsprechende Sound-Datei auswählen.


Abb. 1. Registerkarte "Events" in den Einstellungen des Terminals

Allerdings haben Sie auch die Möglichkeit, einen eigenen Signalton für jedes benutzerdefinierte Programmereignis festzulegen. Zu diesem Zweck nutzen wir die Funktion PlaySound().

Bevor wir Signaltöne zum Expert Advisor hinzufügen, erstellen wir einen Expert Advisor für unseren Testzwecke. Wir setzen die Idee um, beim Laden eines Expert Advisors im Diagramm ein Sound-Panel zu öffnen. Das Sound-Panel besteht aus grafischen Objekten, bspw. dem Button (OBJ_BUTTON). Jedem Button wird ein eigener Ton zugewiesen, der beim Anklicken des Buttons wiedergegeben wird.

Im Internet fand ich 25 verschiedene Sound-Dateien im Format *.wav (diese können am Ende des Beitrags heruntergeladen werden). Sie müssen in den Ordner MetaTrader 5\MQL5\Files\Sounds gelegt werden. Um die Arbeit mit Sound-Dateien zu üben, erstellen wir nun einen Expert Advisor mit dem MQL5 Wizard. Gleich am Anfang legen wir die Array-Größe basierend auf der Menge der Buttons im Sound-Panel fest (es wird insgesamt 26 Buttons geben).

//--- Array size
#define ARRAY_SIZE 26

Dann müssen wir die Ordner und Dateinamen festlegen, die den Expert Advisor mit Ressourcen versorgen. Das geschieht mithilfe der Direktive #resource. Nach der Direktive geben wir den Ablageort der Dateien in Anführungszeichen an:

//--- Sound files
#resource "\\Files\\Sounds\\alert.wav"
#resource "\\Files\\Sounds\\AHOOGA.wav"
#resource "\\Files\\Sounds\\APPLAUSE.wav"
#resource "\\Files\\Sounds\\BONK.wav"
#resource "\\Files\\Sounds\\CARBRAKE.wav"
#resource "\\Files\\Sounds\\CASHREG.wav"
#resource "\\Files\\Sounds\\CLAP.wav"
#resource "\\Files\\Sounds\\CORKPOP.wav"
#resource "\\Files\\Sounds\\DOG.wav"
#resource "\\Files\\Sounds\\DRIVEBY.wav"
#resource "\\Files\\Sounds\\DRUMROLL.wav"
#resource "\\Files\\Sounds\\EXPLODE.wav"
#resource "\\Files\\Sounds\\FINALBEL.wav"
#resource "\\Files\\Sounds\\FROG.wav"
#resource "\\Files\\Sounds\\GLASS.wav"
#resource "\\Files\\Sounds\\GUNSHOT.wav"
#resource "\\Files\\Sounds\\LASER.wav"
#resource "\\Files\\Sounds\\LATNWHIS.wav"
#resource "\\Files\\Sounds\\PIG.wav"
#resource "\\Files\\Sounds\\RICOCHET.wav"
#resource "\\Files\\Sounds\\RINGIN.wav"
#resource "\\Files\\Sounds\\SIREN.wav"
#resource "\\Files\\Sounds\\TRAIN.wav"
#resource "\\Files\\Sounds\\UH_OH.wav"
#resource "\\Files\\Sounds\\VERYGOOD.wav"
#resource "\\Files\\Sounds\\WHOOSH.wav"

Jetzt müssen wir drei String-Arrays erstellen, die die Ablageorte der Ressourcendateien, die Namen der grafischen Objekte und den auf den grafischen Objekten angezeigten Text enthalten. Beachten Sie den doppelten Doppelpunkt beim Angeben der Dateiablageorte. Dabei handelt es sich um eine spezielle Angabe für den Aufruf der Ressource nach Namen.

//--- Sound file location
string sound_paths[ARRAY_SIZE]=
  {
   "::Files\\Sounds\\alert.wav",
   "::Files\\Sounds\\AHOOGA.wav",
   "::Files\\Sounds\\APPLAUSE.wav",
   "::Files\\Sounds\\BONK.wav",
   "::Files\\Sounds\\CARBRAKE.wav",
   "::Files\\Sounds\\CASHREG.wav",
   "::Files\\Sounds\\CLAP.wav",
   "::Files\\Sounds\\CORKPOP.wav",
   "::Files\\Sounds\\DOG.wav",
   "::Files\\Sounds\\DRIVEBY.wav",
   "::Files\\Sounds\\DRUMROLL.wav",
   "::Files\\Sounds\\EXPLODE.wav",
   "::Files\\Sounds\\FINALBEL.wav",
   "::Files\\Sounds\\FROG.wav",
   "::Files\\Sounds\\GLASS.wav",
   "::Files\\Sounds\\GUNSHOT.wav",
   "::Files\\Sounds\\LASER.wav",
   "::Files\\Sounds\\LATNWHIS.wav",
   "::Files\\Sounds\\PIG.wav",
   "::Files\\Sounds\\RICOCHET.wav",
   "::Files\\Sounds\\RINGIN.wav",
   "::Files\\Sounds\\SIREN.wav",
   "::Files\\Sounds\\TRAIN.wav",
   "::Files\\Sounds\\UH_OH.wav",
   "::Files\\Sounds\\VERYGOOD.wav",
   "::Files\\Sounds\\WHOOSH.wav"
  };
//--- Names of graphical objects
string sound_names[ARRAY_SIZE]=
  {
   "sound_button01","sound_button02",
   "sound_button03","sound_button04",
   "sound_button05","sound_button06",
   "sound_button07","sound_button08",
   "sound_button09","sound_button10",
   "sound_button11","sound_button12",
   "sound_button13","sound_button14",
   "sound_button15","sound_button16",
   "sound_button17","sound_button18",
   "sound_button19","sound_button20",
   "sound_button21","sound_button22",
   "sound_button23","sound_button24",
   "sound_button25","sound_button26"
  };
//--- Text displayed on graphical objects
string sound_texts[ARRAY_SIZE]=
  {
   "ALERT","AHOOGA","APPLAUSE","BONK","CARBRAKE","CASHREG",
   "CLAP","CORKPOP","DOG","DRIVEBY","DRUMROLL","EXPLODE","FINALBEL",
   "FROG","GLASS","GUNSHOT","LASER","LATNWHIS","PIG",
   "RICOCHET","RINGIN","SIREN","TRAIN","UH_OH","VERYGOOD","WHOOSH"
  };

Schreiben wir die Funktion CreateButton(), die das grafische Objekt "Button" mit den festgelegten Eigenschaften in einem Diagramm erstellt:

//+------------------------------------------------------------------+
//| Creating the Button object                                       |
//+------------------------------------------------------------------+
void CreateButton(long              chart_id,         // chart id
                  int               sub_window,       // window number
                  string            name,             // object name
                  string            text,             // displayed name
                  ENUM_ANCHOR_POINT anchor,           // anchor point
                  ENUM_BASE_CORNER  corner,           // chart corner
                  string            font_name,        // font
                  int               font_size,        // font size
                  color             font_color,       // font color
                  color             background_color, // background color
                  color             border_color,     // border color
                  int               x_size,           // width
                  int               y_size,           // height
                  int               x_distance,       // X-coordinate
                  int               y_distance,       // Y-coordinate
                  long              z_order)          // Z-order
  {
//--- Creating an object
   if(ObjectCreate(chart_id,name,OBJ_BUTTON,sub_window,0,0))
     {
      ObjectSetString(chart_id,name,OBJPROP_TEXT,text);                  // setting name
      ObjectSetString(chart_id,name,OBJPROP_FONT,font_name);             // setting font
      ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color);          // setting font color
      ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color);  // setting background color
      ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); // setting border color
      ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor);             // setting anchor point
      ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner);             // setting chart corner
      ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size);        // setting font size
      ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size);              // setting width X
      ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size);              // setting height Y
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance);      // setting X-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance);      // setting Y-coordinate
      ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);          // cannot select the object if FALSE
      ObjectSetInteger(chart_id,name,OBJPROP_STATE,false);               // button state (clicked/unclicked)
      ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order);            // higher/lower Z-order
      ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n");               // no tooltip if "\n"
     }
  }

Um es interessanter zu machen, wird die Farbe jedes Buttons zufällig gewählt. Dazu schreiben wir die einfache Funktion GetRandomColor():

//+------------------------------------------------------------------+
//| Returning a random color                                         |
//+------------------------------------------------------------------+
color GetRandomColor()
  {
//--- Select a random color from 0 to 25
   switch(MathRand()%26)
     {
      case 0  : return(clrOrange);           break;
      case 1  : return(clrGold);             break;
      case 2  : return(clrChocolate);        break;
      case 3  : return(clrChartreuse);       break;
      case 4  : return(clrLime);             break;
      case 5  : return(clrSpringGreen);      break;
      case 6  : return(clrMediumBlue);       break;
      case 7  : return(clrDeepSkyBlue);      break;
      case 8  : return(clrBlue);             break;
      case 9  : return(clrSeaGreen);         break;
      case 10 : return(clrRed);              break;
      case 11 : return(clrSlateGray);        break;
      case 12 : return(clrPeru);             break;
      case 13 : return(clrBlueViolet);       break;
      case 14 : return(clrIndianRed);        break;
      case 15 : return(clrMediumOrchid);     break;
      case 16 : return(clrCrimson);          break;
      case 17 : return(clrMediumAquamarine); break;
      case 18 : return(clrDarkGray);         break;
      case 19 : return(clrSandyBrown);       break;
      case 20 : return(clrMediumSlateBlue);  break;
      case 21 : return(clrTan);              break;
      case 22 : return(clrDarkSalmon);       break;
      case 23 : return(clrBurlyWood);        break;
      case 24 : return(clrHotPink);          break;
      case 25 : return(clrLightSteelBlue);   break;
      //---
      default : return(clrGold);
     }
//---
   return(clrGold);
  }

Schreiben wir nun die Funktion SetSoundPanel(), die das Sound-Panel zum Diagramm hinzufügt:

//+------------------------------------------------------------------+
//| Adding the sound panel to the chart                              |
//+------------------------------------------------------------------+
void SetSoundPanel()
  {
   int   column_count =0;       // Column counter
   int   x_dist       =10;      // Indent from the left side of the chart
   int   y_dist       =15;      // Indent from the top of the chart
   int   x_size       =100;     // Button width
   int   y_size       =20;      // Button height
   color button_color =clrNONE; // Button color
//--- Set the objects
   for(int i=0; i<ARRAY_SIZE; i++)
     {
      //--- Increase the column counter
      column_count++;
      //--- Get the button color
      button_color=GetRandomColor();
      //--- Draw a button
      CreateButton(0,0,sound_names[i],sound_texts[i],
                   ANCHOR_LEFT_UPPER,CORNER_LEFT_UPPER,"Arial",8,
                   clrWhite,button_color,button_color,x_size,y_size,x_dist,y_dist,1);
      //--- If two buttons have already been set in the same row
      if(column_count==2)
        {
         x_dist=10;        // Move the X-coordinate to the initial position
         y_dist+=20;       // Set the Y-coordinate for the next row
         column_count=0;   // Zero out the counter
        }
      else
      //--- Set the X-coordinate for the next button 
         x_dist+=x_size;
     }
//--- Refresh the chart
   ChartRedraw(0);
  }

Zum Entfernen des Panels aus dem Diagramm nutzen wir die nachfolgend aufgeführten Funktionen:

//+------------------------------------------------------------------+
//| Deleting the info panel                                          |
//+------------------------------------------------------------------+
void DeleteSoundPanel()
  {
//--- Delete position properties and their values
   for(int i=0; i<ARRAY_SIZE; i++)
      DeleteObjectByName(name_sound_object[i]);
//--- Redraw the chart
   ChartRedraw();
  }
//+------------------------------------------------------------------+
//| Deleting objects by name                                         |
//+------------------------------------------------------------------+
void DeleteObjectByName(string name)
  {
//--- If the object is found
   if(ObjectFind(ChartID(),name)>=0)
     {
      //--- If an error occurred when deleting, print the relevant message
      if(!ObjectDelete(ChartID(),name))
         Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!");
     }
  }

Beim Laden des Expert Advisors wird das Panel also aus der Funktion OnInit() im Diagramm eingerichtet und beim Entfernen des Expert Advisors durch die Funktion OnDeinit() aus dem Diagramm entfernt.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- Set the sound panel
   SetSoundPanel();
  }
//+------------------------------------------------------------------+
//| Deinitialization function of the expert advisor                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the sound panel
   DeleteSoundPanel();
  }

Nun müssen wir nur noch die Interaktion mit dem Panel implementieren, sodass der jeweilige Ton wiedergegeben wird, wenn ein bestimmter Button angeklickt wird. Um das Ganze noch fröhlicher zu gestalten, ändern wir die Farben der Buttons, wenn einer der Buttons im Sound-Panel gedrückt wird. Dazu benötigen wir die Funktion ChangeColorsOnSoundPanel(), deren Code unten aufgeführt ist:

//+------------------------------------------------------------------+
//| Changing colors on the sound panel                               |
//+------------------------------------------------------------------+
void ChangeColorsOnSoundPanel()
  {
   color clr=clrNONE; // Button color
//--- Iterate over all buttons in a loop and change their color
   for(int i=0; i<ARRAY_SIZE; i++)
     {
      //--- Get the new color
      clr=GetRandomColor();
      //--- Set the border color
      ObjectSetInteger(0,sound_names[i],OBJPROP_BGCOLOR,clr);
      //--- Set the background color
      ObjectSetInteger(0,sound_names[i],OBJPROP_BORDER_COLOR,clr);
      //--- Unclicked button
      ObjectSetInteger(0,sound_names[i],OBJPROP_STATE,false);
      //--- Refresh the chart
      ChartRedraw(0);
      //--- Wait for 20 ms (lag)
      Sleep(20);
     }
  }

Und zu guter Letzt muss der folgende Code zur Funktion OnChartEvent() hinzugefügt werden:

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void OnChartEvent(const int     id,     // Event identifier  
                  const long&   lparam, // Parameter of the event of type long
                  const double& dparam, // Parameter of the event of type double
                  const string& sparam) // Parameter of the event of type string
  {
//--- If there was an event of left-clicking on the object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If the object name contains "sound_button"
      if(StringFind(sparam,"sound_button",0)>=0)
        {
         //--- Play the sound based on the object name
         //    5019 - ERR_FILE_NOT_EXIST - The file does not exist
         if(!PlaySound(GetSoundPath(sparam)))
            Print("Error: ",GetLastError());
         //--- Change colors of all buttons
         ChangeColorsOnSoundPanel();
        }
     }
  }

Der markierte String im obigen Code bedeutet, dass der Ablageort der Sound-Datei mithilfe der benutzerdefinierten Funktion GetSoundPath() an die Funktion PlaySound() übergeben wird. Der Code der Funktion GetSoundPath() ist nachfolgend aufgeführt:

//+------------------------------------------------------------------+
//| Returning sound file location by the object name                 |
//+------------------------------------------------------------------+
string GetSoundPath(string object_name)
  {
//--- Iterate over all sound panel objects in a loop
   for(int i=0; i<ARRAY_SIZE; i++)
     {
      //--- If the name of the object clicked in the chart
      //    matches one of those available on the panel, return the file location
      if(object_name==name_sound_object[i])
         return(path_sound_object[i]);
     }
//---
   return("");
  }

Nun ist alles fertig. Das Sound-Panel (das Programm kann aus den Anhängen dieses Beitrags heruntergeladen werden) wird eingerichtet, sobald der Expert Advisor an das Diagramm angehängt wird:

Das Sound-Panel im Diagramm

Abb. 2. Das Sound-Panel im Diagramm

Das Prinzip der Arbeit mit Sound-Dateien dürfte nun klar sein. Kehren wir zurück zu unserem Expert Advisor aus dem vorhergehenden Beitrag "Das MQL5-Kochbuch: Speichern der Optimierungsergebnisse eines Expert Advisors auf Basis bestimmter Kriterien" und entscheiden, welche Töne wir im Expert Advisor nutzen werden. Wir erstellen Resources.mqh und integrieren die Datei in die Hauptdatei des Expert Advisors.

//--- Include custom libraries
#include "Include/Errors.mqh"
#include "Include/Enums.mqh"
#include "Include/Resources.mqh"
#include "Include/TradeSignals.mqh"
#include "Include/TradeFunctions.mqh"
#include "Include/ToString.mqh"
#include "Include/Auxiliary.mqh"

Wir wählen nun Dateien für die wichtigsten Handelsereignisse aus.

//--- Sound files
#resource "\\Files\\Sounds\\AHOOGA.WAV"   // Error
#resource "\\Files\\Sounds\\CASHREG.WAV"  // Position opening/position volume increase/pending order triggering
#resource "\\Files\\Sounds\\WHOOSH.WAV"   // Pending order/Stop Loss/Take Profit setting/modification
#resource "\\Files\\Sounds\\VERYGOOD.WAV" // Position closing at profit
#resource "\\Files\\Sounds\\DRIVEBY.WAV"  // Position closing at loss
//--- Sound file location
string SoundError          = "::Files\\Sounds\\AHOOGA.WAV";
string SoundOpenPosition   = "::Files\\Sounds\\CASHREG.WAV";
string SoundAdjustOrder    = "::Files\\Sounds\\WHOOSH.WAV";
string SoundCloseWithProfit= "::Files\\Sounds\\VERYGOOD.WAV";
string SoundCloseWithLoss  = "::Files\\Sounds\\DRIVEBY.WAV";

Ich möchte auch erwähnen, dass Sie im Expert Advisor neben den als Ressourcen verwendeten Sound-Dateien auch Bilder im *.bmp-Format für das Interface, Textdateien und sogar Indikatoren speichern können. EAs für MetaTrader 5 werden jetzt als voll funktionsfähige Anwendungen betrachtet. Das ist sehr bequem, da Sie anstatt mehrerer Dateien nur eine übergeben müssen.

Also weiter. In den externen Parametern müssen wir den Parameter UseSound hinzufügen, um die Möglichkeit zu erhalten, Töne zu deaktivieren:

//--- External parameters of the Expert Advisor
input  int        NumberOfBars =2;    // Number of one-direction bars
sinput double     Lot          =0.1;  // Lot
input  double     TakeProfit   =100;  // Take Profit
input  double     StopLoss     =50;   // Stop Loss
input  double     TrailingStop =10;   // Trailing Stop
input  bool       Reverse      =true; // Position reversal
sinput bool       UseSound     =true; // Sound notifications

In Include\Enums.mqh erstellen wir die Aufzählung ENUM_SOUNDS für Töne.

//--- Sounds
enum ENUM_SOUNDS
  {
   SOUND_ERROR             =0,   // Error
   SOUND_OPEN_POSITION     = 1,  // Position opening/position volume increase/pending order triggering
   SOUND_ADJUST_ORDER      = 2,  // Stop Loss/Take Profit/pending order setting
   SOUND_CLOSE_WITH_PROFIT = 3,  // Position closing at profit
   SOUND_CLOSE_WITH_LOSS   = 4   // Position closing at loss
  };

Diese Identifikatoren werden für die benutzerdefinierte Funktion PlaySoundByID() benötigt.

//+------------------------------------------------------------------+
//| Playing sounds                                                   |
//+------------------------------------------------------------------+
void PlaySoundByID(ENUM_SOUNDS id)
  {
//--- If it is the real-time mode and sounds are enabled
   if(IsRealtime() && UseSound)
     {
      //--- Play the sound based on the identifier passed
      switch(id)
        {
         case SOUND_ERROR              : PlaySound(SoundError);            break;
         case SOUND_OPEN_POSITION      : PlaySound(SoundOpenPosition);     break;
         case SOUND_ADJUST_ORDER       : PlaySound(SoundAdjustOrder);      break;
         case SOUND_CLOSE_WITH_PROFIT  : PlaySound(SoundCloseWithProfit);  break;
         case SOUND_CLOSE_WITH_LOSS    : PlaySound(SoundCloseWithLoss);    break;
        }
     }
  }

Während Handelsoperationen, die durch den Expert Advisor durchgeführt werden, können Soundeffekte durch Aufrufen von PlaySoundByID() aus den entsprechenden Handelsfunktionen abgespielt werden. Sehen wir uns an, wie dies in der Funktion OpenPosition() umgesetzt wird:

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(0);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(10));
//--- The Instant Execution and Market Execution modes
//    *** Starting with build 803, Stop Loss and Take Profit                             ***
//    *** can be set upon opening a position in the SYMBOL_TRADE_EXECUTION_MARKET mode ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT ||
      symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If the position failed to open
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
        {
         //--- Play the error sound and print the relevant message
         PlaySoundByID(SOUND_ERROR);
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
      //--- Otherwise play the position opening sound
      else
         PlaySoundByID(SOUND_OPEN_POSITION);
     }
  }

Falls allerdings eine Position bei Stop Loss, Take Profit, manuell oder anderweitig geschlossen wird, muss dieses Ereignis in der Funktion OnTrade() überwacht werden. Dafür schreiben eine weitere Funktion, SoundNotification(), die die erforderlichen Prüfungen durchführt: Wenn die Historie der Abschlüsse einen neuen Abschluss mit dem Identifikator DEAL_ENTRY_OUT oder DEAL_ENTRY_INOUT für das aktuelle Symbol anzeigt (vollständige/teilweise Schließung der Position oder eine Umkehrung), prüft das Programm, ob dieser Abschluss einen Gewinn oder Verlust mit sich brachte, und spielt den jeweiligen Ton ab.

//+------------------------------------------------------------------+
//| Sound notification                                               |
//+------------------------------------------------------------------+
void SoundNotification()
  {
//--- If it is the real-time mode and sounds are enabled
   if(IsRealtime() && UseSound)
     {
      ulong        ticket      =0; // Deal ticket
      int          total       =0; // Total deals
      static ulong last_ticket =0; // Last ticket prior to this check
      //--- Get the complete history
      if(!HistorySelect(0,TimeCurrent()+1000))
         return;
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- In the obtained list, iterate over all deals from the last one to the first one
      for(int i=total-1; i>=0; i--)
        {
         //--- If the deal ticket by its position in the list has been obtained
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- get the symbol of the deal
            GetHistoryDealProperties(ticket,D_SYMBOL);
            //--- If the symbol of the deal and the current symbol are the same
            if(deal.symbol==_Symbol)
              {
               //--- get the direction of the deal
               GetHistoryDealProperties(ticket,D_ENTRY);
               //--- If it is position closing, volume decrease or reversal
               if(deal.entry==DEAL_ENTRY_OUT || deal.entry==DEAL_ENTRY_INOUT)
                 {
                  //--- If the ticket of the current deal from the list (the last deal for the symbol) is equal to the previous ticket
                  //    or this is the initialization of the ticket of the last deal
                  if(ticket==last_ticket || last_ticket==0)
                    {
                     //--- Save the ticket and exit
                     last_ticket=ticket;
                     return;
                    }
                  //--- Get the result of the deal
                  GetHistoryDealProperties(ticket,D_PROFIT);
                  //--- In case of profit
                  if(deal.profit>=0)
                    {
                     //--- Profit sound
                     PlaySoundByID(SOUND_CLOSE_WITH_PROFIT);
                     //--- Save the ticket number
                     last_ticket=ticket;
                     return;
                    }
                  //--- In case of loss
                  if(deal.profit<0)
                    {
                     //--- Loss sound
                     PlaySoundByID(SOUND_CLOSE_WITH_LOSS);
                     //--- Save the ticket number
                     last_ticket=ticket;
                     return;
                    }
                 }
              }
           }
        }
     }
  }

Die Funktion SoundNotification() muss in den Funktionen OnInit() und OnTrade() platziert werden:

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initialize the new bar
   CheckNewBar();
//--- Initialize tickets of the last deals for the symbol
   SoundNotification();
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Monitoring trade events                                          |
//+------------------------------------------------------------------+
void OnTrade()
  {
//--- Sound notification
   SoundNotification();
  }

Der Signalton wurde ebenfalls am Ende der Funktion ModifyTrailingStop() beim Modifizieren der Trailing-Stop-Ebene hinzugefügt.

 

Fazit

Das ist alles. Alle Dateien für Testzwecke können aus den Anhängen dieses Beitrags heruntergeladen werden. Zum Thema Töne im Terminal möchte ich Ihre Aufmerksamkeit auf eine interessante Lösung lenken, die in der Code Base unter dem Namen CMIDI (von Integer) zur Verfügung steht: Sie ermöglicht Ihnen das Abspielen von MIDI-Dateien in MetaTrader 5. Viel Erfolg!

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/748

Beigefügte Dateien |
sounds.zip (321.8 KB)
soundpanel.mq5 (14.07 KB)
Das MQL5-Kochbuch: Speichern der Optimierungsergebnisse eines Expert Advisors auf Basis bestimmter Kriterien Das MQL5-Kochbuch: Speichern der Optimierungsergebnisse eines Expert Advisors auf Basis bestimmter Kriterien
Wir setzen die Serie der Beiträge zur MQL5-Programmierung fort. Diesmal sehen wir uns an, wie man bei der Optimierung der Parameter eines Expert Advisors Ergebnisse erhält. Mit der Umsetzung wird sichergestellt, dass die Werte des entsprechenden Durchlaufs in eine Datei geschrieben werden, wenn die in den externen Parametern festgelegten Bedingungen erfüllt werden. Neben Testwerten speichern wir auch die Parameter, die zu diesen Ergebnissen geführt haben.
Das MQL5-Kochbuch: Überwachen von mehreren Timeframes in einem Fenster Das MQL5-Kochbuch: Überwachen von mehreren Timeframes in einem Fenster
In MetaTrader 5 stehen 21 Timeframes für die Analyse zur Auswahl. Sie können spezielle Diagrammobjekte nutzen, die Sie im bestehenden Diagramm platzieren können, und Symbol, Timeframe und einige weitere Eigenschaften direkt dort festlegen. Dieser Beitrag liefert detaillierte Informationen zu solchen grafischen Diagrammobjekten: Wir erstellen einen Indikator mit Steuerelementen (Buttons), die es uns ermöglichen, mehrere Diagrammobjekte gleichzeitig in einem Unterfenster einzurichten. Ferner werden Diagrammobjekte genau in das Unterfenster passen und werden automatisch angepasst, wenn die Größe des Hauptdiagramms oder des Terminalfensters verändert wird.
Erweiterung der MQL5-Standardbibliothek und Wiederverwendung von Code Erweiterung der MQL5-Standardbibliothek und Wiederverwendung von Code
Die MQL5-Standardbibliothek erleichtert Ihnen das Leben als Entwickler. Dennoch geht sie nicht auf die Bedürfnisse aller Entwickler auf der Welt ein. Wenn Sie also das Gefühl haben, dass Sie mehr benutzerdefinierte Funktionen brauchen, können Sie einen Schritt weitergehen und die Bibliothek erweitern. Dieser Beitrag begleitet Sie durch die Integration des technischen Indikators ZigZag von MetaQuotes in die Standardbibliothek. Wir lassen uns durch die Designphilosophie von MetaQuotes inspirieren, um unser Ziel zu erreichen.
Grundlagen der Börsenkursbildung am Beispiel des Terminhandelsbereichs der Moskauer Börse Grundlagen der Börsenkursbildung am Beispiel des Terminhandelsbereichs der Moskauer Börse
In diesem Beitrag wird die Theorie der Kursbildung und der Besonderheiten der Verrechnung im Terminhandelsbereich der Moskauer Börse vorgestellt. Es handelt sich um einen umfassenden Überblicksartikel, der sowohl Neueinsteigern helfen soll, erste Erfahrungen im Terminhandel zu sammeln, als auch erfahrenen Devisenhändlern, die den Handel auf einer zentralisierten Plattform in Erwägung ziehen.