English 中文 Español Deutsch 日本語 Português
Отправка SMS из торгового советника через Skype

Отправка SMS из торгового советника через Skype

MetaTrader 4Примеры | 20 июня 2007, 02:49
2 837 13
Alexey Koshevoy
Alexey Koshevoy

Введение

Skype – телекоммуникационная программа, которая, кроме обычных чатов, позволяет вести телефонные разговоры по Интернет. Одним из наиболее значимых преимуществ Skype перед другими программами подобного плана является шлюз на реальных операторов мобильной связи. Соответственно можно звонить с компьютера на реальный мобильный телефон, отсылать SMS и так далее. Так же существует версия Skype для мобильных телефонов, можно экономить на SMS, потому что отправка обычных сообщений внутри программы совершенно бесплатна. Правда, мобильный телефон должен работать под управлением операционной системы. В общем, при желании, можно быть полностью мобильным, чем в последнее время и пользуется все большее количество людей.


Кому и зачем это надо?

Трейдер не всегда может и должен сидеть за торговым терминалом, наблюдать за тем, как идет торговля. Однако, было бы неплохо иметь возможность иногда получать сигналы о действиях эксперта или о состоянии рынка в определенные моменты времени. Почему бы не получать данную информацию на мобильный телефон?


Какую информацию было бы полезно получать?

Информацию, которую можно получать посредством сообщений на телефон можно разделить на два класса:

  1. текущая, которая ни на что не влияет и практически дублируют логфайл;
  2. полезная, которая будет реально полезна для трейдера именно в момент поступления.

Рассмотрим примеры текущей информации:

  • Состояние ордеров. Когда открылся, по какой цене, в каком направлении, значения стопов. Когда закрылся, по какой причине, в убыток или с прибылью;
  • Различные состояния на рынке. Например, пересечения индикаторов, смена направления тренда.

Полезная информация:

  • Отчет об ошибках. Все программисты люди и иногда возникают неприятные ситуации при неправильной работе эксперта. Было бы неплохо знать, при каких условиях возникают ошибки и привело ли это к фатальной остановке. Это, конечно же, сработает, если логика эксперта позволяет отслеживать ошибки;
  • Состояние работы эксперта. Например, эксперт настроен так, чтобы отсылать сообщение о состоянии работоспособности каждый час, а вы в это время находитесь в рабочей поездке. И вот сообщение не пришло в назначенный час. Могло случиться все, что угодно, от разрыва соединения с Интернет до полного выключения электроэнергии. Было бы целесообразно попросить коллегу или жену, если терминал работает дома, выяснить причину и настроить все как было, а не ждать неделю в неведении. Конечно же, такое разделение носит условный характер, да и список возможных событий в данной статье не исчерпывается. Каждый трейдер сам сможет решить, какое содержание должно иметь сообщение. Главное осознать полезность данной функции.


Как это работает в Skype?

  • SMS сообщения. Функция, естественно, платная. Все выглядит как обычно: набираете номер абонента, сообщение и нажимаете кнопку отправить.
  • Обычные сообщения. Совершенно бесплатные. Просто выбираете пользователя, пишите сообщение и нажимаете кнопку отправить.


Как это сделать из эксперта?

Я нашел два способа и оба используют DLL:

  1. Предварительно подготавливаем макрофайл, то есть файл, при запуске которого будет перехвачено управление клавиатурой и мышью компьютера. Таким образом, с помощью последовательности действий нам нужно активировать Skype, найти в меню пункт отправки SMS, затем в появившемся окне набрать номер абонента и вставить из буфера обмена текстовое сообщение, которое заранее было туда вставлено из эксперта. Потренироваться и отточить действия можно заранее. Таким образом, мы подготовили файл, который является ассоциированным документом и может быть запущен как обычное приложение. Кстати, приложений делающих запись и воспроизведение макрофайлов существует большое множество, поэтому в статье конкретные экземпляры рассматриваться не будут.

    Дальше нам нужно разработать DLL, работа которой будет заключаться в двух небольших действиях. Первое, – это поместить переданный из эксперта текст в буфер обмена и, второе, – запустить заранее заданный макрофайл. Если все заранее хорошо настроено и все окна и кнопки буду появляться на своих местах, то проблем быть не должно, сообщение отправится.

    Однако, это жутковатый способ. Интуиция мне подсказывала, что если мозги начинают выдумывать что-то подобное, значит надо искать более элегантное решение или отказаться от этой идеи вообще. И тут проскользнула мысль – а может быть Skype имеет API? И точно, на сайте есть и голый API и ActiveX интерфейс. Супер! Рассмотрим второй способ работы со Skype из эксперта.

  2. Смысл тот же. Из эксперта в DLL передается номер абонента и текст, который должен быть отправлен, а DLL уже выполняет отправку посредством COM объекта Skype.


