English Русский 中文 Español Deutsch 日本語
Notificações SMS do Status do EA

Notificações SMS do Status do EA

MetaTrader 4Exemplos | 4 novembro 2015, 15:04
1 261 0
Дмитрий
Дмитрий

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

  1. Recursos do Google Calendar
  2. Algumas palavras sobre a instalação de APIs de dados do Google
  3. Fluxograma do sistema
  4. Código do aplicativo Java
  5. O código de arquivo .bat
  6. Código do Expert Advisor
  7. Deficiências
  8. 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

Arquivos anexados |
TerminalWatch_02.zip (1622.08 KB)
TerminalWatch_03.zip (1622.04 KB)
Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors Lite_EXPERT2.mqh: Kit Funcional para Desenvolvedores de Expert Advisors
Este artigo continua a série "Expert Advisors Baseados nos Sistemas de Negociação Populares e na Alquimia da Otimização de Robô de Negociação". Tem o objetivo de familiarizar os leitores com uma biblioteca de funções mais universal do arquivo Lite_EXPERT2.mqh.
Expert Advisor para Negociação no Canal Expert Advisor para Negociação no Canal
O Expert Advisor desenha linhas para formar um canal. As linhas de canal superior e inferior atuam como níveis de suporte e resistência. O Expert Advisor marca pontos de referência, fornece notificação sonora toda vez que o preço atinge ou cruza as linhas do canal e desenha os símbolos dos pontos principais. Após a formação do fractal, as setas correspondentes aparecem nas últimas barras. Linhas de rompimentos podem sugerir a possibilidade de uma tendência crescente. O Expert Advisor é amplamente comentado em toda a sua extensão.
Otimização Visual de Indicador e Sinal de Rentabilidade Otimização Visual de Indicador e Sinal de Rentabilidade
Este artigo é uma continuação e desenvolvimento de meu artigo anterior "Testes Visuais de Rentabilidade dos Indicadores e Alertas". Tendo acrescentado alguma interatividade com o processo de mudança de parâmetro e reformulado os objetivos do estudo, além de obter uma nova ferramenta que mostra os potenciais resultados com base nos sinais utilizados, também permite que você obtenha imediatamente um layout de operações, gráfico do saldo e o resultado final da negociação, movendo controles deslizantes virtuais que funcionam como controladores para os valores dos parâmetros do sinal no gráfico principal.
Ação do Preço: Automatizando a Estratégia de Negociação "Inside Bar" Ação do Preço: Automatizando a Estratégia de Negociação "Inside Bar"
O artigo descreve o desenvolvimento de um Expert Advisor MetaTrader 4 baseado na estratégia "Inside Bar" (Barra Envolvida), incluindo princípios para detecção deste padrão, bem como configurações de regras para uma ordem stop e pendente. Os resultados dos testes e otimização são publicados também.