李大仁博客

MT4使用MQL连接Redis的插件

工作中需要将MT4的数据读取并且存储到Redis数据库中去,同时MT4读取Redis当中的数据用于下单的切换账户。
MT4支持使用MQL进行开发,通过调用标准的系统DLL实现系统调用,因此技术实现并不是太难,只需要按MQL的接口要求编写相应的CPP代码
编译成DLL即可实现所需要的功能。

在Windows平台上,连接Redis的客户端选用Hiredis作为连接客户端lib。

MT4 连接Redis 头文件定义,
MT4RedisPlugin.h

#define MT4_REDIS_ERR -1          /* Error */
#define MT4_REDIS_OK 0            /* OK */
#define MT4_REDIS_ERR_IO 1        /* error in read or write */
#define MT4_REDIS_ERR_EOF 3       /* eof */
#define MT4_REDIS_ERR_PROTOCOL 4  /* protocol error */
#define MT4_REDIS_ERR_OTHER 2     /* something else */

#define MT4_REDIS_CMD_SUCCESSED 0 /* Successed */
#define MT4_REDIS_CMD_FAILED   -1 /* Failed */

//---
#define MT4_EXPFUNC __declspec(dllexport)

//+------------------------------------------------------------------+
//| Test Redis if is working                                         |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisTest(const char* server, const int port);

//+------------------------------------------------------------------+
//| Excute Redis Command "GET key"                                   |
//+------------------------------------------------------------------+
MT4_EXPFUNC wchar_t* __stdcall RedisGet(const wchar_t* key);

//+------------------------------------------------------------------+
//| Excute Redis Command "GET key"                                   |
//+------------------------------------------------------------------+
MT4_EXPFUNC wchar_t* __stdcall RedisGetWithTimeout(const wchar_t* key,int timeout);

//+------------------------------------------------------------------+
//| Excute Redis Command "SET key value"                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisSet(const wchar_t* key, const wchar_t* value);

//+------------------------------------------------------------------+
//| Excute Redis Command "SET key value"                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisSetWithTimeout(const wchar_t* key, const wchar_t* value,int timeout);

//+------------------------------------------------------------------+
//| Excute Redis Command                                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisCommand(const wchar_t* command);

//+------------------------------------------------------------------+
//| Excute Redis Command                                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisCommandWithTimeout(const wchar_t* command,int timeout);

//+------------------------------------------------------------------+
//| char to WCHAR 、wchar_t、LPWSTR etc                              |
//+------------------------------------------------------------------+
static wchar_t * CStr2WStr(const char *cStr);

//+------------------------------------------------------------------+
//| WCHAR 、wchar_t、LPWSTR to char                                  |
//+------------------------------------------------------------------+
static char* WStr2CStr(const wchar_t *wchar);

//+------------------------------------------------------------------+
//| Show Messagebox                                                  |
//+------------------------------------------------------------------+
static void MT4RedisMsgBox(const wchar_t* msg);

使用Hiredis读取Redis数据库

//+------------------------------------------------------------------+
//| Excute Redis Command "GET key"                                   |
//+------------------------------------------------------------------+
MT4_EXPFUNC wchar_t* __stdcall RedisGetWithTimeout(const wchar_t* key,int timeout)
  {
          // 构造windows socket对象
        //WSADATA wsaData;
        //WSAStartup(MAKEWORD(2,1), &wsaData);

        // 设置超时
        struct timeval tv;
        tv.tv_sec = timeout/1000;
        tv.tv_usec = timeout *1000;
        redisContext* context = redisConnectWithTimeout(REDIS_SERVER,REDIS_PORT,tv);

        //判断连接是否有错误
        if (context->err) {
            printf("Failed to connect redis server[%s:%d]\n",REDIS_SERVER,REDIS_PORT);
            redisFree(context);
            return NULL;
        }

        //构造Redis命令
        //获取size
        size_t len = wcslen(key) + 20;
        //命令长度
        if (len > COMMAND_BUFFER) {
            printf("Command is too long, Command string must short than %d",COMMAND_BUFFER);
            return NULL;
        }
        // 构建Comand
        wchar_t command[COMMAND_BUFFER];
        //构造Redis命令
        wsprintf(command,L"GET %s",key);

        //字符串转换
        const char* command1 = WStr2CStr(command);

        //执行Redis命令
        printf("Ready to execute command[%s]\n", command1);

        // 执行命令
        redisReply* reply = (redisReply*)redisCommand(context, command1);

        //没有Redis响应
        if( NULL == reply)
        {
            printf("Failed to execute command[%s]\n",command1);
            redisFree(context);
            return NULL;
        }

        //响应状态
        if ( reply->type != REDIS_REPLY_STRING)
        {
            printf("Failed to execute command[%s]\n",command1);
            freeReplyObject(reply);
            redisFree(context);
            return NULL;
        }
        printf("The value of \"%s\" is \"%s\"\n", key, reply->str);

        //字符串转换
        wchar_t * result = CStr2WStr(reply->str);

        //释放Reply对象
        freeReplyObject(reply);
        //释放Redis连接
        redisFree(context);
        printf("Succeed to execute command[%s]\n", command1);
        delete command1;
        command1 = NULL;
        //返回结果字符串
        return result;
  }

