Enviar mensajes desde un Asesor Experto mediante Skype

Alexey Koshevoy | 15 marzo, 2016

Introducción

Skype es un programa de mensajería de texto, voz y vídeo, que además permite hacer llamadas telefónicas a través de Internet. La mayor ventaja de Skype, en comparación con otros programas del mismo tipo, es su acceso a las redes de los operadores de telefonía móvil. Por lo tanto, se pueden hacer llamadas a teléfonos móviles reales, enviar mensajes SMS, etc. Existe también una versión de Skype para teléfonos móviles. Este programa permite ahorrar el dinero que se gasta en los SMS, ya que los mensaje normales entre los usuarios del programa son totalmente gratuitos. Sin embargo, el teléfono tiene que disponer de un sistema operativo. Así que ya es posible estar completamente conectado al móvil si hace falta. Y cada vez hay más personas que usan este recurso hoy en día.


¿Quién puede necesitarlo y por qué?

Un trader no puede ni debe estar sentado permanentemente en frente del terminal de trading y observar como se llevan a cabo las operaciones. Sin embargo, estaría bien que le trader pueda recibir señales de vez en cuando para recibir informaciones acerca de las acciones del Asesor Experto o de la situación del mercado en momentos concretos. ¿Por qué no recibir esta información en el teléfono móvil?


¿Qué tipo de información sería útil recibir?

Se pueden dividir la informaciones que se reciben mediante mensaje en el teléfono móvil en dos grupos:

  1. los datos actuales que no tienen ninguna influencia y son prácticamente iguales a los del archivo de registro;
  2. informaciones útiles que puede aprovechar el trader en el momento exacto de su llegada.

Veamos dos ejemplos de datos actuales:

Informaciones útiles:

Está claro que esta lista no es exhaustiva y los posibles eventos van mucho más allá que este artículo. Cada trader decidirá por sí mismo cuál va a ser el contenido del mensaje. Lo más importante es darse cuenta que este aspecto es muy útil.

¿Cómo funciona esto en Skype?

¿Cómo hacerlo desde el Asesor Experto?

He encontrado dos métodos para hacer esto, y ambos requieren el uso de las DLL:

  1. Primero tenemos que preparar con antelación un archivo de macros, es decir, un archivo que al iniciarse controlará el teclado y el ratón. Por lo tanto, mediante una secuencia de acciones tenemos que activar Skype, encontrar el elemento de envío de mensajes SMS en el menú, luego marcar el número de teléfono en la ventana correspondiente y pegar desde el portapapeles el mensaje de texto escrito inicialmente en el Asesor Experto. Puede entrenarse y perfeccionar las operaciones con antelación. De este modo, hemos preparado un archivo asociado a un documento y que se puede ejecutar como una aplicación corriente. Por cierto, hay muchas aplicaciones que graban y reproducen archivos de macros, por lo que no vamos a abordar ningún programa concreto en este artículo.

    Después tenemos que desarrollar una DLL que funcionará del siguiente modo. Lo primero que hace es colocar el texto del Asesor Experto en el portapapeles. Lo segundo es lanzar el archivo de macros predefinido. Si todo está correctamente configurado y todas las ventanas y botones aparecen en el lugar correspondiente no tiene que haber ningún problema y se enviará el mensaje.

    Sin embargo, este método me parece un poco extraño. La intuición me dice que si empezamos a tener este tipo de percepción es mejor buscar una solución mejor y abandonar esta idea por completo. Entonces, me surgió una nueva idea: ¿Puede contar Skype con una API? Bueno, he encontrado la API y la interfaz ActiveX en su página web. ¡Genial! Vamos a ver otra forma de trabajar con Skype desde un Asesor Experto.

  2. Es prácticamente lo mismo. Se pasará el número de teléfono y el mensaje a enviar desde el Asesor Experto a la DLL, que enviará el mensaje a través del objeto COM de Skype.

La implementación del segundo método

Vamos a empezar con la DLL. La mayor parte del trabajo consiste en preparar la DLL para interactuar con el Asesor Experto. En primer lugar, escribimos una librería que funcione cuando se le llama desde varios Asesores Expertos. Desafortunadamente, no es suficiente con sólo escribir una función y llamarla. Estamos usando ActiveX, por lo que es recomendable crear un proceso independiente y llevar a cabo todo el trabajo en él. La herramienta estándar análoga para las funciones Mutex no nos puede ayudar. Habrán fallos que no se pueden detectar. Así que llevaremos a cabo la secuencia de llamadas mediante el sistema de mensajería del usuario.

