下载MetaTrader 5

MQL5 细则手册:MetaTrader 5 交易事件的声音通知

27 五月 2014, 13:28
Anatoli Kazharski
0
910

简介

在本文中,我们将考虑在“EA 交易”的文件中包含声音文件、从而为交易事件添加声音通知的事宜。将包含文件的事实意味着声音文件将位于“EA 交易”的内部。因此,在向其他用户提供编译后的“EA 交易”版本 (*.ex5) 时,您无需再提供声音文件并说明它们应予以保存的位置。

 

开发

出于测试目的,我们的 EA 交易取自前文“MQL5 细则手册:保存基于指定标准的“EA 交易”的优化结果”。为使其更加简单,我去除了与当前主题无关的所有因素。

要使用 MQL5 资源为交易事件添加声音通知,我们可以使用 Alert()PlaySound() 函数。如果您选择 Alert() 函数,它将总是播放相同的声音通知并打开一个含相关消息的窗口。您可以在 “MQL5 细则手册:使用不同的打印模式”一文中查看它的运转情况。

警示声可在终端设置中进行设置:Tools(工具)-> Options(选项)或 Ctrl+O。然后在 Events(事件)选项卡中,我们需要勾选 "Enable"(启用)选项以为事件启用声音通知,并在提醒下拉列表中选择相应的声音文件。


图 1. 终端设置中的 "Events"(事件)选项卡

然而,您也可以为任何自定义程序事件设置一个独特的声音通知。为此,我们使用 PlaySound 函数。

在我们将声音文件添加至“EA 交易”之前,让我们创建一个用于测试的“EA 交易”。当在图表上加载“EA 交易”时,让我们实现一个打开声音面板的构想。声音面板将由图形对象构成,例如按钮(OBJ_BUTTON)。每个按钮将具有分配给其的独特声音,声音将在按下按钮时播放。

我在网上找到 25 种 *.wav 格式的不同声音文件(这些在本文的末尾提供下载链接)。必须将它们放在 MetaTrader 5\MQL5\Files\Sounds 文件夹中。要得到使用声音文件的诀窍,现在我们将使用 MQL5 向导创建一个新的“EA 交易”。在最开始,我们基于声音面板上的按钮数目指定数组的大小(总共将有 26 个按钮)。

//--- Array size
#define ARRAY_SIZE 26

然后,我们需要指定将为“EA 交易”提供资源的文件夹和文件名称。这可以使用 #resource 指令完成。在该指令后,我们在双引号中指定文件位置:

//--- 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"

现在,我们需要创建三个字符串数组,用于包含源文件的位置、图形对象的名称以及在图形对象上显示的文本。请注意指定文件位置时使用的双冒号 - 这是按名称调用资源的特别说明。

//--- 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"
  };

我们来编写一个函数 CreateButton(),它将在图像上创建具有指定属性的图形对象“按钮”:

//+------------------------------------------------------------------+
//| 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"
     }
  }

为使其更加有趣,将随机选择每个按钮的颜色。要实现这一点,我们将编写一个简单的函数 - 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);
  }

现在我们来编写一个函数,以将声音面板添加至图表 - SetSoundPanel():

//+------------------------------------------------------------------+
//| 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);
  }

要从图表上删除面板,我们将使用下面提供的函数:

//+------------------------------------------------------------------+
//| 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!");
     }
  }

因此,当加载“EA 交易”时,面板将从 OnInit() 函数设置到图表上,并在删除“EA 交易”时通过 OnDeinit() 函数从图表上删除。

//+------------------------------------------------------------------+
//| 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();
  }

现在,我们只需要实现与面板的交互,以便在按下某个按钮时播放相应的声音。为使其更加具有趣味性,我们将在按下一个声音面板按钮时更改按钮颜色。要实现这一点,我们将需要 ChangeColorsOnSoundPanel() 函数,其代码如下所示:

//+------------------------------------------------------------------+
//| 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);
     }
  }

最后,应将下述代码添加至 OnChartEvent() 函数:

//+------------------------------------------------------------------+
//| 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();
        }
     }
  }

上述代码中高亮显示的字符串表示声音文件的位置已使用自定义 GetSoundPath() 函数传递至 PlaySound() 函数。GetSoundPath() 函数的代码如下所示:

//+------------------------------------------------------------------+
//| 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("");
  }

现在,一切准备就绪。声音面板(该程序可以从本文的附件下载)将在“EA 交易”附加至图表时设置:

图表上的声音面板

