Русский 中文 Español Deutsch 日本語 Português
EA Status SMS Notifications

EA Status SMS Notifications

MetaTrader 4Examples | 24 September 2013, 07:41
8 052 0

Introduction

My work often interferes with my ability to continuously monitor the terminal. It may be just 20-30 minutes but it may well be a whole day. I therefore decided to develop a system that would send an SMS to notify me of any critical situation, from a blackout to a problem like my computer not coming out of sleep mode after the weekend. I am sure that the system as provided in this article will be useful for many traders or will serve as a basis for those who don't find it good enough the way it is and would like to create their own 'masterpiece'.

In this article, I am going to demonstrate the development of a working solution to the specified task. It should be noted that I'm not even anywhere close to having professional skills in Java development so I had to ask my fellow who is a Java developer to help me debug and fix my failing code.


Plan

  1. Google Calendar features
  2. A few words about installation of Google Data APIs
  3. System flowchart
  4. Java application code
  5. The .bat file code
  6. Code of the Expert Advisor
  7. Shortcomings
  8. Conclusion


Google Calendar features

In developing the SMS notification system, I decided in favor of Google Calendar as it allows creating events in its free Calendar and you can use SMS as the means of notification of any such event. For the specified purpose, I created a special separate profile with Google.

In a nutshell, the description of the operating principle is as follows: if the current message is not deleted by 9.59 am (please see the above screenshot), i.e. if the Terminal does not get connected with Google server to initiate the replacement of the current message with a different one, an SMS will be sent to your phone with the appropriate notification.


A few words about installation of Google Data APIs

To be able to use Google services in developing your software solutions, Google provides the Google Data APIs documentation.
All the documentation that a Java developer may need when working with Google Calendar can be found using this link Google Calendar APIs and Tools.

To start programming, you will have to install Google Data Java Client Library. On the same page, you can find a link to the documentation related to the library for Eclipse. This is what I used and would recommend it to you: Using Eclipse with Google Data APIs.


System flowchart

I think that I should first comment upon the flowchart:

  • the StopTXT event is required to be able to manually and remotely stop the flow of SMS just in case;
  • the ReanimationTXT event is required to inform that for some reason the terminal managed to get connected after the corresponding SMS with a warning was sent to you;


Java application code

All the source codes and distribution used are attached at the end of the article.