Código fuente de la 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);
  }

El archivo DEF

LIBRARY SkypeLib
 
EXPORTS SendSkypeSMS
        SendSkypeMessage

El Asesor Experto de la prueba

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

El asesor Experto es muy sencillo, su principal objetivo es enviar un SMS y un mensaje ordinario mediante la DLL que hemos escrito. Actúa en la función de inicialización, así que podemos utilizarlo durante los fines de semana.

Instalación de Skype

Se puede descargar la aplicación desde http://www.skype.com/. Se recomienda instalar la última versión del programa, ya que las versiones anteriores no son compatibles con la interfaz COM, sólo disponen de una API. Desafortunadamente, la API no admite el envío de mensajes SMS.

Ya está instalado Skype. Ahora tenemos que descargar la librería COM. Está disponible en https://developer.skype.com/, en la zona de descargas. Compruebe el saldo disponible en su cuenta para el envío de mensajes SMS. Si no es suficiente, se puede recargar por Internet. No se pueden enviar mensajes SMS si no hay saldo en la cuenta, pero sí que se pueden enviar mensajes normales sin ningún problema.


Para que el terminal pueda acceder a la API de Skype, hay que registrarlo. Puede comprobar si se puede trabajar con la API a través de Herramientas->Opciones->Privacidad->Gestionar el acceso de oros programas a Skype. Será algo como esto:




Se registrará el terminal con el primer intento de acceder a la librería. Se puede hacer esto manualmente. En la primera instalación de la librería hay que esperar el envío de un mensaje para confirmar el permiso de uso de la API de Skype. Veremos el siguiente mensaje en Skype:




Después de la confirmación, comenzará el sistema a funcionar de modo automático.


Instalación de SkypeLib

Para instalar la librería SkypeLib.dll, hace falta copiarla en la carpeta experts/libraries que se encuentra en el directorio del terminal. También hay que copiar la librería Skype4COM.dll en esta misma carpeta. Ahora tenemos que configurar el terminal para poder trabajar con la DLL. Para ello, compruebe el campo "Allow DLL imports" (permitir la importación de DLL) en la sección "Safety" (seguridad) al añadir el Asesor Experto, como se muestra en la siguiente imagen:



Ahora podemos usar la librería.

Algunos detalles importantes

Después de varias pruebas he observado algunos "matices". Por ejemplo, hay que tener en cuenta que si tiene bastante saldo en su cuenta y envía un SMS a un número incorrecto, no se notificará ningún error, la acción se hará correctamente y se mostrará el mensaje de estado "Enviando...". De allí la importancia de configurar correctamente las entradas de la función. También es muy importante usar la versión 3.0 de Skype (o posteriores).

Puede ocurrir (aunque muy raramente) que el objeto COM no se haya inicializado y que no se envíe ningún mensaje. Esto sólo puede solucionarse instalando Skype de nuevo. La interfaz externa es bastante nueva y no está exenta de fallos, por lo que puedan haber algunas molestias. Que yo recuerde, sólo me ocurrió dos veces. Esperemos que las últimas versiones sean más estables.

También hay que tener en cuenta que SkypeLib.dll pueda necesitar otras librerías para su funcionamiento. El problema es particularmente agudo después del lanzamiento del primer Service Pack para Visual Studio 2005. La mejor manera de resolver este problema es crear un archivo de configuración. Incluirá todas las librerías necesarias. También puede incluir Skype4COM.dll.

Los archivos adjuntos a este artículo


Ventajas e inconvenientes

Se han observado los siguientes inconvenientes con la utilización de mensajes SMS con Skype:

Este método tiene las siguientes ventajas:

Conclusiones

Hemos aprendido cómo enviar mensajes SMS y mensajes normales mediante Skype. De modo que hemos conseguido una interfaz, que tal vez no sea la más conveniente, pero seguramente indispensable, para informarnos sobre lo que ocurre en el terminal. ¿Cuál es la la siguiente etapa? Por ejemplo, Skype permite ENVIAR y RECIBIR mensajes...