下载MetaTrader 5

使用 Skype 发送来自 Expert Advisor 的消息

25 二月 2016, 15:34
Alexey Koshevoy
0
286

简介

Skype 是一种通讯程序,允许人们通过互联网打电话和进行正常的聊天。与其他同类程序相比,Skype 最重要的优势之一是,它是通往真正移动网络运营商的一个途径。人们可以拨打真正的移动电话,发送短信等等。还有一个移动电话的 Skype 版本。人们可以节省短信费用,因为用此程序发送常规消息是完全免费的。基本上,移动电话必须在操作系统下运行。不过,如今必要时也可以实现全移动式运行。这正是现在很多人在利用的机会。


哪些人需要它?为什么?

交易者不可能一直坐在交易终端前看着交易执行情况,也不必这么做。但是,能够不时获取一些信号,让交易者了解有关 Expert Advisor 的操作或特定时刻的市场状态的信息,这自然是极好的。为什么不在移动电话里获取此类信息呢?


哪种信息是有用的?

可通过移动电话中的消息获取的信息可分为两类:

  1. 不影响任何东西且实际上与日志文件中的数据并无差别的当前数据;
  2. 收到时正好对交易者有帮助的有用信息。

让我们看看当前数据的示例:

  • 订单状态。订单是何时开放的,哪个方向,为其分配了什么止损位等,订单何时关闭,什么原因,是亏损了还是盈利了等等。
  • 各种市场状态例如,某项指标满足一定水平或某个趋势改变了方向时。

有用的信息:

  • 错误报告。所有程序员都是人,有时在 Expert Advisor 发生故障时会出现一些不愉快的情形。人们会很乐意了解错误发生时的状况以及是否造成致命停机。当然,如果 Expert Advisor 的逻辑允许人检测错误,也是可行的。
  • Expert Advisor 的操作状态。例如,EA 设置为在您出差时每小时向您发送一条关于其操作状态的消息。而预定的时间内并没有发来预期的消息。从断网到断电,一切情况都有可能发生。如果是在家里使用终端,可以请求同事或配偶找出出错原因并还原设置,而不是在一无所知的情况下空等一个礼拜。

当然,这种区分具有相对性质,可能出现的情况远不止本文所述。每个交易者将自己决定消息应包括的内容。重点是要认识到,这个功能是非常有用的。


这个功能在 Skype 中如何实现?

  • SMSes

    此服务当然是付费服务。一切看起来都一如往常:键入用户号码,输入消息,再按“发送”。

  • 常规消息

    这是完全免费的。只需选择一个用户,输入消息,然后按“发送”。

如何从 Expert Advisor 实现这一点?

有两种方法,这两种方法都需要使用 DLL:

  1. 我们应提前准备好一个宏文件,即在启动该文件时,对键盘和鼠标的控制将被截获。因此我们应使用操作序列激活 Skype,在菜单中找到短信发送项目,然后在显示的窗口中键入用户号码,并从剪贴板中粘贴起初在 Expert Advisor 中键入的文本信息。您可事先练习并熟悉这些操作。这样,我们就制作了一份文件,这份文件是一个关联文档,可作为普通应用程序启动。顺便提一下,可以记录和播放宏文件的应用程序数不胜数,因此本文中未讨论具体程序。

    接下来,我们必须开发一个将以如下方式运行的 DLL。其第一项操作是将 Expert Advisor 中的文本放入剪贴板。第二项操作是启动预定义的宏文件。如果一切正常,所有窗口和按钮都显示在正确位置,则不会出现任何问题,消息将被发送出去。

    但这种方法有点耸人听闻。直觉告诉我,如果大脑开始出现这种想法,那就必须找出一个更令人愉快的解决方案或是完全放弃这个想法。一个新的想法突然浮现在我脑海里:Skype 是否可以有一个 API?我在他们的网站上找到了 API 和 ActiveX 界面。棒极了!让我们考虑从 Expert Advisor 使用 Skype 的另一种方法。

  2. 方法大致是相同的。用户号码和要发送的文本将从 EA 传递到 DLL,然后通过 Skype COM 对象发送消息。

如何实现第二种方法

让我们先从 DLL 开始。所有工作的主要部分是准备 DLL 以与 Expert Advisor 交互。首先,我们编写一个库,当从多个 Expert Advisor 中调用时,它可正常工作。遗憾的是,仅仅编写和调用一个函数是不够的。我们正在使用 ActiveX,所以最好为其创建一个特殊的单独线程,在这个线程里执行所有操作。互斥函数的标准并联工具并不能提供什么帮助。将会出现无法检测到的崩溃。因此我们将通过自定义消息传递系统实现调用序列。

DLL 源代码