Реализация второго способа.

Начнем с DLL. Основную часть работы будет занимать подготовка DLL для взаимодействия с экспертом. Во-первых, напишем библиотеку, которая будет работать при обращении к ней из нескольких экспертов. К сожалению, будет недостаточно просто написать функцию и вызывать ее. Мы используем ActiveX, поэтому желательно создать для него отдельный поток и проводить всю работу в нем. Стандартное средство распараллеливания работы функций Mutex не поможет. Будут наблюдаться креши, причем не отслеживаемые. Реализуем последовательность обращений через систему пользовательских сообщений.


Исходный текст библиотеки 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
 
// Подключаем библиотеку Skype4COM.dll, предварительно выкачанную 
// с сайта разработчиков для Skype – http://developers.skype.com/
#import "Skype4COM.dll" rename("CreateEvent","CreatePluginEvent"), 
                        rename("SendMessage","SendChatMessage")
 
 
#define MT4_EXPFUNC __declspec(dllexport)
 
// Объявляем коды сообщений для наших функций.
#define WM_PROC_SENDSKYPESMS WM_USER + 01
#define WM_PROC_SENDSKYPEMESSAGE WM_USER + 02
 
// Переменные для потока, которые мы будем использовать для 
// отправки сообщений
HANDLE hUserThread;
DWORD ThreadId;
 
// Структуры для хранения параметров функций
// 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;
      };
    // Инициализируем COM
    CoInitialize(NULL);
    while(GetMessage(&msg, 0, 0, 0))
      {
        if(msg.message == WM_QUIT)
          {
            break;
          }
        // Обработчик сообщения WM_PROC_SENDSKYPESMS
        else 
            if(msg.message == WM_PROC_SENDSKYPESMS)
              {
                fcpSendSkypeSMS* fcp = (fcpSendSkypeSMS*)msg.wParam;
                hEvent = (HANDLE)msg.lParam;
                try
                  {
                    // Инициализируем Skype 
                    SKYPE4COMLib::ISkypePtr pSkype(__uuidof(SKYPE4COMLib::Skype));
                    // Соединяемся со Skype. 6 – это версия протокола
                    HRESULT hr=pSkype->Attach(6,VARIANT_TRUE);
                    // Если все нормально, то начинаем отправку сообщения
                    if(!FAILED(hr))
                      {    
                        try
                          {
                            fcp->ExitCode = 1;
                            // Пытаемся отослать SMS
                            pSkype->SendSms(fcp->UserNum,fcp->Message,"");
                          }
                        catch(...)
                          {
                            fcp->ExitCode=-1;
                          }
                      }
                    // Деинициализируем Skype
                    pSkype = NULL;
                  }
                catch(...)
                  {
                    //Ошибку обрабатываем здесь
                  }
                // Отпускаем событие
                SetEvent(hEvent);
              }
            // Обработчик сообщения WM_PROC_SENDSKYPEMESSAGE
            else 
                if(msg.message == WM_PROC_SENDSKYPEMESSAGE)
                  {
                    fcpSendSkypeMessage* fcp = 
                                   (fcpSendSkypeMessage*)msg.wParam;
                    hEvent = (HANDLE)msg.lParam;
        
                    try
                      {
                        // Инициализируем Skype 
                        SKYPE4COMLib::ISkypePtr pSkype(__uuidof
                                              (SKYPE4COMLib::Skype));
                        // Соединяемся со Skype. 6 – это версия протокола
                        HRESULT hr=pSkype->Attach(6,VARIANT_TRUE);
                        // Если все нормально, то начинаем отправку сообщения
                        if(!FAILED(hr))
                          {
                            try
                              {
                                fcp->ExitCode = 1;
                                // Пытаемся отослать сообщение
                                pSkype->SendChatMessage(fcp->UserName,
                                                        fcp->Message);
                              }
                            catch(...)
                              {
                                fcp->ExitCode=-1;
                                MessageBeep(0);
                              }
                          }
                        // Деинициализируем Skype
                        pSkype = NULL;
                      }
                    catch(...)
                      {
                        //Ошибку обрабатываем здесь
                      }
  
                    // Отпускаем событие
                    SetEvent(hEvent);
                  }
              };
            // Деинициализируем COM
            CoUninitialize();
            return 0;
          }
 
