文章 "如何采用 MQL5 创建用于 Telegram 的 bots" - 页 31

 

发送照片

该类通过两种应用方式提供了发送照片的机会。

int SendPhoto(const long   chat_id,
              const string local_path,
              string       &photo_id,
              const string caption=NULL,
              const bool   common_flag=false,
              const int    timeout=10000)
聊天号码 聊天号码
本地路径 <data folder>\MQL5\Files 文件夹的本地路径
照片 ID 上传到服务器的照片的标识符
标题 照片下方的签名文字
common_flag 所有客户端的公共文件夹中的文件位置标志 (Terminal\Common\Files
超时 以毫秒为单位的操作超时

发送照片有几种方法。

CCustomBot bot;

string token = "208375865:AAFnuOjlZ3Wsdan6PAjeqqUtBybe0Di1or8";

bot.Token(token);

string photo_id;
int result=bot.SendPhoto(198289825,"EURUSD1.gif",photo_id,"screenshot");
if(result==0)
   Print("Photo ID: ",photo_id);
else
   Print("Error: ",GetErrorDescription(result));

我看到你有一个减号。

你可以查看 Telegram.mqh 文件。

//+------------------------------------------------------------------+
   int SendPhoto(const long   _chat_id,
                 const string _photo_id,
                 const string _caption=NULL)
     {
      if(m_token==NULL)
         return(ERR_TOKEN_ISEMPTY);

      string out;
      string url=StringFormat("%s/bot%s/sendPhoto",TELEGRAM_BASE_URL,m_token);
      string params=StringFormat("chat_id=%lld&photo=%s",_chat_id,_photo_id);
      if(_caption!=NULL)
         params+="&caption="+UrlEncode(_caption);

      int res=PostRequest(out,url,params,WEB_TIMEOUT);
      if(res!=0)
        {
         //--- 解析结果
         CJAVal js(NULL,jtUNDEF);
         bool done=js.Deserialize(out);
         if(!done)
            return(ERR_JSON_PARSING);

         //--- 获取错误描述
         bool ok=js["ok"].ToBool();
         long err_code=js["error_code"].ToInt();
         string err_desc=js["description"].ToStr();
        }
      //--- 完成
      return(res);
     }

   //+------------------------------------------------------------------+
   int SendPhoto(string &_photo_id,
                 const string _channel_name,
                 const string _local_path,
                 const string _caption=NULL,
                 const bool _common_flag=false,
                 const int _timeout=10000)
     {
      if(m_token==NULL)
         return(ERR_TOKEN_ISEMPTY);

      string name=StringTrim(_channel_name);
      if(StringGetCharacter(name,0)!='@')
         name="@"+name;

      if(m_token==NULL)
         return(ERR_TOKEN_ISEMPTY);

      ResetLastError();
      //--- 将文件复制到内存缓冲区
      if(!FileIsExist(_local_path,_common_flag))
         return(ERR_FILE_NOT_EXIST);

      //---
      int flags=FILE_READ|FILE_BIN|FILE_SHARE_WRITE|FILE_SHARE_READ;
      if(_common_flag)
         flags|=FILE_COMMON;

      //---
      int file=FileOpen(_local_path,flags);
      if(file<0)
         return(_LastError);

      //---
      int file_size=(int)FileSize(file);
      uchar photo[];
      ArrayResize(photo,file_size);
      FileReadArray(file,photo,0,file_size);
      FileClose(file);

      //--- 创建边界:(数据 -> base64 -> 1024 字节 -> md5)
      uchar base64[];
      uchar key[];
      CryptEncode(CRYPT_BASE64,photo,key,base64);
      //---
      uchar temp[1024]={0};
      ArrayCopy(temp,base64,0,0,1024);
      //---
      uchar md5[];
      CryptEncode(CRYPT_HASH_MD5,temp,key,md5);
      //---
      string hash=NULL;
      int total=ArraySize(md5);
      for(int i=0;i<total;i++)
         hash+=StringFormat("%02X",md5[i]);
      hash=StringSubstr(hash,0,16);

      //--- WebRequest
      uchar result[];
      string result_headers;

      string url=StringFormat("%s/bot%s/sendPhoto",TELEGRAM_BASE_URL,m_token);

      //--- 1
      uchar data[];

      //--- 添加 chart_id
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,"--"+hash+"\r\n");
      ArrayAdd(data,"Content-Disposition: form-data; name=\"chat_id\"\r\n");
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,name);
      ArrayAdd(data,"\r\n");

      if(StringLen(_caption)>0)
        {
         ArrayAdd(data,"--"+hash+"\r\n");
         ArrayAdd(data,"Content-Disposition: form-data; name=\"caption\"\r\n");
         ArrayAdd(data,"\r\n");
         ArrayAdd(data,_caption);
         ArrayAdd(data,"\r\n");
        }

      ArrayAdd(data,"--"+hash+"\r\n");
      ArrayAdd(data,"Content-Disposition: form-data; name=\"photo\"; filename=\"lampash.gif\"\r\n");
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,photo);
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,"--"+hash+"--\r\n");

      // SaveToFile("debug.txt",数据);

      //---
      string headers="Content-Type: multipart/form-data; boundary="+hash+"\r\n";
      int res=WebRequest("POST",url,headers,_timeout,data,result,result_headers);
      if(res==200)//确定
        {
         //--- 删除 BOM
         int start_index=0;
         int size=ArraySize(result);
         for(int i=0; i<fmin(size,8); i++)
           {
            if(result[i]==0xef || result[i]==0xbb || result[i]==0xbf)
               start_index=i+1;
            else
               break;
           }

         //---
         string out=CharArrayToString(result,start_index,WHOLE_ARRAY,CP_UTF8);

         //--- 解析结果
         CJAVal js(NULL,jtUNDEF);
         bool done=js.Deserialize(out);
         if(!done)
            return(ERR_JSON_PARSING);

         //--- 获取错误描述
         bool ok=js["ok"].ToBool();
         if(!ok)
            return(ERR_JSON_NOT_OK);

         total=ArraySize(js["result"]["photo"].m_e);
         for(int i=0; i<total; i++)
           {
            CJAVal image=js["result"]["photo"].m_e[i];

            long image_size=image["file_size"].ToInt();
            if(image_size<=file_size)
               _photo_id=image["file_id"].ToStr();
           }

         return(0);
        }
      else
        {
         if(res==-1)
           {
            string out=CharArrayToString(result,0,WHOLE_ARRAY,CP_UTF8);
            //Print(out);
            return(_LastError);
           }
         else
           {
            if(res>=100 && res<=511)
              {
               string out=CharArrayToString(result,0,WHOLE_ARRAY,CP_UTF8);
               //Print(out);
               return(ERR_HTTP_ERROR_FIRST+res);
              }
            return(res);
           }
        }
      //--- 
      return(0);
     }

   //+------------------------------------------------------------------+
   int SendPhoto(string &_photo_id,
                 const long _chat_id,
                 const string _local_path,
                 const string _caption=NULL,
                 const bool _common_flag=false,
                 const int _timeout=10000)
     {
      if(m_token==NULL)
         return(ERR_TOKEN_ISEMPTY);

      ResetLastError();
      //--- 将文件复制到内存缓冲区
      if(!FileIsExist(_local_path,_common_flag))
         return(ERR_FILE_NOT_EXIST);

      //---
      int flags=FILE_READ|FILE_BIN|FILE_SHARE_WRITE|FILE_SHARE_READ;
      if(_common_flag)
         flags|=FILE_COMMON;

      //---
      int file=FileOpen(_local_path,flags);
      if(file<0)
         return(_LastError);

      //---
      int file_size=(int)FileSize(file);
      uchar photo[];
      ArrayResize(photo,file_size);
      FileReadArray(file,photo,0,file_size);
      FileClose(file);

      //--- 创建边界:(数据 -> base64 -> 1024 字节 -> md5)
      uchar base64[];
      uchar key[];
      CryptEncode(CRYPT_BASE64,photo,key,base64);
      //---
      uchar temp[1024]={0};
      ArrayCopy(temp,base64,0,0,1024);
      //---
      uchar md5[];
      CryptEncode(CRYPT_HASH_MD5,temp,key,md5);
      //---
      string hash=NULL;
      int total=ArraySize(md5);
      for(int i=0;i<total;i++)
         hash+=StringFormat("%02X",md5[i]);
      hash=StringSubstr(hash,0,16);

      //--- WebRequest
      uchar result[];
      string result_headers;

      string url=StringFormat("%s/bot%s/sendPhoto",TELEGRAM_BASE_URL,m_token);

      //--- 1
      uchar data[];

      //--- 添加 chart_id
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,"--"+hash+"\r\n");
      ArrayAdd(data,"Content-Disposition: form-data; name=\"chat_id\"\r\n");
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,IntegerToString(_chat_id));
      ArrayAdd(data,"\r\n");

      if(StringLen(_caption)>0)
        {
         ArrayAdd(data,"--"+hash+"\r\n");
         ArrayAdd(data,"Content-Disposition: form-data; name=\"caption\"\r\n");
         ArrayAdd(data,"\r\n");
         ArrayAdd(data,_caption);
         ArrayAdd(data,"\r\n");
        }

      ArrayAdd(data,"--"+hash+"\r\n");
      ArrayAdd(data,"Content-Disposition: form-data; name=\"photo\"; filename=\"lampash.gif\"\r\n");
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,photo);
      ArrayAdd(data,"\r\n");
      ArrayAdd(data,"--"+hash+"--\r\n");

      // SaveToFile("debug.txt",数据);

      //---
      string headers="Content-Type: multipart/form-data; boundary="+hash+"\r\n";
      int res=WebRequest("POST",url,headers,_timeout,data,result,result_headers);
      if(res==200)//确定
        {
         //--- 删除 BOM
         int start_index=0;
         int size=ArraySize(result);
         for(int i=0; i<fmin(size,8); i++)
           {
            if(result[i]==0xef || result[i]==0xbb || result[i]==0xbf)
               start_index=i+1;
            else
               break;
           }

         //---
         string out=CharArrayToString(result,start_index,WHOLE_ARRAY,CP_UTF8);

         //--- 解析结果
         CJAVal js(NULL,jtUNDEF);
         bool done=js.Deserialize(out);
         if(!done)
            return(ERR_JSON_PARSING);

         //--- 获取错误描述
         bool ok=js["ok"].ToBool();
         if(!ok)
            return(ERR_JSON_NOT_OK);

         total=ArraySize(js["result"]["photo"].m_e);
         for(int i=0; i<total; i++)
           {
            CJAVal image=js["result"]["photo"].m_e[i];

            long image_size=image["file_size"].ToInt();
            if(image_size<=file_size)
               _photo_id=image["file_id"].ToStr();
           }

         return(0);
        }
      else
        {
         if(res==-1)
           {
            string out=CharArrayToString(result,0,WHOLE_ARRAY,CP_UTF8);
            //Print(out);
            return(_LastError);
           }
         else
           {
            if(res>=100 && res<=511)
              {
               string out=CharArrayToString(result,0,WHOLE_ARRAY,CP_UTF8);
               //Print(out);
               return(ERR_HTTP_ERROR_FIRST+res);
              }
            return(res);
           }
        }
      //--- 
      return(0);
     }
   //+------------------------------------------------------------------+