#include "stdafx.h"
 
#pragma once
// Allow use of features specific to Windows XP or later. 
#ifndef WINVER
// Change this to the appropriate value to target other versions of Windows.
#define WINVER 0x0501      
#endif
// Exclude rarely-used stuff from Windows headers 
#define WIN32_LEAN_AND_MEAN
 
// Include Skype4COM.dll, preliminarily downloaded 
// from the Skype developers website – http://developers.skype.com/
#import "Skype4COM.dll" rename("CreateEvent","CreatePluginEvent"), 
                        rename("SendMessage","SendChatMessage")
 
 
#define MT4_EXPFUNC __declspec(dllexport)
 
// Declare message codes for our functions.
#define WM_PROC_SENDSKYPESMS WM_USER + 01
#define WM_PROC_SENDSKYPEMESSAGE WM_USER + 02
 
// Variables for the thread to be used for 
// sending messages
HANDLE hUserThread;
DWORD ThreadId;
 
// Structures to store parameters of functions
// SendSkypeSMS
struct fcpSendSkypeSMS
  {
    int ExitCode;
    char * UserNum;
    char * Message;
  };
 
// SendSkypeMessage
struct fcpSendSkypeMessage
  {
    int ExitCode;
    char * UserName;
    char * Message;
  };
//+------------------------------------------------------------------+
//| Thread function                                                  |
//+------------------------------------------------------------------+
DWORD WINAPI ThreadProc(LPVOID lpParameter)
  {
    MSG msg;
    HANDLE hEvent;
  
    while(true)
      {
        if(PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0))
            break;
      };
    // Initialize COM
    CoInitialize(NULL);
    while(GetMessage(&msg, 0, 0, 0))
      {
        if(msg.message == WM_QUIT)
          {
            break;
          }
        // Message processor WM_PROC_SENDSKYPESMS
        else 
            if(msg.message == WM_PROC_SENDSKYPESMS)
              {
                fcpSendSkypeSMS* fcp = (fcpSendSkypeSMS*)msg.wParam;
                hEvent = (HANDLE)msg.lParam;
                try
                  {
                    // Initialize Skype 
                    SKYPE4COMLib::ISkypePtr pSkype(__uuidof(SKYPE4COMLib::Skype));
                    // Connect to Skype. 6 is the protocol version
                    HRESULT hr=pSkype->Attach(6,VARIANT_TRUE);
                    // If everything is ok, start sending the message
                    if(!FAILED(hr))
                      {    
                        try
                          {
                            fcp->ExitCode = 1;
                            // Try to send an SMS
                            pSkype->SendSms(fcp->UserNum,fcp->Message,"");
                          }
                        catch(...)
                          {
                            fcp->ExitCode=-1;
                          }
                      }
                    // Deinitialize Skype
                    pSkype = NULL;
                  }
                catch(...)
                  {
                    //Error is processed here
                  }
                // Set the event
                SetEvent(hEvent);
              }
            // Message processor WM_PROC_SENDSKYPEMESSAGE
            else 
                if(msg.message == WM_PROC_SENDSKYPEMESSAGE)
                  {
                    fcpSendSkypeMessage* fcp = 
                                   (fcpSendSkypeMessage*)msg.wParam;
                    hEvent = (HANDLE)msg.lParam;
        
                    try
                      {
                        // Initialize Skype 
                        SKYPE4COMLib::ISkypePtr pSkype(__uuidof
                                              (SKYPE4COMLib::Skype));
                        // Connect to Skype. 6 is the protocol version
                        HRESULT hr=pSkype->Attach(6,VARIANT_TRUE);
                        // If everything is ok, start sending the message
                        if(!FAILED(hr))
                          {
                            try
                              {
                                fcp->ExitCode = 1;
                                // Try to send the message
                                pSkype->SendChatMessage(fcp->UserName,
                                                        fcp->Message);
                              }
                            catch(...)
                              {
                                fcp->ExitCode=-1;
                                MessageBeep(0);
                              }
                          }
                        // Deinitialize Skype
                        pSkype = NULL;
                      }
                    catch(...)
                      {
                        //Error is processed here
                      }
  
                    // Set the event
                    SetEvent(hEvent);
                  }
              };
            // Deinitialize COM
            CoUninitialize();
            return 0;
          }
 
//DLL Initialization
//+------------------------------------------------------------------+
//| DLL entry                                                        |
//+------------------------------------------------------------------+
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
                      LPVOID lpReserved)
  {
    if(ul_reason_for_call == DLL_PROCESS_ATTACH)
      {
        // Create a thread and attach the processor procedure address to it
        hUserThread = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &ThreadId);
        if(!hUserThread)
          {
            // Error processing if the thread is not created
          };
      } 
    else 
        if(ul_reason_for_call == DLL_PROCESS_DETACH)
          {
            // Delete the thread when exiting the library
            CloseHandle(hUserThread);
          }
    return(TRUE);
  }
 