//Инициализация библиотеки.
//+------------------------------------------------------------------+
//| DLL entry                                                        |
//+------------------------------------------------------------------+
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
                      LPVOID lpReserved)
  {
    if(ul_reason_for_call == DLL_PROCESS_ATTACH)
      {
        // Создаем поток и привязываем к нему адрес процедуры обработчика
        hUserThread = CreateThread(NULL, NULL, ThreadProc, NULL, 0, &ThreadId);
        if(!hUserThread)
          {
            // Обработка ошибки, если поток не будет создан
          };
      } 
    else 
        if(ul_reason_for_call == DLL_PROCESS_DETACH)
          {
            // Уничтожаем поток при выходе из библиотеки
            CloseHandle(hUserThread);
          }
    return(TRUE);
  }
 
MT4_EXPFUNC bool __stdcall SendSkypeSMS(int &ExCode,char* sUserNum, 
                                        char* sMessage)
  {
    //Объявляем структуру параметров функции
    fcpSendSkypeSMS* fcp;
    //Объявляем событие
    HANDLE hEvent;
    //Результат работы функции по умолчанию false
    bool Result = false;
 
    // Выделяем память под структуру и инициализируем ее
    fcp = new fcpSendSkypeSMS();
    memset(fcp, 0, sizeof(fcpSendSkypeSMS));
 
    // Заполняем структуру
    //По умолчанию код окончания работы функции – ошибка.
    fcp->ExitCode = -1;
    fcp->UserNum = sUserNum;
    fcp->Message = sMessage;
 
    // Создаем событие
    hEvent = CreateEvent(NULL,FALSE,FALSE, NULL);
    // Вызывает событие WM_PROC_SENDSKYPESMS, передаем в процедуру 
    // обработки адрес структуры с данными
    PostThreadMessage(ThreadId, WM_PROC_SENDSKYPESMS, (WPARAM)fcp,
                      (LPARAM)hEvent);
    if(WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE))
      {
        
        Result = true;
      } 
    else
      {
        // Если была ошибка при отработке сообщения, то функция 
        // вернет значение false
        return(Result);
      };
    // Присваиваем переменной код отработки функции
    ExCode = fcp->ExitCode;
    if(ExCode == -1) 
        Result = false;
    // Освобождаем память и переменные и выходим
    delete fcp;
    CloseHandle(hEvent);
    return(Result);
  }
 
MT4_EXPFUNC bool __stdcall SendSkypeMessage(int &ExCode,char* sUserName, 
                                            char* sMessage)
  {
    //Объявляем структуру параметров функции
    fcpSendSkypeMessage* fcp;
    //Объявляем событие
    HANDLE hEvent;
    //Результат работы функции по умолчанию false
    bool Result = false;
 
    // Выделяем память под структуру и инициализируем ее
    fcp = new fcpSendSkypeMessage();
    memset(fcp, 0, sizeof(fcpSendSkypeMessage));
 
    // Заполняем структуру
    //По умолчанию код окончания работы функции – ошибка.
    fcp->ExitCode = -1;
    fcp->UserName = sUserName;
    fcp->Message = sMessage;
 
    // Создаем событие
    hEvent = CreateEvent(NULL, FALSE,FALSE, NULL);
    // Вызывает событие WM_PROC_SENDSKYPESMS, передаем в процедуру 
    // обработки адрес структуры с данными
    PostThreadMessage(ThreadId, WM_PROC_SENDSKYPEMESSAGE, (WPARAM)fcp,
                      (LPARAM)hEvent);
    if(WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE))
      {
        Result = true;
      } 
    else
      {
        // Если была ошибка при отработке сообщения, то функция 
        // вернет значение false
        return(Result);
      };
    // Присваиваем переменной код отработки функции
    ExCode = fcp->ExitCode;
    if(ExCode == -1) 
        Result = false;
    // Освобождаем память и переменные и выходим
    delete fcp;
    CloseHandle(hEvent);
    return(Result);
  }


DEF файл

LIBRARY SkypeLib
 
EXPORTS SendSkypeSMS
        SendSkypeMessage


Торговый советник для тестирования