使用Hiredis写入Redis数据库

//+------------------------------------------------------------------+
//| Excute Redis Command "SET key value"                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisSetWithTimeout(const wchar_t* key, const wchar_t* value, int timeout)
  {
        //构造Redis命令
        //获取size
        size_t len = wcslen(key)+wcslen(value) + 20;
        //命令长度
        if (len > COMMAND_BUFFER) {
            printf("Command is too long, Command string must short than %d",COMMAND_BUFFER);
            return MT4_REDIS_CMD_FAILED;
        }
        // 构建Comand
        wchar_t command[COMMAND_BUFFER];
        //构造Redis命令
        wsprintf(command,L"SET %s %s",key,value);
        return RedisCommandWithTimeout(command,timeout);
  }

使用Hiredis执行Redis命令

//+------------------------------------------------------------------+
//| Excute Redis Command                                             |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall RedisCommandWithTimeout(const wchar_t* command,int timeout)
  {
        // 构造windows socket对象
        //WSADATA wsaData;
        //WSAStartup(MAKEWORD(2,1), &wsaData);

        // 设置超时
        struct timeval tv;
        tv.tv_sec = timeout/1000;
        tv.tv_usec = timeout *1000;
        redisContext* context = redisConnectWithTimeout(REDIS_SERVER,REDIS_PORT,tv);

        //判断连接是否有错误
        if (context->err) {
            printf("Failed to connect redis server[%s:%d]\n",REDIS_SERVER,REDIS_PORT);
            redisFree(context);
            return MT4_REDIS_CMD_FAILED;
        }

        // 命令长度
        size_t len = wcslen(command) + 1;
        if (len > COMMAND_BUFFER) {
            printf("Command is too long, Command string must short than %d",COMMAND_BUFFER);
            redisFree(context);
            return MT4_REDIS_CMD_FAILED;
        }

        //字符串装换
        const char* command1 = WStr2CStr(command);

        //执行Redis命令
        printf("Ready to execute command[%s]\n", command1);

        // 执行命令
        redisReply* reply = (redisReply*)redisCommand(context, command1);

        //没有Redis响应
        if( NULL == reply)
        {
            printf("Failed to execute command[%s]\n",command1);
            redisFree(context);
            return MT4_REDIS_CMD_FAILED;
        }

        //响应状态
        if( !(reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str,"OK")==0))
        {
            printf("Failed to execute command[%s]\n",command1);
            freeReplyObject(reply);
            redisFree(context);
            return MT4_REDIS_CMD_FAILED;
        }

        //释放Reply对象
        freeReplyObject(reply);
        //释放Redis连接
        redisFree(context);
        printf("Succeed to execute command[%s]\n", command1);
        delete command1;
        command1 = NULL;
        //返回成功状态
        return MT4_REDIS_CMD_SUCCESSED;
  }

测试MQL代码

//+------------------------------------------------------------------+
//|                                              DLLSampleTester.mq4 |
//|                 Copyright ゥ 2005-2014, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ゥ 2005-2014, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net/"

#import "MT4RedisPlugin.dll"
string HelloWorld(string);
string RedisGet(string);
string RedisGetWithTimeout(string,int);
int RedisSet(string,string);
int RedisSetWithTimeout(string, string, int);
int RedisCommand(string);
int RedisCommandWithTimeout(string,int);
int RedisTest(string,int);
#import

#define TIME_INDEX   0
#define OPEN_INDEX   1
#define LOW_INDEX    2
#define HIGH_INDEX   3
#define CLOSE_INDEX  4
#define VOLUME_INDEX 5
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   Print("GO GO GO");

   string hello;
   hello = HelloWorld("1234abc");
   Print("result is", hello);

   string test;
   test = RedisTest("127.0.0.1",6379);
   Print("test result is", test);

   int cmd1;
   cmd1 = RedisCommand("set KEYabc VALUE123");
   Print("RedisCommand test = ", cmd1);

   int cmd2;
   cmd2 = RedisCommandWithTimeout("set KEYabc VALUE123",10000);
   Print("RedisCommandWithTimeout test = ", cmd2);

   string key1 = "key1";
   string value1 = "value1";
   int set1 = RedisSet(key1,value1);
   Print("RedisSet test = ", set1);

   string key2 = "key2";
   string value2 = "value2";
   int timeout = 10000;
   int set2 = RedisSetWithTimeout(key2,value2,timeout);
   Print("RedisSetWithTimeout test = ", set2);

   string get1 = RedisGet(key1);
   Print("RedisGet test = ", get1);

   string get2 = RedisGetWithTimeout(key2,timeout);
   Print("RedisGetWithTimeout test = ", get2);

   string key3 = "key3";
   string get3 = RedisGet(key3);
   Print("RedisGet test = ", get3);

   string key4 = "key4";
   string get4 = RedisGet(key4);
   Print("RedisGet test = ", get4);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| array functions call                                             |
//+------------------------------------------------------------------+
int start()
  {
   return(0);
  }
//+------------------------------------------------------------------+

完整的代码地址
https://github.com/limccn/mt4-redis

Exit mobile version