在 mqh 文件中可以看到

      string name=StringTrim(_channel_name);
      if(StringGetCharacter(name,0)!='@')
         name="@"+name;

因此,您可以尝试做如下修改

      string name = _channel_name;
      //if(StringGetCharacter(name,0)!='@')
      // name="@"+name;
 
tdbguy:

请勿重复发帖!

我会删除您的主题并将回复移到这里。

 
John Progton:

Andrey Voytenko 基本上,我添加了您使用的文件,然后修改了脚本,以便在执行交易操作时发送到电报而不是电子邮件。除了在开仓交易时会多次发送信息外,这个方法还是有效的。

同样的问题
 

我确认,只需对 #46 号帖子中的代码稍作修改,代码就能在 MT5 上正常工作,向通道发送警报。

我还确认,向机器人发送用于控制 EA 的请求也能正常工作。

但有人成功地将机器人向 EA 发出的请求锁定在某个 "from_id "上吗? 这样机器人就只能监听来自特定 ID 的请求。

 
huwa:

我确认,只需对 #46 号帖子稍作修改,代码就能在 MT5 上正常工作,向通道发送警报。

我还确认,向控制 EA 的机器人发送请求也正常。

但有人成功地将机器人向 EA 发出的请求锁定在某个 "from_id "上吗? 这样机器人就只能监听来自特定 ID 的请求。