//+------------------------------------------------------------------+
//|                                              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("Отправляем сообщение...");
   Alert(SendSkypeMessage(ExCode, "skype.account.name", "Skype message test"));
   if(ExCode[0] == -1)
       Alert("Ошибка отправки сообщения");
   else 
       Alert("Сообщение отправлено");
   Alert("Отправляем SMS сообщение...");
   Alert(SendSkypeSMS(ExCode, "+1234567890", "Skype sms test"));
   if(ExCode[0] == -1)
       Alert("Ошибка отправки SMS сообщения");
   else
       Alert("SMS сообщение отправлено");
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   return(0);
  }
//+------------------------------------------------------------------+

Эксперт прост, его главная цель – отправить SMS сообщение и обычное сообщение через написанную нами библиотеку. Он проделывает все действия в функции инициализации, поэтому тестировать можно и в выходные.


Установка Skype

Скачать можно на http://www.skype.com/. Желательно установить последнюю версию программы, потому что в предыдущих версиях COM интерфейс не поддерживается, есть только API. Но, к сожалению API не поддерживает отправку SMS сообщений.

Итак, Skype установлен. Теперь нам нужно выкачать COM библиотеку. Находится она на сайте для разработчиков https://developer.skype.com/ в разделе Downloads. Проверяем наличие финансов на счету, которые будут использоваться для отправки SMS. Если таковых нет, то счет можно пополнить через Интернет из программы. При отсутствии денег на счету отправлять SMS не получится, однако, обычные сообщения без проблем.

Для того чтобы терминал имел доступ к Skype API, нужно его зарегистрировать. Проверить наличие разрешения для работы с API можно через меню Tools->Options->Privacy->Manage other programs access to Skype. Должно выглядеть примерно так:

Регистрируется терминал при первой попытке воспользоваться библиотекой. Вручную сделать этого нельзя. Поэтому при первой установке библиотеки следует дождаться отправки сообщения, чтобы подтвердить разрешение на пользование Skype API. Skype выдаст следующий диалог:

После подтверждения система начинает работать в автоматическом режиме.


Установка библиотеки SkypeLib

Для того чтобы установить библиотеку SkypeLib.dll, нужно скопировать ее в папку experts/libraries в каталоге терминала. Также туда нужно скопировать библиотеку Skype4COM.dll. Теперь нужно настроить терминал для работы с DLL. Для этого при установке эксперта в разделе Safety отмечаем галочкой пункт Allow DLL imports, как это показано ниже:

Теперь можно пользоваться библиотекой.


Некоторые важные моменты

После небольшого опыта тестирования и внедрения были замечены небольшие тонкости. Нужно учитывать, что если у вас на счету достаточно денег и вы отправили SMS сообщение на несуществующий номер, то ошибки не будет, функция отработает успешно, а статус сообщения будет установлен в состояние “sending...”. Поэтому нужно четко настраивать входные параметры функций. Следить нужно и за тем, чтобы версия Skype была не ниже 3.0.

Очень редко бывает, что COM объект не инициализирован, и сообщения отправляться не будут. Помогает только переустановка Skype. Интерфейс внешнего взаимодействия относительно новый, не без ошибок, поэтому случается такой неприятный момент. На моей памяти было только два таких случая. Будем надеяться, что в более поздние версии будут работать стабильнее.

Так же следует отметить, что для работы SkypeLib.dll могут потребоваться дополнительные библиотеки. Особенно остро вопрос стоит после выхода первого service pack к Visual Studio 2005. Лучшим выходом будет создание setup файла. Туда автоматически будут включены все необходимые библиотеки. Так же можно включить и файл Skype4COM.dll.


Прикрепленные к статье файлы

  • SkypeLib.dll - библиотека откомпилирована на Visual C++ 6.0. Не нуждается в дополнительных файлах, кроме Skype4COM.dll.
  • SkypeLib.zip - исходный код библиотеки.
  • SkypeExample.mq4 - торговый советник для тестирования возможностей библиотеки.


Достоинства и недостатки.

Недостатки использования Skype SMS

  • SMS стоят денег
  • Нельзя отправить сообщение самому себе, нужно иметь другой Skype account для получения сообщений.
  • Телефон должен поддерживать мобильную версию Skype. При использовании компьютера на прием сообщений этот недостаток отпадает.

Достоинства данного метода:

  • Оповещение в реальном времени
  • На данный момент ничем не заменяемая функция. Это не совсем достоинство, скорее факт.


Выводы

Мы научились отправлять SMS сообщения и обычные сообщения через Skype. Таким образом, мы получили, может быть, не самый удобный, но незаменимый интерфейс для оповещения о текущих событиях в терминале. Что дальше? А ведь в Skype можно не только отправлять сообщения, но и получать...

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/1454

