Sistema de notificações de voz de eventos e sinais de negociação
Sumário
- Introdução
- Desenvolvendo o sistema de notificações de voz
- Aplicação prática em indicadores
- Aplicação prática em EAs
- Aplicação prática em ferramentas de negociação rápida
- Fim do artigo
Introdução
O terminal de negociação MetaTrader 5 possui um sistema para configurar notificações sonoras, que inclui 11 eventos para os quais podemos por um aviso de áudio. No entanto, ao usar o terminal, existem muitas outras situações em que seria útil receber informações sonoras, como o aparecimento de um sinal de um sistema de negociação ou informações de que uma posição colocada é aberta, fechada ou alterada por um Expert Advisor ativo. Hoje em dia, os assistentes de voz ocupam um papel proeminente na vida humana, seja um navegador, um mecanismo de busca por voz ou um tradutor. Por isso, essa ideia pode ser usada ao negociar por meio do terminal MetaTrader 5. Neste artigo, tentarei desenvolver um sistema simples e compreensível de notificações de voz para diferentes eventos, condições de mercado ou sinais de sistemas de negociação.
Desenvolvendo o sistema de notificações de voz
Antes de embarcarmos na criação do sistema, gostaria de ressaltar o fato de que os eventos que escolhi para a implementação de notificações de voz são apenas um conjunto padrão para demonstração. Por esse motivo, para aqueles para quem não for suficiente, o sistema permitirá adicionar eventos e notificações de voz próprios. Mesmo para pessoas com conhecimento modesto de MQL5, será simples de entender como estender o sistema de acordo com suas necessidades.
O sistema é implementado como uma classe CSoundsLib no arquivo de inclusão. Portanto, na pasta MQL5/Include vamos criar a pasta SoundsLib e nesta, o arquivo SoundsLib.mqh. Antes de criar a classe, apresentaremos duas enumerações que serão necessárias posteriormente ao trabalhar com notificações de voz. A primeira delas é LANGUAGE, usada para selecionar o idioma de notificação. No sistema, serão dois idiomas, russo e inglês.
//+------------------------------------------------------------------+ //| Enumeration for switching the notification language | //+------------------------------------------------------------------+ enum LANGUAGE { RUSSIAN, // Russian ENGLISH // English };
A segunda enumeração conterá o conjunto de eventos que escolhi como demonstração e, mais adiante no artigo, será mostrado como integrá-los em sistemas prontos de diferentes tipos, desde indicadores e EAs a aplicativos como ferramentas de negociação rápida. Assim, a enumeração será chamada de 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 };
O conjunto básico contém 24 notificações. A maioria deles é associado ao trabalho e estado de posições abertas ou ordens pendentes. E também estão presentes aqueles que irão dar som ao ambiente de negociação. Já os três últimos são comuns. A notificação do status do sistema de notificação de voz habilitado, bem como as mensagens sobre a presença de um sinal de compra ou venda são úteis ao trabalhar com sistemas manuais ou semiautomáticos de EAs ou com diferentes sinais vindos de indicadores, tanto simples quanto como parte de uma estratégia de negociação.
Agora criamos a classe CSoundsLib, escrevemos nela os métodos necessários para trabalharmos.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); };
Na seção privada estão m_language e m_activity_status. Elas são duas variáveis necessárias para os métodos Language() e IsActive() criados abaixo. Estes são usados para definir o idioma das notificações por voz e receber/definir a atividade do próprio sistema. Sua implementação é mostrada na listagem abaixo:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CSoundsLib::Language(LANGUAGE lang) { m_language=lang; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSoundsLib::IsActive(void) { return(m_activity_status); }
Outro método é Message() que reproduz a própria notificação, definida a partir da enumeração MESSAGE. A implementação deste método também é fácil de entender:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); } }
Gostaria de ressaltar vários pontos importantes, pois entendê-los afetará diretamente o quão exato resulte expandir este sistema usando suas próprias notificações de voz. O primeiro é o local correto para a instalação dos arquivos de som, ou seja, por padrão eles devem estar na pasta MQL5/Files/SoundsLib. Além disso, devemos criar a pasta SoundsLib. O segundo é os nomes e o formato dos arquivos de som que serão colocados na pasta criada. Vejamos que essas linhas de código adicionam o sufixo _RU ou _EN à sua enumeração MESSAGE no final. Por isso, o nome do arquivo em questão, por exemplo, para a notificação de voz sobre o sinal de compra SIGNAL_BUY, será associado a dois arquivos de som: SIGNAL_BUY _RU e SIGNAL_BUY_EN para sonorização em russo e inglês. Além disso, devemos nos lembrar de que a função do sistema PlaySound() só pode reproduzir um arquivo no formato *.WAV e, portanto, os nomes completos dos arquivos em nosso exemplo com extensões na pasta SoundsLib vai ficar assim:
Fig.1 Nome completo e extensão do arquivo de som.
Portanto, os 24 eventos definidos na enumeração MESSAGE corresponderão a 48 arquivos de som. 2 para cada evento em dois idiomas. A seguir, mostrarei minha própria maneira de criar notificações de voz, mas todos são livres para usar a que mais gosta. Para o artigo, usei o serviço gratuito de conversão de mensagens de texto em arquivos de som.
Fig. 2 Serviço de conversão de texto em arquivo de som.
Essa ferramenta possui funcionalidade suficiente para realizar a tarefa requerida. Pode-se escolher o idioma do mecanismo de voz e os tipos com o formato de que precisamos. No entanto, não há formato WAV para o mecanismo de voz em inglês, portanto, por meio de um conversor online ou de um software para trabalhar com arquivos de som, você pode converter facilmente o formato mp3 para wav. Com este serviço, iremos receber todos os arquivos necessários para o nosso sistema e colocá-los numa pasta emMQL5\Files\SoundsLib com o formato e nomes corretos de acordo com a enumeração MESSAGE e sufixos de idioma. Aqui está a lista que obtive:
Fig. 3 Lista completa de arquivos de som para notificações de voz.
Para uma compreensão mais clara, a seguir darei um guia passo a passo sobre como criar notificações de voz próprias.
Passo 1. Adicionando seu evento de voz ao sistema.
Para fazer isso, vamos para o arquivo SoundsLib.mqh e encontramos a enumeração MESSAGE. Devemos adicionar seu evento com um nome significativo. Um exemplo de nomes é mostrado na Fig. 3 e acima no código.
Passo 2. Criando o arquivo de som da futura notificação de voz.
Vamos para o serviço (ou o que você quiser) e personalizamos os parâmetros desejados (mostrados na Fig. 2) e salvamos o arquivo em formato WAV na pasta MQL5\Files\SoundsLib com o nome "O nome do seu evento na enumeração MESSAGE"+_ RU(_EN) dependendo de se pertence ao idioma russo ou inglês. Se você fez tudo corretamente, o novo arquivo de som será associado ao novo evento adicionado por você no passo 1, e estará pronto para ser usado.
Aplicação prática em indicadores
Agora vamos ver como isso funciona através de vários exemplos. Vamos criar um indicador composto com base nos dois sinais indicadores descritos na tabela abaixo:
Parâmetros | Descrição |
---|---|
Indicador utilizado | ADXCloud |
Indicador utilizado | ColorZerolagRVI |
Timeframe | Qualquer um |
Condições de compra | ADXCloud é verde, ColorZerolagRVI muda de vermelho para verde. |
Condições de venda | ADXCloud é vermelho, ColorZerolagRVI muda de verde para vermelho. |
Na Fig. 4 são mostrados exemplos de entrada com base nos dois sinais desses indicadores. Embora sejam bastante simples, faremos com eles um indicador de sinal composto que mostrará no gráfico usando setas os pontos de entrada no mercado.
Fig.4 Condições de entrada com base nos sinais desses indicadores.
//+------------------------------------------------------------------+ //| 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 get the 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 get the 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); } //+------------------------------------------------------------------+
Como resultado teremos a implementação mostrada na Fig. 5, e agora temos que implementar um sistema de notificação de voz.
Fig.5 Indicador de seta baseado em dois indicadores.
Primeiro, vamos anexar o arquivo SoundsLib.mqh ao indicador:
#include <SoundsLib/SoundsLib.mqh>
Criamos uma instância da classe do sistema de notificação por voz:
CSoundsLib Notify;
Na função de inicialização OnInit() definimos o idioma das notificações de voz, vou colocar em inglês. Embora, se você usar o inglês para as notificações, podemos dispensar a instalação do idioma, uma vez que é definido por padrão, mas, para entender melhor isto, iremos instalá-lo.
Notify.Language(ENGLISH);
Como o indicador de seta mostra apenas pontos de entrada no mercado ou sinais de compra/venda, a partir da lista de MESSAGE usaremos estas duas notificações de voz:
SIGNAL_BUY, // A Buy signal SIGNAL_SELL, // A Sell signal
No entanto, ao introduzir notificações de voz no indicador criado, é necessário que elas não venham com base em todos os sinais do histórico, mas apenas para a barra atual, portanto, modificamos o ciclo de busca de sinal da seguinte forma:
//--- 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; } }
Aqui nós verificamos se há um sinal na barra zero e, se estiver presente, notificamos o usuário do terminal sobre isso.
Aplicação prática em EAs
Para o indicador, a integração de notificações por voz é limitada a apenas dois tipos, embora nada impeça você de adicionar suas próprias, por exemplo, para osciladores, uma notificação sobre a entrada na zona de sobrecompra, quebra de canal para bandas de Bollinger, etc. O Expert Advisor pode usar muitas mais notificações diferentes a partir do conjunto combinável. Por isso, criaremos um robô de negociação de teste que avisará não só que encontrou um sinal para entrar no mercado, mas também comentará sobre suas ações futuras, por exemplo, acerca de com que tipo de posição entrará no mercado. Primeiro, vamos definir a estratégia de entrada do futuro Expert Advisor.
Parâmetros | Descrição |
---|---|
Indicador utilizado | ColorStDev |
Indicador utilizado | Três nível Tirone |
Timeframe | Qualquer um |
Condições de compra | O histograma ColorStdDev é vermelho (tendência forte), enquanto o preço atual deve estar acima do nível superior de Tirone. |
Condições de venda | O histograma ColorStdDev é vermelho (tendência forte), enquanto o preço atual deve estar abaixo do nível inferior de Tirone. |
Condições de saída | Take-Profit/Stop-Loss |
Visualmente, os pontos de entrada no mercado serão parecidos com a Fig. 6 dada como exemplo.
Fig. 6 Exemplos de entrada no mercado usando esta estratégia.
Agora vamos implementar essa estratégia no MetaTrader 5, e usaremos notificações de voz para alguns eventos.
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Vamos considerar esta lista com mais detalhes a nível de uso de notificações. Na inicialização do robô de negociação, foi utilizada uma verificação de se era permitida a negociação usando sistemas automáticos no terminal. Se esta opção for desativada, o usuário será avisado pela notificação de voz correspondente. Em seguida, na função OnTick() quando é encontrado um determinado sinal de negociação, o Expert Advisor avisa que foi encontrado um sinal de compra ou venda, respectivamente. Ocorre a tentativa de colocar uma posição de acordo com o sinal e, se tudo correr bem, outra notificação de voz avisará que ela foi posicionada no mercado.
Essas notificações são muito mais eficazes a nível de entrega de informações ao usuário do terminal, porque nem sempre é possível ver atempadamente a notificação de texto necessária de um EA na guia Experts ou em outro local. Quanto aos alertas, os sons que vem com a plataforma podem ser diferentes para diferentes indicadores e EAs. Quanto às notificações por voz, tudo é claro e simples de compreender, pois o evento necessário é entregue por fala.
Aplicação prática em ferramentas de negociação rápida
Nos meus dois artigos anteriores, desenvolvi uma ferramenta para traders que negociam manualmente, ou seja, que procuram sinais para entrar no mercado, definem ordens, acompanham e fecham. Como exemplo, no âmbito deste artigo, gostaria de complementar esse aplicativo com um sistema de notificação de voz. E, assim, mostrar que não será difícil adicioná-lo a uma ferramenta deste tipo. Vou tomar como base o projeto anexado no final deste artigo. Primeiro, vamos definir uma lista de ações e eventos para as quais serão incorporadas notificações de voz.
- Abertura bem-sucedida de uma posição de compra ou venda.
- Colocação bem-sucedida de ordens pendentes e sua remoção.
- Verificação de se é possível fazer ordens através de um EA.
Antes de começar a integrar notificações de voz, vamos anexar a biblioteca a este projeto. Para fazer isso, abrimos o arquivo Program.mqh e no começo vamos fazer isso.
//+------------------------------------------------------------------+ //| 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>
Agora vamos para a seção privada da classe CFastTrading e criamos uma variável-instância da classe CSoundsLib.
//---
CSoundsLib m_notify;
Também precisamos definir dois novos parâmetros na própria caixa de ferramentas para habilitar/desabilitar notificações de voz e selecionar idioma. Vamos para SimpleTrading.mq5 e na seção Parâmetros de Entrada do EA iremos escrever novos:
//+------------------------------------------------------------------+ //| 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
E para passá-los para uma instância da classe CSoundsLib m_notify na seção pública da classe base CFastTrading, vamos criar dois métodos e implementá-los:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::SetNotifyLanguage(LANGUAGE lang) { m_notify.Language(lang); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::UseVoiceNotify(bool state) { m_notify.IsActive(state); } //+------------------------------------------------------------------+
Agora vamos aplicá-los na função OnInit() do arquivo SimpleTrading.mq5 e passamos os parâmetros de entrada para os métodos que acabamos de criar.
//+------------------------------------------------------------------+ //| 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); }
Assim, configuramos os principais parâmetros de entrada do sistema de notificação de voz. Agora encontramos métodos para definir posições de compra e venda a mercado. Na classe base CFastTrading, eles são SetBuyOrder() e SetSellOrder(). Vamos para o corpo do método para colocar uma posição de compra e nos locais onde ocorre uma verificação de abertura bem-sucedida de posição, escreveremos a notificação de voz correspondente 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); }
Faremos a alteração análoga com o método de abertura de posições de venda, mas apenas com uma chamada de notificação de voz 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); }
Agora vamos prosseguir para as ordens pendentes. Existem quatro tipos na caixa de ferramentas, já para posicioná-las há um método para cada uma:
bool SetBuyStopOrder(int id,long lparam); bool SetSellStopOrder(int id,long lparam); bool SetBuyLimitOrder(int id,long lparam); bool SetSellLimitOrder(int id,long lparam);
Para cada uma, precisamos definir a notificação de voz correspondente. Vamos fazer isso usando o exemplo de uma ordem BuyStop, porque devemos fazer ações semelhantes com o resto. Como se pode ver na lista abaixo, é usada a notificação BUYSTOP_ORDER_SET.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); }
Se tivermos concluído a instalação de notificações de voz para fazer ordens pendentes, agora resta implementar notificações para excluir ordens feitas anteriormente. Para isso, vamos encontrar o método RemoveOrder(), que determina qual das ordens pendentes na tabela é selecionada, depois disso torna-se possível trabalhar com ela - editar ou excluir. Mas neste método, a ordem pendente é excluída clicando no botão excluir.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); }
Vamos considerar a alteração do corpo do método com mais detalhes. Após determinar o ticket da ordem selecionada, recebemos os dados necessários para fazer uma solicitação de exclusão, preenchendo a estrutura MqlTradeRequest e chamando o métodoOrderSend(). Para entender que tipo de ordem pendente foi selecionada na tabela, usamos o valor da variável type. Com base em seu valor, atribuímos tipo apropriado de notificação de voz ao o método Message().
E a última coisa que resta de nossa tarefa principal é avisar por voz se o modo de negociação automática está desativado no terminal MetaTrader 5. Visto que o conjunto de ferramentas é, na verdade, um EA e, embora as ordens sejam colocadas por ele apenas com base em ações do usuário, ou seja, manualmente, o terminal e a corretora os reconhecem como negociação automática. Para adicionar a verificação de permissão, precisamos, na classe base do aplicativo, irmos para o manipulador de eventos OnEvent() na seção ON_END_CREATE_GUI e na parte inferior registrarmos uma verificação com atribuição de notificação de voz:
// --- 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); }
Em conclusão, usando como exemplo um conjunto de ferramentas de negociação rápida, o vídeo gravado a seguir mostra o funcionamento das notificações por voz ao trabalhar com posições a mercado e ordens pendentes.
Fim do artigo
No final do artigo é anexado um arquivo com todos os arquivos listados, classificados por pastas. Por isso, para um correto funcionamento, basta colocar a pasta MQL5 na raiz do terminal. E para encontrar a raiz do terminal onde está localizada a pasta MQL5, no MetaTrader 5 é necessário pressionar a combinação de teclas Ctrl+Shift+D ou usar o menu contextual, conforme mostrado na Figura 7 abaixo.
Fig. 7 Busca da pasta MQL5 na raiz do terminal MetaTrader 5
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/8111
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso