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

EA Status SMS Notifications

MetaTrader 4Examples | 24 September 2013, 07:41
7 821 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)
Lite_EXPERT2.mqh: Functional Kit for Developers of Expert Advisors Lite_EXPERT2.mqh: Functional Kit for Developers of Expert Advisors
This article continues the series of articles "Expert Advisors Based on Popular Trading Systems and Alchemy of Trading Robot Optimization". It familiarizes the readers with a more universal function library of the Lite_EXPERT2.mqh file.
Expert Advisor for Trading in the Channel Expert Advisor for Trading in the Channel
The Expert Advisor plots the channel lines. The upper and lower channel lines act as support and resistance levels. The Expert Advisor marks datum points, provides sound notification every time the price reaches or crosses the channel lines and draws the relevant marks. Upon fractal formation, the corresponding arrows appear on the last bars. Line breakouts may suggest the possibility of a growing trend. The Expert Advisor is extensively commented throughout.
Visual Optimization of Indicator and Signal Profitability Visual Optimization of Indicator and Signal Profitability
This article is a continuation and development of my previous article "Visual Testing of Profitability of Indicators and Alerts". Having added some interactivity to the parameter changing process and having reworked the study objectives, I have managed to get a new tool that does not only show the prospective trade results based on the signals used but also allows you to immediately get a layout of deals, balance chart and the end result of trading by moving virtual sliders that act as controls for signal parameter values in the main chart.
Simple Methods of Forecasting Directions of the Japanese Candlesticks Simple Methods of Forecasting Directions of the Japanese Candlesticks
Knowing the direction of the price movement is sufficient for getting positive results from trading operations. Some information on the possible direction of the price can be obtained from the Japanese candlesticks. This article deals with a few simple approaches to forecasting the direction of the Japanese candlesticks.