English Русский Español Deutsch 日本語 Português
EA 状态短信通知

EA 状态短信通知

MetaTrader 4示例 | 11 四月 2016, 18:02
5 361 0
Дмитрий
Дмитрий

简介

我的工作经常影响对终端的持续监视。 这可能是 20-30 分钟,也可能是一整天。 因此我决定开发一个系统,能够在出现任何紧急情况时发送短信通知我,无论是出现停电还是诸如我的电脑在周末后没有退出睡眠模式等问题。 我相信本文提供的系统对于很多交易者来说会非常有用,或者对于那些觉得它不够好但想要创建他们自己的‘杰作’的人,可以将其作为基础。

本文中,我想展示这一特定任务的解决方案的规划。 需要注意的是,我几乎不具备 Java 开发的专业技能,所以不得不请求作为 Java 开发工程师的朋友帮助我调试并修正错误代码。



计划

  1. Google Calendar 功能
  2. 关于安装 Google Data APIs 的简述
  3. 系统流程图
  4. Java 应用程序代码
  5. .bat 文件代码
  6. Expert Advisor 代码
  7. 缺点
  8. 总结


Google Calendar 功能

在开发短信通知系统时,我决定选用 Google Calendar,因为它允许在其免费的 Calendar 中创建事件,你可以使用短信作为通知任何这种事件的方式。 为了实现这个特定的目的,我使用 Google 创建了一个专门的单独配置文件。

简而言之,工作原理描述如下:如果当前的信息未在 9.59 am 之前删除(请查看上面的截屏),即如果终端没有连接 Google 的服务器并将当前信息替换为不同的信息,就会有一条短信发送到你的手机进行通知。



关于安装 Google Data APIs 的简述

为了能够在开发你的软件解决方案时使用 Google 服务,Google 提供了 Google Data APIs 文档。
Java 开发工程师在使用 Google Calendar 时所需的所有文档都可以使用下面的链接找到:Google Calendar APIs and Tools

要开始编程,你必须安装 Google Data Java Client Library。 在同一页上,你可以找到一个跟 Eclipse 的库相关文档的链接。 这就是我所使用并且想推荐给你的: Using Eclipse with Google Data APIs

系统流程图

我想我应该先评论流程图:

  • StopTXT 事件 要求能够在必要时手动和远程停止短信发送。
  • StopTXT 事件 要求在相应的警告短信发送给你 之后, 通知你终端出于某种原因已经连接上了。



Java 应用程序代码

所使用的全部源代码和分配均附在文章末尾。

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(); } } }

.bat 文件代码

由于当前无法在 MQL4 中创建 .bat 文件,我使用了 2 个具有不同 Mode 的 .bat 文件。

@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%

Expert Advisor 代码

下面提供了一些函数的代码。根据你的交易系统的规则,这些函数需要在‘预定操作’程序块中调用。
在交易时段结束时,我调用了预定第二天早上的短信的函数。

链接具有 .lnk 标记,我们将控制台窗口设置为‘最小化到图标’调用模式,以免在它弹出时被吓到。

//+------------------------------------------------------------------+
//| 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);
}
//+------------------------------------------------------------------+


缺点

在实践中,很难将 Terminal、Quotes Server 和 Google Server 的时钟与运行同步。 因此,在 Expert Advisor 的代码中我使用了以下技巧: 使用 8 分钟的定时器将短信设置为每 5 分钟进行通知。 这在 95% 的情形下工作良好,但我不得不处理剩下的 5%——这是唯一的美中不足。



总结

如果你觉得很有趣,想注册一个 Google 帐户,那你就可以检验我这个并不复杂的系统的能力了。
再说一次,对于本文提供的很多 Java 实现的细节,我并非完全清楚。 我从作为开发工程师的朋友那里得到很大的帮助(非常感谢 Dima!),所以无法非常精准的回答你的所有问题。
感谢你们的阅读!



受本文的评论启发进行的改动

当前的版本包含了一个由 komposter 在运行逻辑上进行的有用改动:

  • 如果复原的信息尚未发送,则不予删除。

请查看本文的附件 TerminalWatch_03.rar

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1376

附加的文件 |
TerminalWatch_02.zip (1622.08 KB)
TerminalWatch_03.zip (1622.04 KB)
Lite_EXPERT2.mqh: Expert Advisor 开发人员的功能套件 Lite_EXPERT2.mqh: Expert Advisor 开发人员的功能套件
本文是一系列“基于常见交易系统的 Expert Advisor 和交易机器人优化的惊人作用”文章的继续展开。 本文让读者熟悉 Lite_EXPERT2.mqh 文件的一个更为通用的函数库。
用于在通道中进行交易的 Expert Advisor 用于在通道中进行交易的 Expert Advisor
Expert Advisor 绘制通道线。 上下通道线作为支撑位和阻力位。 Expert Advisor 标记基准点,并在价格达到或穿过通道线时提供声音通知,并绘制相关标记。 分形形成时,对应的箭头将显示在最后一个条柱上。 突破通道线意味着可能会形成上涨趋势。 Expert Advisor 自始至终都有大量的注释。
指标和信号盈利能力的可视化优化 指标和信号盈利能力的可视化优化
本文是我的上一篇文章“指标和提醒的盈利能力的可视化测试”的延续和拓展。 通过在参数更改过程中添加一些交互性和修改研究对象,我成功地获得了一个新工具,此工具不仅仅显示基于所使用信号的预期交易结果,还允许通过移动在主图表中用作信号参数值控件的虚拟滑块,立即获得交易布局、余额图表和最终交易结果。
预测日本蜡烛图方向的简单方法 预测日本蜡烛图方向的简单方法
了解价格变动的方向就足以从交易操作中获得正面结果。 可从日本蜡烛图中获得有关可能的价格方向的一些信息。 本文介绍几种用于预测日本蜡烛图方向的简单方法。