Descargar MetaTrader 5

Comunicándonos con Meta Trader 5 usando conexiones designadas sin utilizar DLL

8 mayo 2014, 13:25
MetaQuotes Software Corp.
0
560

Introducción

Muchos desarrolladores se enfrentan con el mismo problema: cómo llegar al módulo del terminal sin utilizar DLL poco seguras.

Uno de los métodos más sencillos y seguros es utilizar conexiones designadas que funcionan como operaciones de archivo normales. Estos nos permiten organizar la comunicación cliente-servidor entre procesadores entre los programas. Aunque ya hay un artículo publicado sobre este tema (Una solución libre de DLL para la comunicación entre los terminales de Meta Trader 5 usando conexiones designadas) que muestra cómo habilitar el acceso a las DLL, usaremos las características estándar y seguras del terminal de cliente.

Puede encontrar más información sobre las conexiones designadas en la librería MSDN, pero nos iremos a ejemplos prácticos en C++ y MQL5. Implementaremos un servidor, un cliente y un intercambio de datos entre los mismos y luego calificaremos el rendimiento.


Implementación del servidor

Vamos a crear el código de un simple servidor en C++. Un script del terminal conectará con este servidor e intercambiará con datos con él. El núcleo del servidor tiene el siguiente conjunto de funciones de WinAPI:

Una vez que se abre una conexión designada esta devuelve un controlador de archivo que puede usarse para operaciones de lectura/escritura de archivos habituales. Como resultado, tenemos un mecanismo muy simple que no requiere ningún conocimiento especial en operaciones de red.

Las conexiones designadas tienen una característica distintiva: pueden ser locales y de red. Es decir, es fácil implementar un servidor remoto que acepte conexiones de red de los terminales de cliente.

Este es un simple ejemplo de creación de un servidor local como canal full-duplex que funciona en modo de intercambio de bytes:

//--- open 
CPipeManager manager;

if(!manager.Create(L"\\\\.\\pipe\\MQL5.Pipe.Server"))
   return(-1);


//+------------------------------------------------------------------+
//| Create named pipe                                                |
//+------------------------------------------------------------------+
bool CPipeManager::Create(LPCWSTR pipename)
  {
//--- check parameters
   if(!pipename || *pipename==0) return(false);
//--- close old
   Close();
//--- create named pipe
   m_handle=CreateNamedPipe(pipename,PIPE_ACCESS_DUPLEX,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                            PIPE_UNLIMITED_INSTANCES,256*1024,256*1024,1000,NULL);

   if(m_handle==INVALID_HANDLE_VALUE)
     {
      wprintf(L"Creating pipe '%s' failed\n",pipename);
      return(false);
     }
//--- ok
   wprintf(L"Pipe '%s' created\n",pipename);
   return(true);
  }

Para obtener una conexión de cliente tenemos que usar la función ConnectNamedPipe:

//+------------------------------------------------------------------+
//| Connect client                                                   |
//+------------------------------------------------------------------+
bool CPipeManager::ConnectClient(void)
  {
//--- pipe exists?
   if(m_handle==INVALID_HANDLE_VALUE) return(false);
//--- connected?
   if(!m_connected)
     {
      //--- connect
      if(ConnectNamedPipe(m_handle,NULL)==0)
        {
         //--- client already connected before ConnectNamedPipe?
         if(GetLastError()!=ERROR_PIPE_CONNECTED)
            return(false);
         //--- ok
        }
      m_connected=true;
     }
//---
   return(true);
  }

El intercambio de datos se organiza usando 4 funciones simples:

  • CPipeManager::Send(void *data,size_t data_size)
  • CPipeManager::Read(void *data,size_t data_size)
  • CPipeManager::SendString(LPCSTR command)
  • CPipeManager::ReadString(LPSTR answer,size_t answer_maxlen)