package Calendar;
/* INSTRUCTION: This is a command line application. 
    So please execute this template with the following arguments:

                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 {
            //--- EXTERNAL VARIABLES ----------------------------
            String alertTxt = args[2];
            String reanimationTxt = args[3];
            String stopSMS = args[4];
            int timePeriod = Integer.parseInt(args[5]); // interval in minutes at which the terminal 
                                                        // will get connected
            int mode = Integer.parseInt(args[6]);
            int startHour = Integer.parseInt(args[7]);
            int startMin = Integer.parseInt(args[8]);
            //---------------------------------------------------
            //--- INTERNAL VARIABLES --------------------------
            URL feedUrl = new URL("http://www.google.com/calendar/feeds/default/private/full");
            //link for working with events
            URL calendarUrl = new URL("http://www.google.com/calendar/feeds/default/allcalendars/full");
            //link for working with calendars   
            //---------------------------------------------------
            System.out.println(">>----------  Start   ----------<<");

            // Create a new Calendar service, connect to Google
            CalendarService myService = new CalendarService("My Application");
            myService.setUserCredentials(args[0], args[1]);    // LOGIN AND PASSWORD AS ARGUMENTS

            // DECLARE VARIABLES FOR EVENT SEARCH
            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;

            // PREPARE SEARCH QUERY
            myQuery.setFullTextQuery(stopSMS);            // stopSMS TEXT EVENT
            myResultsFeed = myService.query(myQuery, CalendarEventFeed.class);
            if (myResultsFeed.getEntries().size() > 0) {
                System.out.println(">> STOP event found. \n>> Finish");
                return;
            }

            // PREPARE SEARCH QUERY 
            myQuery.setFullTextQuery(reanimationTxt);    // reanimationTxt TEXT EVENT
            myResultsFeed = myService.query(myQuery, CalendarEventFeed.class);
            if (myResultsFeed.getEntries().size() > 0) {    // IF FOUND
                System.out.println(">> REANIMATION event found");
                // GET TITLE OF THE FIRST MATCH ENTRY
                firstMatchEntry = (CalendarEventEntry) myResultsFeed.getEntries().get(0);
                myEntryTitle = firstMatchEntry.getTitle().getPlainText();

                // IF THE reanimationTxt EVENT FOUND, DELETE IT
                deleteUrl = new URL(firstMatchEntry.getEditLink().getHref());
                myService.getRequestFactory().setHeader("If-Match", "*");
                myService.delete(deleteUrl);
                System.out.println(">> ...deleting REANIMATION event");
            }

            // PREPARE SEARCH QUERY
            myQuery.setFullTextQuery(alertTxt);            // alertTxt TEXT EVENT
            myResultsFeed = myService.query(myQuery, CalendarEventFeed.class);
            if (myResultsFeed.getEntries().size() > 0) {    // IF FOUND
                System.out.println(">>  >> ALERT event found");
                // GET TITLE OF THE FIRST MATCH ENTRY
                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)) {    
                    // IF THE START TIME OF THE OLD EVENT IS LESS THAN timePeriod MINUTES AGO
                    // DELETE IT
                    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 { // THE TIME IS MORE THAN timePeriod MINUTES AGO, WHICH MEANS THAT THE sms HAS ALREADY BEEN SENT // DELETE IT 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(">> >> #### ### # ### #### "); // CREATE NEW EVENT myEntry = new CalendarEventEntry(); myEntry.setTitle(new PlainTextConstruct(reanimationTxt)); // SET ITS TITLE newDate.setTime(newDate.getTime() + 1000 * 60 * 1); // CURRENT TIME + 1 MINUTE startTime = DateTime.parseDateTime(formater.format(newDate)); // INSERTS THE LINE USING THE PATTERN "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); // AGAIN ADD THE CURRENT TIME  // + 1 MINUTE 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; // REMIND 1 MINUTE BEFORE reminder.setMinutes(reminderMinutes); reminder.setMethod(methodType); myEntry.getReminder().add(reminder); // CREATE A NEW Calendar service, CONNECT TO Google CalendarService tempService = new CalendarService("My Application"); tempService.setUserCredentials(args[0], args[1]); // LOGIN AND PASSWORDS AS ARGUMENTS // PUT EVENT IN QUEUE tempService.insert(feedUrl, myEntry); } } // CREATE A NEW Calendar service, CONNECT TO Google CalendarService basicService = new CalendarService("basic Application"); basicService.setUserCredentials(args[0], args[1]); // LOGIN AND PASSWORD AS ARGUMENTS // CREATE NEW EVENT CalendarEventEntry basicEntry = new CalendarEventEntry(); basicEntry.setTitle(new PlainTextConstruct(alertTxt)); // SET ITS TITLE if (mode == 0) { // STANDARD DAILY SITUATION newDate.setTime(newDate.getTime() + 1000 * 60 * timePeriod); // CURRENT TIME + timePeriod MINUTES startTime = DateTime.parseDateTime(formater.format(newDate)); // INSERTS THE LINE USING THE PATTERN "2009-06-30T20:55:00" newDate.setTime(newDate.getTime() + 1000 * 60 * 0); // AGAIN ADD THE CURRENT TIME // + timePeriod MINUTES endTime = DateTime.parseDateTime(formater.format(newDate)); } if (mode == 1) { // SCHEDULE EVENT FOR THE NEXT MORNING OR MONDAY MORNING Date curDate = new Date(); GregorianCalendar gDate = new GregorianCalendar(); gDate.setTime(curDate); // SET THE REQUIRED HOUR AND MINUTE 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) { // MO - THU gDate.set(GregorianCalendar.DAY_OF_MONTH, gDate.get(GregorianCalendar.DAY_OF_MONTH) + 1); } else { // MO 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("creating ALERT event!"); 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; // REMIND 1 MINUTE BEFORE reminder.setMinutes(reminderMinutes); reminder.setMethod(methodType); basicEntry.getReminder().add(reminder); // PUT EVENT IN QUEUE 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(); } } }


The .bat file code

Since creation of .bat files in MQL4 is currently impossible, I use 2 .bat files that have different Modes.

@rem +-----------------------------------------------------------------------------------------+
@rem |         The application sends SMS                                                       |
@rem |      ------------------------------------------------------                             |
@rem | Rules:                                                                                  |
@rem |                                                                                         |
@rem | USER   -   sender's account                                                             |
@rem | PASS   -   sender's password                                                            |
@rem | ALER   -   Alert, text of the alert message                                             |
@rem |              (only use Latin characters)                                                |
@rem | REAN   -   Reanimated, text of the message notifying about the reestablished connection |
@rem |                  (only use Latin characters)                                            |
@rem | STOP   -   STOP, title of the event that forbids execution                              |
@rem |                  of the program actions                                                 |
@rem |                  (only use Latin characters)                                            |
@rem | PERI   -   Period, period-timer for sending Alert message                               |
@rem | MODE   -   Mode                                                                         |
@rem |                  (0 - standard work,                                                    |
@rem |                   1 - scheduling the message to be sent tomorrow morning or             |
@rem |                        on Monday morning)                                               |
@rem | HOUR   -   Hour "of tomorrow morning or Monday morning" at                              |
@rem |                   which the message is required to be sent.                             |
@rem | MINU   -   Minutes, minutes "of tomorrow morning..."                                    |
@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%


Code of the Expert Advisor

The functions whose code is provided below will need to be called in the 'scheduled actions' block according to the rules of your Trading System.
At the end of the trading session, I call the function that schedules SMS for the next morning.

Links are tagged with .lnk so that we can set the 'Minimize to icon' call mode for the console window not to get startled when it pops up.

//+------------------------------------------------------------------+
//| Sends a status SMS                                               |
//+------------------------------------------------------------------+
int sendSMS()
{
      string destination = StringConcatenate(TerminalPath(),"\TerminalWatch\launch.lnk");
      ShellExecuteA(WindowHandle(Symbol(),0),"open", destination, NULL, NULL,1);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Sends a status SMS the next morning                              |
//+------------------------------------------------------------------+
int sendSMSnextDate()
{
      string destination = StringConcatenate(TerminalPath(),"\TerminalWatch\launch_next_date.lnk");
      ShellExecuteA(WindowHandle(Symbol(),0),"open", destination, NULL, NULL,1);
}
//+------------------------------------------------------------------+


Shortcomings

In practice, it is very hard to synchronize the operation with the clock of the Terminal, Quotes Server and Google Server. Therefore, in the code of the Expert Advisor I use the following technique: SMS is set every 5 minutes with the 8 minute timer. This works well in 95% of cases but I still have to deal with the remaining 5% - the only fly in the ointment.


Conclusion

If you find it interesting and feel like signing up for a Google account, you can easily check what my unsophisticated system is capable of.
Once again, I should say that many details of the Java implementation provided in the article are not completely clear to me. I got some great help from my fellow developers (Thanks a lot Dima!) so I will not be able to answer all your questions to the utmost accuracy.
Thank you for your time!


Changes inspired by the comments received on the article

The current version contains a useful amendment by komposter regarding the operation logic:

  • the reanimation message is not deleted if it has not been sent;

Please find TerminalWatch_03.rar attached to the article.

Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1376

Attached files |
TerminalWatch_02.zip (1622.08 KB)
TerminalWatch_03.zip (1622.04 KB)
MQL5 Cookbook: Reducing the Effect of Overfitting and Handling the Lack of Quotes MQL5 Cookbook: Reducing the Effect of Overfitting and Handling the Lack of Quotes
Whatever trading strategy you use, there will always be a question of what parameters to choose to ensure future profits. This article gives an example of an Expert Advisor with a possibility to optimize multiple symbol parameters at the same time. This method is intended to reduce the effect of overfitting parameters and handle situations where data from a single symbol are not enough for the study.
How to Make Money from MetaTrader AppStore and Trading Signals Services If You Are Not a Seller or a Provider How to Make Money from MetaTrader AppStore and Trading Signals Services If You Are Not a Seller or a Provider
It is possible to start making money on MQL5.com right now without having to be a seller of Market applications or a profitable signals provider. Select the products you like and post links to them on various web resources. Attract potential customers and the profit is yours!
MQL5 Wizard: How to Teach an EA to Open Pending Orders at Any Price MQL5 Wizard: How to Teach an EA to Open Pending Orders at Any Price
The article describes a method of modifying the code of a trading signal module for the implementation of the functionality allowing you to set pending orders at any distance from the current price: it may be the Close or Open price of the previous bar or the value of the moving average. There are plenty of options. Important is that you can set any opening price for a pending order. This article will be useful to traders who trade with pending orders.
Creating Neural Network EAs Using MQL5 Wizard and Hlaiman EA Generator Creating Neural Network EAs Using MQL5 Wizard and Hlaiman EA Generator
The article describes a method of automated creation of neural network EAs using MQL5 Wizard and Hlaiman EA Generator. It shows you how you can easily start working with neural networks, without having to learn the entire body of theoretical information and writing your own code.