MT4_EXPFUNC bool __stdcall SendSkypeSMS(int &ExCode,char* sUserNum, 
                                        char* sMessage)
  {
    //Declare the structure of function parameters
    fcpSendSkypeSMS* fcp;
    //Declare an event
    HANDLE hEvent;
    //The result of function operation by default is false
    bool Result = false;
 
    // Allocate a password for the structure and initialize it
    fcp = new fcpSendSkypeSMS();
    memset(fcp, 0, sizeof(fcpSendSkypeSMS));
 
    // Fill out the structure
    //By default, the code of the function working end is an error.
    fcp->ExitCode = -1;
    fcp->UserNum = sUserNum;
    fcp->Message = sMessage;
 
    // Create an event
    hEvent = CreateEvent(NULL,FALSE,FALSE, NULL);
    // Call event WM_PROC_SENDSKYPESMS, pass  the data structure address 
    // to processing procedure 
    PostThreadMessage(ThreadId, WM_PROC_SENDSKYPESMS, (WPARAM)fcp,
                      (LPARAM)hEvent);
    if(WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE))
      {
        
        Result = true;
      } 
    else
      {
        // If there was an error at message processing, the function will 
        // return false
        return(Result);
      };
    // Assign the function processing code to the variable
    ExCode = fcp->ExitCode;
    if(ExCode == -1) 
        Result = false;
    // Free memory and variables and exit
    delete fcp;
    CloseHandle(hEvent);
    return(Result);
  }
 
MT4_EXPFUNC bool __stdcall SendSkypeMessage(int &ExCode,char* sUserName, 
                                            char* sMessage)
  {
    //Declare the structure of function parameters
 fcpSendSkypeMessage* fcp;
    //Declare an event
    HANDLE hEvent;
    //The result of function operation by default is false
    bool Result = false;
 
    // Allocate memory for the structure and initialize it
    fcp = new fcpSendSkypeMessage();
    memset(fcp, 0, sizeof(fcpSendSkypeMessage));
 
    // Fill out the structure
    //By default, the code of the function working end is an error.
    fcp->ExitCode = -1;
    fcp->UserName = sUserName;
    fcp->Message = sMessage;
 
    // Create an event
    hEvent = CreateEvent(NULL, FALSE,FALSE, NULL);
    // Call the event WM_PROC_SENDSKYPESMS, pass the data structure address 
    // to processing procedure
    PostThreadMessage(ThreadId, WM_PROC_SENDSKYPEMESSAGE, (WPARAM)fcp,
                      (LPARAM)hEvent);
    if(WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE))
      {
        Result = true;
      } 
    else
      {
        // If there was an error at message processing, the function will 
        // return false
        return(Result);
      };
    // Assign the function processing code to the variable
    ExCode = fcp->ExitCode;
    if(ExCode == -1) 
        Result = false;
    // Free memory and variables and exit
    delete fcp;
    CloseHandle(hEvent);
    return(Result);
  }

File DEF

LIBRARY SkypeLib
 
EXPORTS SendSkypeSMS
        SendSkypeMessage

Expert Advisor to Be Tested

//+------------------------------------------------------------------+
//|                                              SkypeTestExpert.mq4 |
//|                               Copyright © 2007, Alexey Koshevoy. |
//+------------------------------------------------------------------+
// Import functions
#import "SkypeLib.dll"
   bool SendSkypeSMS(int &ExCode[], string Num,string Message);
   bool SendSkypeMessage(int &ExCode[], string User, string Message);
#import
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int init()
  {
   int ExCode[1];
   Alert("Send message...");
   Alert(SendSkypeMessage(ExCode, "skype.account.name", "Skype message test"));
   if(ExCode[0] == -1)
       Alert("Error sending the message");
   else 
       Alert("Message sent");
   Alert("Send SMS...");
   Alert(SendSkypeSMS(ExCode, "+1234567890", "Skype sms test"));
   if(ExCode[0] == -1)
       Alert("Error sending the SMS");
   else
       Alert("SMS sent");
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   return(0);
  }
//+------------------------------------------------------------------+

Ea 非常简单,其主要目的是通过已编码的 DLL 发送短信和常规消息。它在初始化函数内起作用,因此也可在周末对其进行测试。


Skype 的安装

此应用程序可在 http://www.skype.com/ 上下载。建议安装最新版程序,因为之前的版本不支持 COM 接口,它们仅有一个 API。但该 API 不支持发送短信。