Estas nos permiten enviar/recibir datos binarios o como cadenas de texto ANSI en modo compatible con MQL5. Además, como CFilePipe en MQL5 abre un archivo en modo ANSI por defecto, los strings son convertidos automáticamente en formato Unicode al recibir y enviar. Si su programa MQL5 abre un archivo en modo Unicode (FILE_UNICODE), entonces puede intercambiar strings Unicode (con la firma inicial BOM).


Implementación del cliente

Escribiremos nuestro cliente en MQL5. Este podrá realizar operaciones de archivo de forma habitual usando la clase CFilePipe de la librería estándar. Esta clase es casi idéntica a CFileBin, pero contiene una importante verificación de la disponibilidad de los datos en un archivo virtual antes de leerlos.

//+------------------------------------------------------------------+
//| Wait for incoming data                                           |
//+------------------------------------------------------------------+
bool CFilePipe::WaitForRead(const ulong size)
  {
//--- check handle and stop flag
   while(m_handle!=INVALID_HANDLE && !IsStopped())
     {
      //--- enough data?
      if(FileSize(m_handle)>=size)
         return(true);
      //--- wait a little
      Sleep(1);
     }
//--- failure
   return(false);
  }

//+------------------------------------------------------------------+
//| Read an array of variables of double type                        |
//+------------------------------------------------------------------+
uint CFilePipe::ReadDoubleArray(double &array[],const int start_item,const int items_count)
  {
//--- calculate size
   uint size=ArraySize(array);
   if(items_count!=WHOLE_ARRAY) size=items_count;
//--- check for data
   if(WaitForRead(size*sizeof(double)))
      return FileReadArray(m_handle,array,start_item,items_count);
//--- failure
   return(0);
  }

Las conexiones designadas tienen diferencias importantes en la implementación de sus modos local y en red. Con dicha verificación, las operaciones en modo de red siempre devolverán un error de lectura al enviar grandes cantidades de datos (más de 64 K).

Vamos a conectar con el servidor con dos comprobaciones: bien a un ordenador remoto llamado 'RemoteServerName' o a una máquina local.

