Notificações SMS do Status do EA
Introdução
O meu trabalho muitas vezes interfere com a minha capacidade de monitorar continuamente o terminal, pode ser apenas 20-30 minutos, mas pode muito bem ser um dia inteiro. Então decidi desenvolver um sistema que envia um SMS para notificar-me de qualquer situação crítica, a partir de um apagão até um problema com o meu computador. Estou certo de que o sistema, tal como previsto neste artigo, será útil para muitos traders ou servirá de base para aqueles que desejarem criar a sua própria 'obra-prima'.
Neste artigo demonstro o desenvolvimento de uma solução de trabalho para a tarefa específica. Como eu não tenho competência profissional de expert no desenvolvimento em Java, então eu pedi a um colega que é um desenvolvedor para me ajudar a depurar e corrigir meu código a fim de evitar falhas.
Plano
- Recursos do Google Calendar
- Algumas palavras sobre a instalação de APIs de dados do Google
- Fluxograma do sistema
- Código do aplicativo Java
- O código de arquivo .bat
- Código do Expert Advisor
- Deficiências
- Conclusão
Recursos do Google Calendar
No desenvolvimento do sistema de notificação SMS decidi a favor do Google Calendar, pois permite a criação de eventos no seu calendário de forma gratuita e você pode usar o SMS como meio de notificação de tal evento. Para esta finalidade, eu criei um perfil especial separado no Google.
Em poucas palavras, o princípio de funcionamento é o seguinte: se a mensagem atual não é excluída por volta das 09:59 (veja a imagem acima) ou se o terminal não se conectar com servidor do Google para iniciar a substituição do atual mensagem com uma diferente, então um SMS será enviado para o seu telefone com a notificação adequada.
Algumas palavras sobre a instalação de APIs de dados do Google
Para usar os serviços do Google no desenvolvimento de suas soluções de software, o Google fornece a documentação APIs de dados do Google.
Toda a documentação que um desenvolvedor Java necessita para trabalhar com o Google Calendar pode ser encontrada usando este link: APIs do Google Calendar e Ferramentas.
Para começar a programação, você terá que instalar a Google Data Java Client Library. Na mesma página, você encontra um link da documentação relacionada com a biblioteca para o Eclipse. Isto é o que eu usei e recomendo a você: Eclipse com APIs de dados do Google.
Fluxograma do sistema
Eu acho que eu deveria primeiro comentar sobre o fluxograma:
- O evento StopTXT é necessário para finalizar o fluxo de SMS manualmente ou remotamente.
- O evento ReanimationTXT é obrigado a informar que por alguma razão o terminal conseguiu ficar ligado após o SMS correspondente com um aviso ter sido enviado para você.
Código do aplicativo Java
Todos os códigos fonte e de distribuição estão anexados no final do artigo.
Pacote do Calendar; /* INSTRUÇÃO: Este é um aplicativo de linha de comando. Então, por favor execute este modelo com os seguintes argumentos: arg[0] = username arg[1] = password */ import com.google.gdata.client.GoogleService; import com.google.gdata.client.Query; import com.google.gdata.client.calendar.CalendarService; import com.google.gdata.data.DateTime; import com.google.gdata.data.PlainTextConstruct; import com.google.gdata.data.calendar.CalendarEntry; import com.google.gdata.data.calendar.CalendarEventEntry; import com.google.gdata.data.calendar.CalendarEventFeed; import com.google.gdata.data.calendar.CalendarFeed; import com.google.gdata.data.extensions.Reminder; import com.google.gdata.data.extensions.When; import com.google.gdata.data.extensions.Reminder.Method; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; public class Calendar { public static void main(String[] args) { try { //--- VARIÁVEIS EXTERNAS ---------------------------- String alertTxt = args[2]; String reanimationTxt = args[3]; String stopSMS = args[4]; int timePeriod = Integer.parseInt(args[5]); // Intervalo em minutos em que o terminal // será conectado int mode = Integer.parseInt(args[6]); int startHour = Integer.parseInt(args[7]); int startMin = Integer.parseInt(args[8]); //--------------------------------------------------- //--- VARIÁVEIS INTERNAS -------------------------- URL feedUrl = new URL("http://www.google.com/calendar/feeds/default/private/full"); //link para trabalhar com eventos URL calendarUrl = new URL("http://www.google.com/calendar/feeds/default/allcalendars/full"); //link para trabalhar com calendários //--------------------------------------------------- System.out.println(">>---------- Start ----------<<"); // Criar um novo serviço de calendário, conectar ao Google CalendarService myService = new CalendarService("My Application"); myService.setUserCredentials(args[0], args[1]); // LOGIN E SENHA COMO ARGUMENTOS // DECLARAR VARIÁVEIS PARA EVENTO DE PESQUISA Query myQuery = new Query(feedUrl); CalendarEventFeed myResultsFeed; CalendarEventEntry firstMatchEntry = null; String myEntryTitle; URL deleteUrl; When timeVar; SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Date newDate = new Date(); CalendarEventEntry myEntry; When eventTimes = new When(); DateTime startTime = null; DateTime endTime = null; int reminderMinutes; Method methodType = Method.SMS; Reminder reminder = new Reminder(); CalendarEventEntry insertedEntry; // PREPARAR CONSULTA DE PESQUISA myQuery.setFullTextQuery(stopSMS); // EVENTO DE TEXTO stopSMS myResultsFeed = myService.query(myQuery, CalendarEventFeed.class); if (myResultsFeed.getEntries().size() > 0) { System.out.println(">> STOP event found. \n>> Finish"); return; } // PREPARAR CONSULTA DE PESQUISA myQuery.setFullTextQuery(reanimationTxt); // EVENTO DE TEXTO reanimationTxt myResultsFeed = myService.query(myQuery, CalendarEventFeed.class); if (myResultsFeed.getEntries().size() > 0) { // SE ENCONTRADO System.out.println(">> REANIMATION event found"); // OBTER O TÍTULO DA PRIMEIRA ENTRADA CORRESPONDENTE firstMatchEntry = (CalendarEventEntry) myResultsFeed.getEntries().get(0); myEntryTitle = firstMatchEntry.getTitle().getPlainText(); // SE ENCONTRADO O EVENTO reanimationTxt, DELETE-O deleteUrl = new URL(firstMatchEntry.getEditLink().getHref()); myService.getRequestFactory().setHeader("If-Match", "*"); myService.delete(deleteUrl); System.out.println(">> ...deleting REANIMATION event"); } // PREPARAR CONSULTA DE PESQUISA myQuery.setFullTextQuery(alertTxt); // EVENTO DE TEXTO alertTxt myResultsFeed = myService.query(myQuery, CalendarEventFeed.class); if (myResultsFeed.getEntries().size() > 0) { // SE ENCONTRADO System.out.println(">> >> ALERT event found"); // OBTER O TÍTULO DA PRIMEIRA ENTRADA CORRESPONDENTE firstMatchEntry = (CalendarEventEntry) myResultsFeed.getEntries().get(0); myEntryTitle = firstMatchEntry.getTitle().getPlainText(); timeVar = firstMatchEntry.getTimes().get(0); System.out.println(">> >> event start&stop time : " + timeVar.getStartTime() + "\n>> >> : " + timeVar.getEndTime()); System.out.println(">> >> event start (milliseconds): " + timeVar.getStartTime().getValue()); System.out.println(">> >> new event start (milliseconds): " + (newDate.getTime() - (1000 * 60 * timePeriod))); if (timeVar.getStartTime().getValue() > newDate.getTime() - (1000 * 60 * 0)) { // SE O TEMPO DO INÍCIO DO EVENTO ANTIGO É MENOR DO QUE O MINUTO timePeriod ANTERIOR // DELETE-O deleteUrl = new URL(firstMatchEntry.getEditLink().getHref()); myService.getRequestFactory().setHeader("If-Match", "*"); myService.delete(deleteUrl); System.out.println(">> >> event start > new event start"); System.out.println(">> >> ...deleting event"); System.out.println(">> >> #M### ##M #M# "); System.out.println(">> >> ######## ### ### "); System.out.println(">> >> ### ### ### ### "); System.out.println(">> >> ### ### ### ### "); System.out.println(">> >> M## ### ######M "); System.out.println(">> >> ### ### #### ### "); System.out.println(">> >> ### ### ### ### "); System.out.println(">> >> ### ### #M# ### "); System.out.println(">> >> ### ### ### ### "); System.out.println(">> >> ######## ### ### "); System.out.println(">> >> #### ### ### "); } else { // O TEMPO É MAIOR DO QUE O MINUTO timePeriod ANTERIOR, SIGNIFICA QUE O sms JA FOI ENVIADO // DELETE-O deleteUrl = new URL(firstMatchEntry.getEditLink().getHref()); myService.getRequestFactory().setHeader("If-Match", "*"); myService.delete(deleteUrl); System.out.println(">> >> SMS has gone already"); System.out.println(">> >> event start < new event start"); System.out.println(">> >> ...deleting event"); System.out.println(">> >> .M#### M##M ###M .##### "); System.out.println(">> >> ######## #### #### ######## "); System.out.println(">> >> ### ### #### #### #M# ### "); System.out.println(">> >> ### ###M# ##### ### "); System.out.println(">> >> #M#### ##### ##### ###### "); System.out.println(">> >> ###### ### # # @## #M#### "); System.out.println(">> >> ##### ### # # ### ##### "); System.out.println(">> >> #M# ### ### # # ### M## ### "); System.out.println(">> >> ### ### ### ### ### ### ### "); System.out.println(">> >> ###### ### ### ### ###### "); System.out.println(">> >> #### ### # ### #### "); // CRIAR NOVO EVENTO myEntry = new CalendarEventEntry(); myEntry.setTitle(new PlainTextConstruct(reanimationTxt)); // CONFIGURA SEU TÍTULO newDate.setTime(newDate.getTime() + 1000 * 60 * 1); // TEMPO ATUAL + 1 MINUTO startTime = DateTime.parseDateTime(formater.format(newDate)); // INSERE LINHA USANDO O PADRÃO "2009-06-30T20:55:00" System.out.println(">> >> creating REANIMATION event"); System.out.println(">> >> event starttime: " + formater.format(newDate)); newDate.setTime(newDate.getTime() + 1000 * 60 * 0); // NOVAMENTE, ADICIONE O TEMPO ATUAL // + 1 MINUTO endTime = DateTime.parseDateTime(formater.format(newDate)); System.out.println(">> >> event stoptime : " + formater.format(newDate)); eventTimes.setStartTime(startTime); eventTimes.setEndTime(endTime); myEntry.addTime(eventTimes); reminderMinutes = 0; // RELEMBRE 1 MINUTO ANTES reminder.setMinutes(reminderMinutes); reminder.setMethod(methodType); myEntry.getReminder().add(reminder); // CRIAR UM NOVO serviço de Calendário, CONECTAR AO Google CalendarService tempService = new CalendarService("My Application"); tempService.setUserCredentials(args[0], args[1]); // LOGIN E SENHA COMO ARGUMENTOS // COLOCAR EVENTO NA FILA tempService.insert(feedUrl, myEntry); } } // CRIAR UM NOVO serviço de Calendário, CONECTAR AO Google CalendarService basicService = new CalendarService("basic Application"); basicService.setUserCredentials(args[0], args[1]); // LOGIN E SENHA COMO ARGUMENTOS // CRIAR NOVO EVENTO CalendarEventEntry basicEntry = new CalendarEventEntry(); basicEntry.setTitle(new PlainTextConstruct(alertTxt)); // CONFIGURA SEU TÍTULO if (mode == 0) { // SITUAÇÃO DIÁRIA PADRÃO newDate.setTime(newDate.getTime() + 1000 * 60 * timePeriod); // TEMPO ATUAL + timeperiod EM MINUTOS startTime = DateTime.parseDateTime(formater.format(newDate)); // INSERE LINHA USANDO O PADRÃO "2009-06-30T20:55:00" newDate.setTime(newDate.getTime() + 1000 * 60 * 0); // NOVAMENTE, ADICIONE O TEMPO ATUAL // + timePeriod EM MINUTOS endTime = DateTime.parseDateTime(formater.format(newDate)); } if (mode == 1) { // PROGRAMAÇÃO DO EVENTO NA PRÓXIMA MANHÃ OU NA SEGUNDA DE MANHÃ Date curDate = new Date(); GregorianCalendar gDate = new GregorianCalendar(); gDate.setTime(curDate); // AJUSTAR AS HORAS E OS MINUTOS NECESSÁRIOS gDate.set(GregorianCalendar.HOUR_OF_DAY, startHour); gDate.set(GregorianCalendar.MINUTE, startMin); gDate.set(GregorianCalendar.SECOND, 0); if (gDate.get(GregorianCalendar.DAY_OF_WEEK) < 6) { // SEGUNDA - QUINTA gDate.set(GregorianCalendar.DAY_OF_MONTH, gDate.get(GregorianCalendar.DAY_OF_MONTH) + 1); } else { // SEGUNDA gDate.set(GregorianCalendar.DAY_OF_MONTH, gDate.get(GregorianCalendar.DAY_OF_MONTH) + 3); } // System.out.println("gDate "+ gDate.getTime()); startTime = DateTime.parseDateTime(formater.format(gDate.getTime())); gDate.set(GregorianCalendar.MINUTE, gDate.get(GregorianCalendar.MINUTE) + timePeriod); endTime = DateTime.parseDateTime(formater.format(gDate.getTime())); System.out.println(">> nextday event should be created"); } //System.out.println("criando evento de ALERTA!"); System.out.println(">> creating ALERT event"); System.out.println(">> event starttime: " + startTime.toString()); System.out.println(">> event stoptime : " + endTime.toString()); eventTimes.setStartTime(startTime); eventTimes.setEndTime(endTime); basicEntry.addTime(eventTimes); reminderMinutes = 0; // RELEMBRE 1 MINUTO ANTES reminder.setMinutes(reminderMinutes); reminder.setMethod(methodType); basicEntry.getReminder().add(reminder); // COLOCAR EVENTO NA FILA basicService.insert(feedUrl, basicEntry); System.out.println(">>---------- Finish ----------<<"); } catch (AuthenticationException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
O código de arquivo .bat
A criação de arquivos .bat é atualmente impossível em MQL4, eu uso 2 arquivos .bat que tem Modos diferentes.
@rem +-----------------------------------------------------------------------------------------+ @rem | O aplicativo para enviar SMS | @rem | ------------------------------------------------------ | @rem | Regras: | @rem | | @rem | USER - conta do remetente | @rem | PASS - senha do remetente | @rem | ALER - Alerta, o texto da mensagem de alerta | @rem | (utilizar apenas caracteres latinos) | @rem | REAN - Reanimado, o texto da mensagem de notificação sobre a conexão restabelecida | @rem | (utilizar apenas caracteres latinos) | @rem | STOP - STOP, título do evento que proíbe a execução | @rem | das ações do programa | @rem | (utilizar apenas caracteres latinos) | @rem | PERI - Período, período do temporizador para o envio de mensagem de alerta | @rem | MODE - Mode | @rem | (0 - trabalho padrão, | @rem | 1 - agendar a mensagem a ser enviada pela parte da manhã ou | @rem | na segunda de manhã) | @rem | HOUR - Hora "de amanhã ou segunda-feira de manhã" para | @rem | a mensagem a ser enviada. | @rem | MINU - Minutos, minutos "pela parte da manhã..." | @rem +-----------------------------------------------------------------------------------------+ @rem ECHO off set USER=forex.myaccount set PASS=mypassword set ALER=Terminal_Alert set REAN=Trading_Resolved set STOP=STOP set PERI=5 set MODE=0 set HOUR=8 set MINU=20 set ARGS= %USER% %PASS% %ALER% %REAN% %STOP% %PERI% %MODE% %HOUR% %MINU% java -jar "d:\Documents\forex\Deltabank Trader 4\TerminalWatch\terminalWatcher.jar" %ARGS% @rem ECHO %ARGS%
Código do Expert Advisor
As funções do EA, cujo código é fornecido abaixo, necessitam ser chamadas em bloco de "ações programadas" com as regras do seu sistema de negociação.
No final da sessão de negociação, eu chamo a função com a agenda SMS da manhã seguinte.
Os links são marcados com .lnk para que possamos definir o modo de chamada 'Minimizar ícone' na janela do console para não assustar quando ele aparece.
//+------------------------------------------------------------------+ //| Envia um status via SMS | //+------------------------------------------------------------------+ int sendSMS() { string destination = StringConcatenate(TerminalPath(),"\TerminalWatch\launch.lnk"); ShellExecuteA(WindowHandle(Symbol(),0),"open", destination, NULL, NULL,1); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Envia um status de SMS na manhã seguinte | //+------------------------------------------------------------------+ int sendSMSnextDate() { string destination = StringConcatenate(TerminalPath(),"\TerminalWatch\launch_next_date.lnk"); ShellExecuteA(WindowHandle(Symbol(),0),"open", destination, NULL, NULL,1); } //+------------------------------------------------------------------+
Deficiências
Na prática é muito difícil sincronizar a operação com o relógio do Terminal, Servidor de Cotações e Servidor do Google, por isto no código do Expert Advisor eu uso a seguinte técnica: o SMS é definido a cada 5 minutos com temporizador de 8 minutos. Isso funciona bem em 95% dos casos, mas eu ainda tenho que lidar com os 5% restantes - a única mosca na sopa.
Conclusão
Se você achar que é interessante se inscrever para uma conta do Google, você pode facilmente verificar o quanto este sistema pouco sofisticado é capaz.
Mais uma vez, devo dizer que muitos dos detalhes da implementação Java fornecida no artigo não são do meu conhecimento. Eu tive uma grande ajuda de um colega desenvolvedor (muito obrigado Dima!), por isso não poderei responder todas as perguntas com maior rigor.
Obrigado pelo seu tempo!
Mudanças inspiradas pelos comentários recebidos sobre o artigo:
A versão atual contém uma alteração útil por komposter , versando sobre a lógica de funcionamento:
- a mensagem de reanimação não é eliminada se não tiver sido enviada
Baixe o arquivo compactado,TerminalWatch_03.rar, ligado ao artigo.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1376
- 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