Skype 已经安装好了。现在我们必须下载 COM 库。可在 https://developer.skype.com/ 上的“Downloads”中找到该库。检查用于发送短信的帐户中的金额。如果金额不足,可在网上充值。帐户上没有资金时,不可发送短信,但可发送常规消息,不会有任何问题。


终端必须注册后方可访问 Skype API。可在菜单“工具->选项->隐私->管理访问 Skype 的其他程序”来勾选是否允许使用 API。大致情况必须如下:




终端将在首次尝试使用库时注册。此操作不可手动进行。因此,在首次安装库时,需要等待直至能够发出一条消息,以此证明允许使用 Skype API。Skype 将显示以下对话框:





确认之后,系统将在自动模式下开始工作。


SkypeLib 的安装

Для 要安装名为 SkypeLib.dll 的库,应将其复制到终端目录下的 experts/libraries 文件夹中。名为 Skype4COM.dll 的库也必须复制到此文件夹。现在,我们需要设置终端能够与 DLL 一起使用。为此,在连接 EA 时,勾选“安全”部分中的“允许 DLL 导入”字段,如下所示:




现在我们可以使用此库。

一些重要细节

凭借测试和实施方面的经验,我注意到了一些“微妙之处”。例如,您需要注意到,如果您的帐户上有足够的钱,当您向不存在的号码发送短信时,不会报告错误,该函数将正常运行,然而消息状态将设置为“发送中…”。这就是为什么非常明确地设置函数输入很重要的原因。使用 Skype 版本 3.0(或更高版本)也很重要。

有时候会发生以下情况(但极少出现):COM 对象未初始化,且不会发送消息。只有重新安装 Skype 才能解决此问题。外部接口相对较新,没有错误,因此可能会出现此类不愉快的情况。据我所知,这种情况出现过两次。让我们期待更高版本会更稳定地工作。

还必须指出,要 SkypeLib. dll 正常工作,还需要一些其他库。在 Visual Studio 2005 的第一个服务包发布之后,该问题尤为严重。解决该问题的最佳方法是创建安装文件。所有必要的库将自动包括在此文件中。文件 Skype4COM. dll 也可包括在此文件中。

本文随附文件

  • SkypeLib.dll - 此库在 Visual C++ 6.0 中进行编译。除 Skype4COM.dll 之外,它不需要任何其他文件。
  • SkypeLib.zip - 库源代码
  • SkypeExample.mq4 - 用于要测试的库的 Expert Advisor。

优势与劣势

使用 Skype 短信时,可观察到以下劣势:

  • SMS 需要花钱
  • 不能向自己发送消息,要获取消息,需要有另一个 Skype 帐户。
  • 您的电话必须支持移动版的 Skype。如果使用计算机接收消息,此劣势不复存在。

此方法具有以下优势:

  • 在实时模式下发送信号
  • 目前不能被任何东西所替代的功能。这一点甚至不是优势,仅仅是事实。

总结

我们学习了如何通过 Skype 发送短信和一般消息。因此,我们在终端上获得了一个可通知我们当前事件的接口,该接口可能并不是最便捷的,但必定是不可缺少的。下一步做什么?例如,Skype 允许发送和接收消息…

由MetaQuotes Software Corp.从英文翻译成
原始文章: https://www.mql5.com/en/articles/1454

附加的文件 |
SkypeExample.mq4 (0.71 KB)
SkypeLib.dll (56 KB)
SkypeLib.zip (2.36 KB)
测试可视化:交易记录 测试可视化:交易记录

本文描述了在可视化测试时便捷查看交易记录的可能性。

三色指标和最大程度简化写入指标的一些方法 三色指标和最大程度简化写入指标的一些方法

作者在本文中详述了一些提高指标对于可视化交易的信息价值的方法。作者分析了三色指标以及使用了其他时间框架内的数据构建的指标的实现方式,然后继续详述指标库,具体可参见文章 "延迟最小的有效平均算法:在指标中的使用"

日内交易中的时间转换原则 日内交易中的时间转换原则

本文包含了允许接收更加平稳的价格流的操作时间概念。也包含了带时间转换裕度的已更改移动平均线的代码。

将指标代码转移至 Expert Advisor 代码。指标结构 将指标代码转移至 Expert Advisor 代码。指标结构

本文详细介绍将指标代码转移至 Expert Advisor 代码的方式,并详细介绍编写 Expert Advisor 的过程,在此过程中,不调用任何自定义指标,且整个程序代码用于计算 Expert Advisor 中的必要指标值。本文介绍了指标结构的总体方案、Expert Advisor 中指标缓冲区的模拟以及函数 IndicatorCounted() 的替代项。本文面向拥有使用 MQL4 语言进行编程的经验的读者。