Прикрепленные файлы |
SkypeExample.mq4 (0.71 KB)
SkypeLib.dll (56 KB)
SkypeLib.zip (2.36 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (13)
[Удален] | 28 мар. 2008 в 11:37
AlexeyKoshevoy:
Вариант с уведомлением через гейты мобильных операторов рассматривался. Однако столкнулись с несколькими проблемами, которые зависят от операторов. Некоторые запрещают посылать сообщения часто, бывает что сообщения доходят очень долго (было такое что сообщения высыпались через 4 часа после отправки) Ну и самое неудобное - нужно затачивать систему под конкретного оператора, которым пользуется клиент. А так как клиенты пользуются разными операторами, то и время разработки возрастает, поэтому решили пользоваться универсальным Skype. Однако не могу с Вами не согласиться в том, что метод оправки сообщения через гейт оператора гораздо проще в исполнении и не требует написания внешних библиотек.

Алексей, вы пишите скрипты под заказ? Есть предложение.
Alexander
Alexander | 13 нояб. 2008 в 23:15
chv:
Алексей, Вы не рассматривали вариант уведомления на моб. телефон через e-mail и MQL функцию void SendMail( string subject, string some_text)? У каждого сотового оператора есть mail-gate, т.е. персональный почтовый адрес, сообщения с которого идёт на телефон как sms. Я, например, из своего PHP кода веб страниц отправляю email на условно адрес 89272536805@mgsm-v.ru, и они идут мне как sms на телефон.
В эксперте нужен параметр string MailSmsAddress, который и будет таким адресом, на него эксперт будет слать важные уведомления.
Настроить отправку почты с терминала можно за пару минут, стоить это будет только интернет-трафик, который стоит копейки или вообще анлим.

полностью согласен. очень удобно получать отчеты на мобильный каждые 15 мин =)

но я бы предпочел написать для этого dll со всем необходимым функционалом

Evgeniy Trofimov
Evgeniy Trofimov | 15 апр. 2009 в 04:59
chv, Не у каждого оператора есть "mail-gate". Вот у этого оператора где он? http://omsk.tele2.ru/
Vovan
Vovan | 24 февр. 2010 в 11:44
Скажите, пожалуйста, а можно сделать точно такую же реализацию, но не для Skype'а, а для Mail.ru агента? У него есть бесплатная отправка SMS даже на те операторы, которые не имеют mail-gate'ов. Заранее, большое спасибо!
[Удален] | 11 янв. 2012 в 06:03
Помогите пожалуйста. Сообщения в skype отправляются советником, а SMS'ки на телефон - нет. Пишет шибка отправки сообщения' в чём может быть причина ? Деньги на скайпе есть. Вручную SMS'ки со скайпа на телефон доходят, советником - нет.
Прогнозирование цен с помощью нейронных сетей Прогнозирование цен с помощью нейронных сетей
Многие трейдеры говорят о нейронных сетях, но что это такое и на что они в реальности способны - мало кто представляет. Данная статья немного приоткрывает дверь в мир искуственного интеллекта. В ней рассказывается о том, как нужно правильно подготавливать данные для сети, а также приводится пример прогнозирования средствами программы Matlab.
Визуализация тестирования. История сделок. Визуализация тестирования. История сделок.
В клиентском терминале MetaTrader 4 появилась функция визуализации тестирования. Она позволяет контролировать процесс тестирования экспертов на качественно новом уровне. Теперь трейдер-программист может наблюдать за каждым действием своего эксперта, проверяя его работу на истории!
Практическое использование Виртуального Частного Сервера (VPS) для автоторговли Практическое использование Виртуального Частного Сервера (VPS) для автоторговли
Автоторговля с помощью VPS. Данная статья предназначена исключительно для автотрейдеров и сторонников автоторговли.
Язык MQL 4 для "чайников". Первое знакомство Язык MQL 4 для "чайников". Первое знакомство
Эта серия статей рассчитана на трейдеров, которые ничего не знают о программировании, но хотят изучить язык MQL 4 максимально быстро с минимальными усилиями и затратами времени. Если вы боитесь таких словосочетаний, как "объектная ориентация" или "трёхмерный массив", эта статья - то что вам нужно. Уроки рассчитаны на максимально быстрый результат. Кроме того, материал будет подаваться в доступной форме. Мы не будем сильно углубляться в теорию, зато практическую пользу вы получите уже на первом уроке.