图 2. 图表上的声音面板

那么,声音文件的使用原理现已清楚。我们回到来自前文 “MQL5 细则手册:保存基于指定标准的“EA 交易”的优化结果”的“EA 交易”,并决定我们将在“EA 交易”中使用哪些声音。我们创建 Resources.mqh 并将其包含在“EA 交易”的主文件中。

//--- 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"

现在,我们为主交易事件选择文件。

//--- 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";

我还想说的是,除了用作资源的声音文件,您也可以在“EA 交易”中存储用作界面的 *.bmp 图像、文本文件甚至指标。MetaTrader 5 的 EA 现被视为功能完备的应用程序 - 这非常方便,您只需传递一个文件而不是多个文件。

我们继续。在外部参数中,我们需要添加 UseSound 参数以能够禁用声音:

//--- 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

Include\Enums.mqh 中,我们为声音创建 ENUM_SOUNDS 枚举。

//--- 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
  };

自定义函数 PlaySoundByID() 将需要这些标识符。

//+------------------------------------------------------------------+
//| 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;
        }
     }
  }

在“EA 交易”执行交易操作期间,音效可通过从相应的交易函数调用 PlaySoundByID() 来播放。我们来看看这一点是如何在 OpenPosition() 函数中实现的:

//+------------------------------------------------------------------+
//| 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);
     }
  }

然而,如果一个仓位在“止损”、“获利”位通过手动或其他方式平仓,必须在 OnTrade() 函数中对该事件进行监控。要实现这一点,我们将编写另一个函数 SoundNotification(),它将负责必要的检查:如果交易的历史数据显示当前交易品种的新的交易具有 DEAL_ENTRY_OUTDEAL_ENTRY_INOUT 标识符(完全/部分平仓或反向操作),程序将检查该交易平仓获利或亏损以及是否播放相应的声音。

//+------------------------------------------------------------------+
//| 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;
                    }
                 }
              }
           }
        }
     }
  }

SoundNotification() 函数应位于 OnInit()OnTrade() 函数中:

//+------------------------------------------------------------------+
//| 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();
  }

当修改追踪止损水平时,声音通知也被添加至 ModifyTrailingStop() 函数的末尾。

 

总结

就是这样。用于测试的所有文件都可在本文的附件中下载。说起终端的声音,我想提醒读者注意代码库中 CMIDI 名称下的一个有趣的解决方案(整型):它允许您在 MetaTrader 5 中播放 MIDI 文件。祝您好运!

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/748

附加的文件 |
sounds.zip (321.8 KB)
soundpanel.mq5 (14.07 KB)
扩展 MQL5 标准库和重用代码 扩展 MQL5 标准库和重用代码

作为一名开发人员,MQL5 标准库让您的工作变得更加容易。然而,它无法实现世界上所有开发人员的全部需求,所以,如果您觉得您需要更多的自定义程序,您可以对标准库进行进一步的扩展。本文指导您完成将 MetaQuotes 的峰谷技术指标集成至标准库。我们从 MetaQuotes 的设计理念获得启发以实现我们的目标。

技术指标和数字滤波器 技术指标和数字滤波器

在本文中,技术指标被视为数字滤波器。本文对数字滤波器的操作原理和基本特性进行了说明。同时,本文还涉及在 MetaTrader 5 终端中接收滤波器内核以及与建立一个频谱分析程序一文中提出的现成频谱分析程序集成等实用方法。本文将典型数字滤波器的脉冲和频谱特性用作示例。

MQL5 细则手册:在单一窗口中监控多个时间表 MQL5 细则手册:在单一窗口中监控多个时间表

在 MetaTrader 5 中,有 21 个时间表可供分析。您可以利用能置于现有图表上的特殊图表对象,并在相应位置设置交易品种、时间表及其他属性。文章将对此类图表图形对象进行详细介绍:我们将使用控件(按钮)创建指标,以便同时在子窗口中建立多个图表对象。此外,图表对象将准确置于子窗口中,并随主图表或终端窗口的大小调整自动进行校正。

MQL5 细则手册:指标子窗口控件 - 按钮 MQL5 细则手册:指标子窗口控件 - 按钮

本文中,我们将探讨开发具备按钮控件的用户界面的示例。为向用户传递互动性理念,当光标悬停于按钮时,按钮颜色会发生改变。光标位于按钮之上时,按钮颜色将稍微变暗,点击时,按钮颜色则会变得明显更暗。此外,我们将为每一按钮添加工具提示,从而创建直观界面。