void OnStart()
  {
//--- wait for pipe server
   while(!IsStopped())
     {
      if(ExtPipe.Open("\\\\RemoteServerName\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN)!=INVALID_HANDLE) break;
      if(ExtPipe.Open("\\\\.\\pipe\\MQL5.Pipe.Server",FILE_READ|FILE_WRITE|FILE_BIN)!=INVALID_HANDLE) break;
      Sleep(250);
     }
   Print("Client: pipe opened");


Intercambio de datos

Después de la conexión con éxito vamos a enviar una cadena de texto con la información de identificación al servidor. La cadena de Unicode será convertida de forma automática a ANSI, ya que el archivo se ha abierto en modo ANSI.

//--- send welcome message
   if(!ExtPipe.WriteString(__FILE__+" on MQL5 build "+IntegerToString(__MQ5BUILD__)))
     {
      Print("Client: sending welcome message failed");
      return;
     }

Como respuesta, el servidor enviará su string "Hello from pipe server" y el entero 1234567890. Una vez más el cliente enviará el string "Test string" y el entero 1234567890.

//--- read data from server
   string        str;
   int           value=0;

   if(!ExtPipe.ReadString(str))
     {
      Print("Client: reading string failed");
      return;
     }
   Print("Server: ",str," received");

   if(!ExtPipe.ReadInteger(value))
     {
      Print("Client: reading integer failed");
      return;
     }
   Print("Server: ",value," received");
//--- send data to server
   if(!ExtPipe.WriteString("Test string"))
     {
      Print("Client: sending string failed");
      return;
     }

   if(!ExtPipe.WriteInteger(value))
     {
      Print("Client: sending integer failed");
      return;
     }

Ok, hemos terminado con el intercambio de datos simple. Ahora es el momento de probar el rendimiento.


Prueba del rendimiento

Como prueba que es, enviaremos 1 gigabyte de datos como matriz de tipo doble en bloques de 8 megabytes desde el servidor al cliente, y luego comprobaremos si los bloques son correctos y mediremos el ratio de transferencia.

Este es el código en el servidor de C++:

//--- benchmark
   double  volume=0.0;
   double *buffer=new double[1024*1024];   // 8 Mb

   wprintf(L"Server: start benchmark\n");
   if(buffer)
     {
      //--- fill the buffer
      for(size_t j=0;j<1024*1024;j++)
         buffer[j]=j;
      //--- send 8 Mb * 128 = 1024 Mb to client
      DWORD   ticks=GetTickCount();

      for(size_t i=0;i<128;i++)
        {
         //--- setup guard signatures
         buffer[0]=i;
         buffer[1024*1024-1]=i+1024*1024-1;
         //--- 
         if(!manager.Send(buffer,sizeof(double)*1024*1024))
           {
            wprintf(L"Server: benchmark failed, %d\n",GetLastError());
            break;
           }
         volume+=sizeof(double)*1024*1024;
         wprintf(L".");
        }
      wprintf(L"\n");
      //--- read confirmation
      if(!manager.Read(&value,sizeof(value)) || value!=12345)
         wprintf(L"Server: benchmark confirmation failed\n");
      //--- show statistics
      ticks=GetTickCount()-ticks;
      if(ticks>0)
         wprintf(L"Server: %.0lf Mb sent at %.0lf Mb per second\n",volume/1024/1024,volume/1024/ticks);
      //---
      delete[] buffer;
     }

y en el cliente MQL5:

//--- benchmark
   double buffer[];
   double volume=0.0;

   if(ArrayResize(buffer,1024*1024,0)==1024*1024)
     {
      uint  ticks=GetTickCount();
      //--- read 8 Mb * 128 = 1024 Mb from server
      for(int i=0;i<128;i++)
        {
         uint items=ExtPipe.ReadDoubleArray(buffer);
         if(items!=1024*1024)
           {
            Print("Client: benchmark failed after ",volume/1024," Kb, ",items," items received");
            break;
           }
         //--- check the data
         if(buffer[0]!=i || buffer[1024*1024-1]!=i+1024*1024-1)
           {
            Print("Client: benchmark invalid content");
            break;
           }
         //---
         volume+=sizeof(double)*1024*1024;
        }
      //--- send confirmation
      value=12345;
      if(!ExtPipe.WriteInteger(value))
         Print("Client: benchmark confirmation failed ");
      //--- show statistics
      ticks=GetTickCount()-ticks;
      if(ticks>0)
         printf("Client: %.0lf Mb received at %.0lf Mb per second\n",volume/1024/1024,volume/1024/ticks);
      //---
      ArrayFree(buffer);
     }

Observe que los elementos primero y último de los bloques transferidos se comprueban para garantizar que no hay errores durante la transferencia. Además, cuando se ha completado la transferencia el cliente envía una señal de confirmación al servidor sobre la correcta recepción de los datos. Si no quiere utilizar confirmaciones finales, encontrará fácilmente una pérdida de datos si una de las partes cierra la conexión demasiado pronto.

Ejecute el servidor PipeServer.exe localmente y adjunte el script PipeClient.mq5 a cualquier gráfico:

PipeServer.exe PipeClient.mq5
MQL5 Pipe Server
Copyright 2012, MetaQuotes Software Corp.
Pipe '\\.\pipe\MQL5.Pipe.Server' created
Client: waiting for connection...
Client: connected as 'PipeClient.mq5 on MQL5 build 705'
Server: send string
Server: send integer
Server: read string
Server: 'Test string' received
Server: read integer
Server: 1234567890 received
Server: start benchmark
......................................................
........
Server: 1024 Mb sent at 2921 Mb per second
PipeClient (EURUSD,H1)  Client: pipe opened
PipeClient (EURUSD,H1)  Server: Hello from pipe server received
PipeClient (EURUSD,H1)  Server: 1234567890 received
PipeClient (EURUSD,H1)  Client: 1024 Mb received at 2921 Mb per second


Para un intercambio local, la velocidad de transferencia es realmente increíble: casi 3 gigabytes por segundo. Esto significa que las conexiones designadas puede utilizarse para trasferir casi cualquier cantidad de datos en los programas de MQL5.

Ahora vamos a medir el rendimiento de transferencia de datos en una red LAN ordinaria de 1 gigabyte:

PipeServer.exe PipeClient.mq5
MQL5 Pipe Server
Copyright 2012, MetaQuotes Software Corp.
Pipe '\\.\pipe\MQL5.Pipe.Server' created
Client: waiting for connection...
Client: connected as 'PipeClient.mq5 on MQL5 build 705'
Server: send string
Server: send integer
Server: read string
Server: 'Test string' received
Server: read integer
Server: 1234567890 received
Server: start benchmark
......................................................
........
Server: 1024 Mb sent at 63 Mb per second
PipeClient (EURUSD,H1)  Client: pipe opened
PipeClient (EURUSD,H1)  Server: Hello from pipe server received
PipeClient (EURUSD,H1)  Server: 1234567890 received
PipeClient (EURUSD,H1)  Client: 1024 Mb received at 63 Mb per second


En una red local, se ha transferido un gigabyte de datos a una velocidad de 63 megabytes por segundo, lo que está muy bien. De hecho, es un 63% del máximo ancho de banda de la red local.


Conclusión

El sistema de protección de la plataforma de trading Meta Trader 5 no permite que los programas MQL5 se ejecuten fuera del sandbox, protegiendo a los operadores frente a amenazas al usar asesores expertos no fiables. El uso de conexiones designadas permite crear integraciones con software de terceras partes con facilidad y gestionar los asesores expertos desde el exterior. De forma segura.

Traducción del ruso hecha por MetaQuotes Software Corp.
Artículo original: https://www.mql5.com/ru/articles/503

Archivos adjuntos |
pipeclient__3.mq5 (3.15 KB)
pipeserver__3.zip (43.59 KB)
MetaTrader 5 - ¡Más de lo que puedas imaginar! MetaTrader 5 - ¡Más de lo que puedas imaginar!

El terminal de cliente de MetaTrader 5 ha sido desarrollado desde cero y mejora con creces a su predecesor. La nueva plataforma ofrece oportunidades ilimitadas para operar en cualquier mercado financiero. Además, se ha ampliado su funcionalidad para ofrecer aún más características y facilidad de uso. Todo ello hace que sea muy difícil la enumeración de todas las ventajas de MetaTrader 5. Hemos intentado describir brevemente todas estas ventajas en un único artículo y nos ha sorprendido ver que el resultado ¡no ha sido nada breve!

Aumente la velocidad de los cálculos con la red en la nube de MQL5 Aumente la velocidad de los cálculos con la red en la nube de MQL5

¿Cuántos procesadores tiene tu ordenador? ¿Cuántos ordenadores puedes usar para optimizar una estrategia de trading? Aquí mostraremos cómo usar la red en la nube de MQL5 para acelerar los cálculos recibiendo la capacidad de procesamiento a través de la red mundial con solo el clic de un ratón. La frase "el tiempo es dinero" se hace más evidente aun con el paso de los años, y no podemos permitirnos esperar para realisar cálculos importantes durante decenas de horas o incluso días.

Trabajando con cestas de parejas de divisas en el mercado fórex Trabajando con cestas de parejas de divisas en el mercado fórex

En el artículo se analizan cuestiones relacionadas con la división en grupos de las parejas de divisas, las cestas; también sobre cómo obtener datos sobre el estado de estas cestas (por ejemplo, sobrecompra o sobreventa); qué indicadores pueden proporcionar estos datos; y al fin, sobre cómo se puede aplicar la información obtenida en el trading práctico.

Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control

El artículo es la continuación de artículos anteriores sobre neuroredes profundas y elección de predictores. En este veremos las particularidades de una neurored iniciada con Stacked RBM, así como su implementación en el paquete "darch".