如果想将机器人请求锁定在 Telegram 帐户 ID 上,请在 Telegram.mqh 中找到这一行:


//--- 过滤器
   //if(m_users_filter.Total()==0 || (m_users_filter.Total()>0 && m_users_filter.SearchLinear(msg.from_username)>=0)) //从代码中删除这一行
   if(msg.from_id==??????????)   //在代码中添加这一行,其中 ?????????? 是您的 Telegram 账户 ID


 
感谢 Andrey Voytenko 分享您的知识,这对我这样的初学者很有帮助。

Telegram_Bot_EA 和 Telegram_Search_EA 运行得很好,但最后一个(Telegram_signal_EA)却不行。
我的频道没有信号。

我的做法是
- 制作一个机器人,添加到我的频道并设置为管理员
- 用我的指标更改您的代码
- 更改 Telegram.mqh 以创建私人频道

运行 Telegram_singal_EA 后,我可以看到我的机器人名称,但仍然没有收到任何信号。


每次勾选都 会出错:

Telegram_Signal_EA GBPUSD,M1:错误:请求错误

Telegram_Signal_EA GBPUSD,M1: {"ok":false, "error_code":400, "description": "Bad Request: chat not found"}


您有任何建议吗?

 

@ade kurniawan 在使用私人频道时应使用聊天 ID(而不是频道名称)。

 
Andrey Voytenko:

@ade kurniawan 你应该使用图表 ID(而不是频道名称)来处理私人频道。

是的,我已经改了。还是同样的错误。即使我将所有内容都改为公共频道
 


我试过在信息中使用**粗体** __italic__ 和标记符,如下所示,但没有成功...


"n**boldtext** __italictext__ Balance: $%s parse_mode=MARKDOWN"

结果是:

**boldtext** __italictext__ 余额:$10056.21parse_mode=MARKDOWN
 

没关系....

我通过将 AsHTML 标志设置为 true 找到了答案...

bot.SendMessage(InpTelegramId,"<b>Balance: $10056.21</b>",true);

抱歉...


spottypegasus:


我试过在信息中使用 **bold** __italic__ 和 markdown,如下所示,但没有成功...


"n**boldtext** __italictext__ Balance: $%s parse_mode=MARKDOWN"

结果是:

**boldtext** __italictext__ 余额:$10056.21parse_mode=MARKDOWN