
A system of voice notifications for trade events and signals
Table of Contents
- Introduction
- Developing a voice notification system
- Practical application in indicators
- Practical application in trading Expert Advisors
- Practical application in Quick Trading Tools
- Conclusion
Introduction
The MetaTrader 5 trading terminal features options enabling the usage of sound alerts. The system covers 11 events, to which separate sound alerts can be assigned. However, there are much more situations when the user may need to receive audio notification, such as the emergence of a trading system signal or Expert Advisor actions, including opening, closing or modification of a position. Nowadays, voice assistants play a prominent role in human life, as we often use navigators, voice search and translators. This idea could be used when trading in the MetaTrader 5 terminal. In this article, I will try to develop a simple and user friendly system of voice notifications for various trade events, market states or signals generated by trading signals.
Developing a voice notification system
Before we start creating the system, I would like to add a note. The events that I have selected for implementing voice notifications, are only chosen to demonstrate the system. If this set is not sufficient, you can add your own events and the relevant voice alerts. After reading the article, expansion and customization of the system will be very easy, even if you do not have extensive MQL5 knowledge.
This system is implemented as a CSoundsLib class in an include file. So, open the MQL5/Include folder and create a folder entitled SoundsLib, in which you should create the SoundsLib.mqh file. Before creating the class, let us introduce two enumerations which will further be used for working with voice alerts. The first of them is LANGUAGE, which will be used for alert language selection. The system will support two languages: English and Russian.
//+------------------------------------------------------------------+ //| Enumeration for switching the notification language | //+------------------------------------------------------------------+ enum LANGUAGE { RUSSIAN, // Russian ENGLISH // English };
The second enumeration contains the set of events which I have selected for demonstration purposes. Further in the article, I will show how to embed them into various ready-made systems, including indicators, Expert Advisors and quick trading toolkits. The enumeration is called MESSAGE:
//+------------------------------------------------------------------+ //| List of voice alerts | //+------------------------------------------------------------------+ enum MESSAGE { STATUS_ON, // Status of enabled voice alerts SIGNAL_BUY, // A Buy signal SIGNAL_SELL, // A Sell signal BUY_ORDER_SET, // A Buy order has been placed SELL_ORDER_SET, // A Sell order has been placed BUYLIMIT_ORDER_SET, // A Limit Buy order has been placed BUYSTOP_ORDER_SET, // A Stop Buy order has been placed SELLLIMIT_ORDER_SET, // A Limit Sell order has been placed SELLSTOP_ORDER_SET, // A Stop Sell order has been placed BUYLIMIT_ORDER_DELETE, // A Limit Buy order has been deleted BUYSTOP_ORDER_DELETE, // A Stop Buy order has been deleted SELLLIMIT_ORDER_DELETE, // A Limit Sell order has been deleted SELLSTOP_ORDER_DELETE, // A Stop Sell order has been deleted BUY_ORDER_CLOSE_PROFIT, // A Buy order has closed with a profit BUY_ORDER_CLOSE_LOSS, // A Buy order has closed with a loss SELL_ORDER_CLOSE_PROFIT, // A Sell order has closed with a profit SELL_ORDER_CLOSE_LOSS, // A Sell order has closed with a loss BUY_ORDER_CLOSE_TP, // A Buy order has been closed by Take Profit BUY_ORDER_CLOSE_SL, // A Buy order has been closed by Stop Loss SELL_ORDER_CLOSE_TP, // A Sell order has been closed by Take Profit SELL_ORDER_CLOSE_SL, // A Sell order has been closed by Stop Loss MARKET_CLOSE, // Market is closed AUTO_TRADING_ON, // Automated trading is allowed AUTO_TRADING_OFF, // Automated trading is prohibited };
The basic set contains 24 alerts. Most of them relate to the operation and status of open positions and pending orders. Some alerts are used for trading environment notifications. The last three notifications relate to common events. Notification about the status of the enabled voice alert system, as well as notification about the emergence of Buy or Sell signals are convenient when working with manual or semi-automated trading Expert Advisors, or when using indicators, including simple ones and those available as part of a trading strategy.
Now let us create the CSoundsLib class and add the methods required for work.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CSoundsLib { private: LANGUAGE m_language; bool m_activity_status; public: CSoundsLib(void); ~CSoundsLib(void); //--- Set the notification language void Language(LANGUAGE lang); //--- Set/get the status of the voice alerts system void IsActive(bool flag); bool IsActive(void); //--- Play the specified notification bool Message(MESSAGE msg); };
The private section has two alerts, m_language and m_activity_status, which are required for the following Language() and IsActive() methods. So, they are used to set the language of voice alerts and to get/set the system activity status. Here is the implementation of the above alerts:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CSoundsLib::Language(LANGUAGE lang) { m_language=lang; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSoundsLib::IsActive(void) { return(m_activity_status); }
Another method is Message(). It plays a notification selected from the MESSAGE enumeration. The implementation of this method is also easy to understand:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSoundsLib::Message(MESSAGE msg) { if(!m_activity_status) return(false); string name=(m_language==RUSSIAN ? EnumToString(msg)+"_RU" : EnumToString(msg)+"_EN"); if(PlaySound("\\Files\\SoundsLib\\"+name+".wav")) return(true); else { if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian") Print("Файл не найден"); else Print("File not found"); return(false); } }
Please pay attention to the following important points — they will help you to correctly expand the system further by adding your own voice notifications. First point is the correct place to save audio files: by default they are located in the MQL5/Files/SoundsLib folder. You should create the SoundsLib folder. Second, make sure to set proper names and audio file formats in the created folder. Pay attention to these code lines: the _RU or _EN suffix is appended to MESSAGE type enumeration here. That is why, the file name corresponding, for example, to a Buy signal alert SIGNAL_BUY will relate to two audio files, SIGNAL_BUY _RU and SIGNAL_BUY_EN, for Russian and English voice alert. Also, don't forget that the system function PlaySound() can only play a file in *.WAV format, and therefore the full file names with extensions in the folder SoundsLib will look like this:
Fig.1 Full name and extension of the audio file.
Therefore, we have 48 audio files for our set of 24 events in the MESSAGE enumeration: two files in different languages for each event. Next, I will show my own method for creating voice alerts. Nevertheless, you can use any preferable method. For this article, I used a free service for converting text to speech.
Fig.2 Service for converting text to speech.
This service provides good functionality for implementing the required task. It allows selecting the language, as well as types with the required format. However, WAV format is not supported for the English language. Here we can use any online converter or any other software to convert mp3 to wav. I have prepared all the required files for the system and saved them to folder MQL5\Files\SoundsLib with the correct format and names according to the MESSAGE enumeration and language suffixes. Here is my resulting list:
Fig.3 Complete list of audio files for voice alerts.
Below is a step-by-step guide on how to create your own voice notifications.
Step 1. Add your voice event to the system.
Open the file SoundsLib.mqh and find the MESSAGE enumeration. Add to it your event with a meaningful name. Naming examples are shown in Figure 3 and in the above code.
Step 2. Create an audio file for the voice alert.
Go to the service (you can use any service you like), configure the required parameters (shown in Figure 2) and save the file in WAV format under MQL5\Files\SoundsLib named "Your event name in MESSAGE enumeration"+_RU(_EN) depending on the language. If all steps are completed correctly, the new sound file will be linked to the new event, which was added in step 1, and thus it is ready to use.
Practical application in indicators
Now let us see how it works, using various examples. Let us create a composite indicator based on two indicator signals described in the table below:
Parameter | Description |
---|---|
Used indicator | ADXCloud |
Used indicator | ColorZerolagRVI |
Timeframe Choice | Any |
Buy conditions | The ADXCloud cloud is green, the ColorZerolagRVI cloud moves from red to the green zone. |
Sell conditions | The ADXCloud cloud is red, the ColorZerolagRVI cloud moves from green to red. |
Entry examples based on the indicator signals is shown in Figure 4, they are quite simple. We will use it as the basis for creating a composite signal indicator that shows market entry points as arrows on the chart.
Fig.4 Entry conditions by indicator signals.
//+------------------------------------------------------------------+ //| Example.mq5 | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "Alex2356" #property link "https://www.mql5.com/en/users/alex2356" #property version "1.00" #property indicator_chart_window //--- two buffers are used for calculating and drawing the indicator #property indicator_buffers 2 //--- used graphic constructions #property indicator_plots 2 #property indicator_label1 "Buy Signal" #property indicator_type1 DRAW_ARROW //--- #property indicator_label2 "Sell Signal" #property indicator_type2 DRAW_ARROW //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input group "ADX Cloud Parameters" input int ADXPeriod = 8; input double Alpha1 = 0.25; input double Alpha2 = 0.25; input group "RVI Color Parameters" input uint Smoothing = 15; //---- input double Weight1 = 0.05; input int RVI_period1 = 8; //---- input double Weight2 = 0.10; input int RVI_period2 = 21; //---- input double Weight3 = 0.16; input int RVI_period3 = 34; //---- input double Weight4 = 0.26; input int RVI_period4 = 55; //---- input double Weight5 = 0.43; input int RVI_period5 = 89; //--- double BuySignal[],SellSignal[],ADXCloud[],FastRVI[],SlowRVI[]; int ADX_Handle,RVI_Hadnle,min_rates_total; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- SetIndexBuffer(0,BuySignal,INDICATOR_DATA); SetIndexBuffer(1,SellSignal,INDICATOR_DATA); //--- PlotIndexSetInteger(0,PLOT_ARROW,233); PlotIndexSetInteger(1,PLOT_ARROW,234); //--- PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrDodgerBlue); PlotIndexSetInteger(1,PLOT_LINE_COLOR,clrCrimson); //--- ArraySetAsSeries(SellSignal,true); ArraySetAsSeries(BuySignal,true); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetInteger(0,PLOT_ARROW_SHIFT,20); PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,-20); //--- ADX_Handle=iCustom(Symbol(),PERIOD_CURRENT,"adxcloud",ADXPeriod,Alpha1,Alpha2); if(ADX_Handle==INVALID_HANDLE) { Print(" Failed to create indicator handle"); return(INIT_FAILED); } //--- RVI_Hadnle=iCustom(Symbol(),PERIOD_CURRENT,"colorzerolagrvi", Smoothing, Weight1,RVI_period1, Weight2,RVI_period2, Weight3,RVI_period3, Weight4,RVI_period4, Weight5,RVI_period5 ); if(RVI_Hadnle==INVALID_HANDLE) { Print(" Failed to create indicator handle"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- c if(BarsCalculated(ADX_Handle)<rates_total || BarsCalculated(RVI_Hadnle)<rates_total || rates_total<min_rates_total) return(0); //--- int limit,to_copy,i; //--- ArraySetAsSeries(ADXCloud,true); ArraySetAsSeries(FastRVI,true); ArraySetAsSeries(SlowRVI,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); //--- if(prev_calculated>rates_total || prev_calculated<=0) limit=rates_total-2; else limit=rates_total-prev_calculated; to_copy=limit+2; //--- if(CopyBuffer(ADX_Handle,0,0,to_copy,ADXCloud)<=0) return(0); //--- if(CopyBuffer(RVI_Hadnle,0,0,to_copy,FastRVI)<=0) return(0); if(CopyBuffer(RVI_Hadnle,1,0,to_copy,SlowRVI)<=0) return(0); //--- for(i=limit-1; i>=0 && !IsStopped(); i--) { if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2]) { BuySignal[i]=low[i]; SellSignal[i]=EMPTY_VALUE; } else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2]) { SellSignal[i]=high[i]; BuySignal[i]=EMPTY_VALUE; } else { BuySignal[i]=EMPTY_VALUE; SellSignal[i]=EMPTY_VALUE; } } //--- return value of prev_calculated for the next call return(rates_total); } //+------------------------------------------------------------------+
The resulting implementation is show in Figure 5. Now we need to implement the system of voice notifications.
Fig.5 An arrow indicator based on two indicators.
First, connect file SoundsLib.mqh to the indicator:
#include <SoundsLib/SoundsLib.mqh>
Create an instance of a voice notifications class:
CSoundsLib Notify;
In OnInit() initialization function, set the notification language. Here, I will set English. Actually, English is set by default so there is no need to additionally set it. So, here we do it for demonstration purposes.
Notify.Language(ENGLISH);
Since the arrow indicator shows only market entry points or buy/sell signals, we will use two voice notifications from the MESSAGE enumeration:
SIGNAL_BUY, // A Buy signal SIGNAL_SELL, // A Sell signal
When we embed the notification system into an indicator, alerts should not be generated in the entire history, but only on the current bar. So, modify the signal search loop as follows:
//--- for(i=limit-1; i>=0 && !IsStopped(); i--) { if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2]) { BuySignal[i]=low[i]; SellSignal[i]=EMPTY_VALUE; if(i==0) Notify.Message(SIGNAL_BUY); } else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2]) { SellSignal[i]=high[i]; BuySignal[i]=EMPTY_VALUE; if(i==0) Notify.Message(SIGNAL_SELL); } else { BuySignal[i]=EMPTY_VALUE; SellSignal[i]=EMPTY_VALUE; } }
Here we check if there is a signal on the zero bar, if there is, then notify the terminal user.
Practical application in trading Expert Advisors
Generally, two types of voice alerts are enough for indicators. Additionally, you can implement alerts to notify about the value entering the overbought zone for oscillators, about channel breakouts for Bollinger Bands, and so on. Much more alerts can be used in Expert Advisors. So, let us create a testing trading robot which will notify not only about a market entry signal, but will also comment further actions, for example which position type is opened. First, let us define the market entry strategy for the Expert Advisor.
Parameter | Description |
---|---|
Used indicator | ColorStDev |
Used indicator | Three Tirone levels |
Timeframe Choice | Any |
Buy conditions | The ColorStdDev histogram is red (strong trend), while the current price should be higher than the upper Tirone level. |
Sell conditions | The ColorStdDev histogram is red (strong trend), while the current price should be below the lower Tirone level. |
Exit Conditions | Take Profit/Stop Loss |
Market entry points are visually displayed as is shows in Figure 6.
Fig. 6 Examples of market entries in this strategy.
Now, let's implement the strategy for MetaTrader 5. Voice alerts will be used for some events.
//+------------------------------------------------------------------+ //| VoiceNotify.mq5 | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "Alex2356" #property link "https://www.mql5.com/en/users/alex2356" #property version "1.00" #include <SoundsLib/SoundsLib.mqh> #include <DoEasy25/Engine.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input uint InpStopLoss = 150; // Stop Loss, in pips input uint InpTakeProfit = 250; // Take Profit, in pips input double InpLot = 0.1; // Take Profit, in pips input ulong InpDeviation = 10; // Deviation input int InpMagic = 2356; // Magic number input LANGUAGE NotifyLanguage = ENGLISH; // Notification Language //--- ColorStDev indicator parameters input int StDevPeriod = 12; // Smoothing period StDev input ENUM_MA_METHOD MA_Method = MODE_EMA; // Histogram smoothing method input ENUM_APPLIED_PRICE applied_price = PRICE_CLOSE; // Applied price input int MaxTrendLevel = 90; // Maximum trend level input int MiddLeTrendLevel = 50; // Middle trend level input int FlatLevel = 20; // Flat level //--- Tirone Levels indicator parameters input int TironePeriod = 13; // Tirone Period //--- CEngine trade; CSoundsLib notify; int Handle1,Handle2; double stdev[],tirone_b[],tirone_s[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) notify.Message(AUTO_TRADING_OFF); //--- OnInitTrading(); //--- Get the handle of the ColorStDev indicator Handle1=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\colorstddev", StDevPeriod, MA_Method, applied_price, MaxTrendLevel, MiddLeTrendLevel, FlatLevel ); if(Handle1==INVALID_HANDLE) { Print("Failed to get colorstddev handle"); Print("Handle = ",Handle1," error = ",GetLastError()); return(INIT_FAILED); } //--- Getting the handle of the Tirone Levels indicator Handle2=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\tirone_levels_x3",TironePeriod,0); if(Handle2==INVALID_HANDLE) { Print("Failed to get Tirone Levels handle"); Print("Handle = ",Handle2," error = ",GetLastError()); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If there are no market positions if(ExistPositions(Symbol(),-1,InpMagic)<1) { //--- Getting data for calculations if(!GetIndValue()) return; //--- Open an order if there is a buy signal if(BuySignal()) { notify.Message(SIGNAL_BUY); if(trade.OpenBuy(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit)) { Sleep(1400); notify.Message(BUY_ORDER_SET); } } //--- Opening an order if there is a sell signal if(SellSignal()) { notify.Message(SIGNAL_SELL); if(trade.OpenSell(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit)) { Sleep(1400); notify.Message(SELL_ORDER_SET); } } } } //+------------------------------------------------------------------+ //| Buy conditions | //+------------------------------------------------------------------+ bool BuySignal() { return(tirone_b[1]>iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false; } //+------------------------------------------------------------------+ //| Sell conditions | //+------------------------------------------------------------------+ bool SellSignal() { return(tirone_b[1]<iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false; } //+------------------------------------------------------------------+ //| Getting the current values of indicators | //+------------------------------------------------------------------+ bool GetIndValue() { return(CopyBuffer(Handle1,0,0,2,stdev)<=0 || CopyBuffer(Handle2,0,0,2,tirone_b)<=0 || CopyBuffer(Handle2,2,0,2,tirone_s)<=0 )?false:true; } //+----------------------------------------------------------------------------+ //| Returns the number of open orders | //+----------------------------------------------------------------------------+ //| Parameters: | //| op - operation (-1 - any position) | //| mn - MagicNumber (-1 - any magic number) | //+----------------------------------------------------------------------------+ int ExistPositions(string sy,int op=-1,int mn=-1) { int pos=0; uint total=PositionsTotal(); //--- for(uint i=0; i<total; i++) { if(SelectByIndex(i)) if(PositionGetString(POSITION_SYMBOL)==sy) if(op<0 || PositionGetInteger(POSITION_TYPE)==op) if(mn<0 || PositionGetInteger(POSITION_MAGIC)==mn) pos++; } return(pos); } //+------------------------------------------------------------------+ //| Select a position on the index | //+------------------------------------------------------------------+ bool SelectByIndex(const int index) { ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); //--- if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { ulong ticket=PositionGetTicket(index); if(ticket==0) return(false); } else { string name=PositionGetSymbol(index); if(name=="") return(false); } //--- return(true); } //+------------------------------------------------------------------+ //| Trading Environment Initialization | //+------------------------------------------------------------------+ void OnInitTrading() { string array_used_symbols[]; //--- Fill in the array of used symbols CreateUsedSymbolsArray(SYMBOLS_MODE_CURRENT,"",array_used_symbols); //--- Set the type of the used symbol list in the symbol collection and fill in the list of symbol timeseries trade.SetUsedSymbols(array_used_symbols); //--- Pass all existing collections to the trading class trade.TradingOnInit(); trade.TradingSetMagic(InpMagic); trade.TradingSetLogLevel(LOG_LEVEL_ERROR_MSG); //--- Set synchronous passing of orders for all used symbols trade.TradingSetAsyncMode(false); //--- Set correct order expiration and filling types to all trading objects trade.TradingSetCorrectTypeExpiration(); trade.TradingSetCorrectTypeFilling(); } //+------------------------------------------------------------------+
Let us consider this code in more detail in terms of the usage of voice alerts. The trading robot initialization function contains a check of whether trading systems are allowed to trade in the terminal. If this option is disabled, an appropriate voice alert will be played to notify the user. Then, in the OnTick() function, if the desired trading signal is found, the EA will notify that the desired Buy or Sell signal is found. An attempt is made to open a position according to the signal. If successful, another voice alert is played to notify the user that a position has been placed.
These notifications are much more efficient, because the user may miss a text alert in Experts tab in the terminal. As for standard sound alerts, the meaning of the sound is not always clear, they can be different in indicators and Expert Advisors. Voice notifications provide the exact information and thus they are much more convenient.
Practical application in Quick Trading Tools
In my previous articles, I developed a toolkit for manual traders, which independently search for market entries, manually place orders, manage positions and close them. For demonstration purposes, I would like to add a system of voice notification to this toolkit. This will also show that the voice alert functionality can be easily added to any tool. As the basis, I will use an attachment from this article. First, let us define a list of actions and events for which we will add voice alerts.
- Successful opening of a buy or sell position.
- Successful placing of pending orders and deletion.
- Checking if an order can be placed using an Expert Advisor.
Before we start integrating voice notifications, let us connect the relevant library to this project. Open Program.mqh and add the following at the very beginning.
//+------------------------------------------------------------------+ //| Program.mqh | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356/ | //+------------------------------------------------------------------+ #include <EasyAndFastGUI\WndEvents.mqh> #include <DoEasy25\Engine.mqh> #include "Defines.mqh" #include <SoundsLib/SoundsLib.mqh>
Go to the private section of the CFastTrading class and create a CSoundsLib class instance variable.
//---
CSoundsLib m_notify;
Also, set two new parameters in the toolkit, which will allow enabling/disabling notifications and selecting the language. Open SimpleTrading.mq5 and add new parameters in the EA's Input Parameters section:
//+------------------------------------------------------------------+ //| Expert Advisor input parameters | //+------------------------------------------------------------------+ input int Inp_BaseFont = 10; // Base FontSize input color Caption = C'0,130,225'; // Caption Color input color Background = clrWhite; // Back color input LANG Language = ENGLISH; // Interface language input ulong MagicNumber = 1111; // Magic Number //--- input bool UseVoiceNotify = true; // Use Voice Notify input LANGUAGE NotifyLanguage = ENGLISH; // Notification Language
To pass them to the CSoundsLib class instance m_notify, create two methods in the public section of the CFastTrading base class, and implement them:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::SetNotifyLanguage(LANGUAGE lang) { m_notify.Language(lang); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::UseVoiceNotify(bool state) { m_notify.IsActive(state); } //+------------------------------------------------------------------+
Now, implement them in the OnInit() function in SimpleTrading.mq5 and pass input parameters to the newly created methods.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- Initialize class variables program.FontName("Trebuchet MS"); program.FontSize(Inp_BaseFont); program.BackgroundColor(Background); program.CaptionColor(Caption); program.SetLanguage(Language); program.SetMagicNumber(MagicNumber); program.UseVoiceNotify(UseVoiceNotify); program.SetNotifyLanguage(NotifyLanguage); //--- Set up the trading panel if(!program.CreateGUI()) { Print(__FUNCTION__," > Failed to create graphical interface!"); return(INIT_FAILED); } program.OnInitEvent(); //--- return(INIT_SUCCEEDED); }
Thus, we have set up the main input parameters of the voice notification system. Now, find methods setting Buy and Sell market positions. These are methods SetBuyOrder() and SetSellOrder() in the CFastTrading base class. Open the body of the method placing Buy orders and find the part where a check is performed if the position was opened successfully. Add there the appropriate voice alert BUY_ORDER_SET:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::SetBuyOrder(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buy_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_B)) { //--- double lot; if(m_switch_button[0].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[0].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[0].GetValue())); if(m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[0].GetValue()); double sl=double(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(!m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[0].GetValue()); int sl=int(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[0].GetValue()); int sl=int(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(!m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[0].GetValue()); double sl=double(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } } return(false); }
Make the same changes for methods opening sell positions. The voice alert to be used is SELL_ORDER_SET:
bool CFastTrading::SetSellOrder(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_sell_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_S)) { //--- double lot; if(m_switch_button[3].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[1].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[1].GetValue())); //--- if(m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed()) { double tp=double(m_tp_edit[1].GetValue()); double sl=double(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(!m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed()) { int tp=int(m_tp_edit[1].GetValue()); int sl=int(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(!m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed()) { int tp=int(m_tp_edit[1].GetValue()); double sl=double(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed()) { double tp=double(m_tp_edit[1].GetValue()); int sl=int(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } } return(false); }
Now, let's move on to pending orders. The toolkit supports four types, each has a separate method:
bool SetBuyStopOrder(int id,long lparam); bool SetSellStopOrder(int id,long lparam); bool SetBuyLimitOrder(int id,long lparam); bool SetSellLimitOrder(int id,long lparam);
A separate voice notification should be set for each of them. Here is an example of a BuyStop orders, others are set up in a similar way. As can be seen from the below code, the BUYSTOP_ORDER_SET notification is used.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::SetBuyStopOrder(int id,long lparam) { if(!m_orders_windows[1].IsVisible()) return(false); if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buystop_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_1)) { //--- double lot; if(m_p_switch_button[0].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[2].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[2].GetValue())); //--- double pr=double(m_pr_edit[0].GetValue()); //--- if(m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[2].GetValue()); double sl=double(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(!m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[2].GetValue()); int sl=int(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[2].GetValue()); int sl=int(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(!m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[2].GetValue()); double sl=double(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } } return(false); }
Now, when notifications for placed pending orders are ready, we need to add notifications for the deletion of earlier placed orders. The RemoveOrder() method determines which of the pending orders in the table is selected. The selected order can then be modified or deleted. Here, an order is deleted by clicking on the Delete button.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::RemoveOrder(long lparam) { //--- Check the element ID if(lparam==m_small_button[3].Id()) { //--- Get index and symbol if(m_table_orders.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_orders.SelectedItem(); ulong ticket=(ulong)m_table_orders.GetValue(0,row); //--- if(OrderSelect(ticket)) { string position_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // order MagicNumber ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); // order type if(type==ORDER_TYPE_BUY_STOP) m_notify.Message(BUYSTOP_ORDER_DELETE); else if(type==ORDER_TYPE_SELL_STOP) m_notify.Message(SELLSTOP_ORDER_DELETE); else if(type==ORDER_TYPE_BUY_LIMIT) m_notify.Message(BUYLIMIT_ORDER_DELETE); else if(type==ORDER_TYPE_SELL_LIMIT) m_notify.Message(SELLLIMIT_ORDER_DELETE); //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action=TRADE_ACTION_REMOVE; // trading operation type request.order = ticket; // order ticket //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); }
Let us consider the modification of the method body in more detail. Once the ticket of the selected order is determined, we receive data required to place a request to delete the order by filling the MqlTradeRequest structure and calling the OrderSend() method. To type of the pending order selected in the tables is determined based on the type variable. Based on the variable value, set the appropriate voice notification in the Message() method.
The last task to implement is to add a voice notification if automated trading is disabled in the MetaTrader 5 terminal. The toolkit is actually an Expert Advisor: although users place orders manually, the terminal and the broker recognize them as automated trading. To add a check if automated trading, go to the base class, find OnEvent() handler -> ON_END_CREATE_GUI section and add a check with the appropriate voice notification:
// --- GUI creation completion if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI) { //--- SetButtonParam(m_switch_button[0],LOT); SetButtonParam(m_switch_button[1],POINTS); SetButtonParam(m_switch_button[2],POINTS); SetButtonParam(m_switch_button[3],LOT); SetButtonParam(m_switch_button[4],POINTS); SetButtonParam(m_switch_button[5],POINTS); //--- SetButtonParam(m_p_switch_button[0],LOT); SetButtonParam(m_p_switch_button[1],POINTS); SetButtonParam(m_p_switch_button[2],POINTS); SetButtonParam(m_p_switch_button[3],LOT); SetButtonParam(m_p_switch_button[4],POINTS); SetButtonParam(m_p_switch_button[5],POINTS); SetButtonParam(m_p_switch_button[6],LOT); SetButtonParam(m_p_switch_button[7],POINTS); SetButtonParam(m_p_switch_button[8],POINTS); SetButtonParam(m_p_switch_button[9],LOT); SetButtonParam(m_p_switch_button[10],POINTS); SetButtonParam(m_p_switch_button[11],POINTS); //--- if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) m_notify.Message(AUTO_TRADING_OFF); }
The below video shows how voice notifications work in the quick trading toolkit, in which alerts are used for market positions and pending orders.
Conclusion
The attached archive contains all the listed files, which are located in the appropriate folders. For their proper operation, you only need to save the MQL5 folder into the terminal folder. To open the terminal root directory, in which the MQL5 folder is located, press the Ctrl+Shift+D key combination in the MetaTrader 5 terminal or use the context menu as shown in Fig. 7 below.
Fig. 7. Opening the MQL5 folder in the MetaTrader 5 terminal root
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/8111





- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hi Alexander,
Thanks for sharing your EA and the article regarding Voice Notify System for MT5. No error on the compiling of the EA but got error on the Journal and Expert adviser tab. Please see error attached:
Journal tab:
Expert tab:
Please help how to isolate order filling type and I'm new user for MT5. Thanks for your response in advance.
Hello do you have mt4 version for this..