MQL4:如何从 URL 读取 CSV

Posted

技术标签:

【中文标题】MQL4:如何从 URL 读取 CSV【英文标题】:MQL4: How to read a CSV from a URL 【发布时间】:2016-09-07 10:19:47 【问题描述】:

我正在使用这个 URL 从 Quandl 网站获取一些内容:

https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv?exclude_column_names=true&rows=1&api_key=my_api_key

Quandl 服务器响应上述请求返回如下值:

2016-08-01, 144598.0

我需要在MQL4 Script中使用144598.0,所以:

第一季度。如何从上面的 URL 获取内容以在 MQL4 脚本中使用?

来自 SO (https://***.com/users/3666197/user3666197) 的一位非常乐于助人的用户提供了以下 script(原始发现于 MQL4: Read single value from CSV)(我自己添加了几个部分)来帮助我实现这一目标,但是,我无法得到它的工作:

// Code created with the help of Stack Overflow question
// https://***.com/questions/39279634/mql4-read-single-value-from-csv/39284875#39284875
// Question by p.luck:
// https://***.com/users/5551849/p-luck
// Answer by user3666197:
// https://***.com/users/3666197/user3666197

void OnStart()
    
     string cookie = NULL,
            headers; 
     char   post[],
            result[]; 
     int    res; 

/*   TODO:                                                                             *
 *   Must allow MT4 to access the server URL,                                          *
 *   you should add URL "https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv" *
 *   in the list of allowed URLs                                                       *
 *   ( MT4 -> Tools -> Options -> [Tab]: "Expert Advisors" ):                          */

     string aDataSOURCE_URL = "https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv";
     string aDataSOURCE_API = "?exclude_column_names=true&rows=1&api_key=my_api_key";

     //-- Create the body of the POST request for API specifications and API-authorization
     ArrayResize( post,
                  StringToCharArray( aDataSOURCE_API, // string   text             |--> [in]  String to copy.
                                     post,            // uchar   &array[]       <--|    [out] Array of uchar type.
                                     0,               // int      start =  0       |--> [in]  Position from which copying starts. Default - 0. 
                                     WHOLE_ARRAY,     // int      count = -1       |--> [in]  Number of array elements to copy. Defines length of a resulting string. Default value is -1, which means copying up to the array end, or till terminating '\0'. Terminating zero will also be copied to the recipient array, in this case the size of a dynamic array can be increased if necessary to the size of the string. If the size of the dynamic array exceeds the length of the string, the size of the array will not be reduced.
                                     CP_UTF8          // uint     cp    = CP_ACP   |--> [in]  The value of the code page. For the most-used code pages provide appropriate constants.
                                     )
                  - 1
                  );

//-- Reset the last error code
     ResetLastError();

//-- Loading a html page from Quandl
     int timeout = 5000;                                                //-- Timeout below 1000 (1 sec.) is not enough for slow Internet connection

     res = WebRequest( "POST",              // const string  method            |--> [in]  HTTP method.
                        aDataSOURCE_URL,    // const string  URL               |--> [in]  URL.
                        cookie,             // const string  cookie            |--> [in]  Cookie value.
                        NULL,               // const string  referrer          |--> [in]  Value of the Referer header of the HTTP request.
                        timeout,            //       int     timeout           |--> [in]  Timeout in milliseconds.
                        post,               // const char   &data              |--> [in]  Data array of the HTTP message body
                        ArraySize( post ),  //       int     data_size         |--> [in]  Size of the data[] array.
                        result,             //       char   &result         <--|    [out] An array containing server response data.
                        headers             //       string &result_headers <--|    [out] Server response headers.
                        );
//-- Check errors
     if ( res == -1 )
         Print( "WebRequest Error. Error code  = ", GetLastError() );  //-- Perhaps the URL is not listed, display a message about the necessity to add the address
          MessageBox( "Add the address '" + aDataSOURCE_URL + "' in the list of allowed URLs on tab 'Expert Advisors'", "Error", MB_ICONINFORMATION );
          
     else //-- Load was successfull
         
          PrintFormat( "The data has been successfully loaded, size = %d bytes.", ArraySize( result ) );

          //-- parse the content ---------------------------------------
          /*
              "2016-08-01, 144598.0"

          */
          //-- consume the content -------------------------------------
          //...


          
     

我已将URL ofhttps://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv添加到MT4 中的allowed URLs 列表中。

如果我启用 AutoTrading 并将名为 (tutorial7) 的 script 拖到 USDCAD,M1chart 上,我会在 Experts tab 中收到这些消息:

Script tutorial7 USDCAD,M1: loaded successfuly tutorial7 USDCAD,M1: initialized tutorial7 USDCAD,M1: The data has been successfully loaded, size = 0 bytes tutorial7 USDCAD,M1: uninit reason 0

如果“The data has successfully loaded”肯定不应该说“size = 0 bytes”吗?

如果我只是将它直接复制并粘贴到MetaQuotes Language Editorcompile 中,这个script 是否可以正常工作?

除了将URL 添加到MT4 中的allowed URLs 并将此代码复制并粘贴到script 之外,还有什么我必须做的吗?

如果有,怎么做?

我将上面的代码作为Script 运行不是 Expert Advisor;这样好吗?

第二季度。我可以在脚本中将获取的值 144598.0 设置为变量吗?

我需要将144598.0value 设为变量,以便可以将其与另一个value 进行比较。

这样的工作是否可行:

void OnStart()


... // above code which fetches the value from the .csv URL

double x = 155876.0     // value manually typed in
       y = 144598.0     // value fetched from the .csv URL using the above code
                        // ignores column 1 consisting of 2016-08-01
   if ( x > y ) 
                        // execute code
 

else  
                        // execute other code



【问题讨论】:

【参考方案1】:

A2:是的! 这是旅程中最简单的部分。A1: 但是!它在实践中是如何工作的?MetaTrader 终端实际上是如何说话的到 Quandl,所以得到它?

我先说明远程的问题,HttpServer-side 处理。

有一个易于制作原型的程序 curl(提供 Linux 和 DOS 版本)将显示在终端窗口(或 Windows cmd 窗口中) Quandl 的远程 HttpServer 如何响应本地组装请求的各种组合,通过 HTTP 协议进行通信。

请注意,刚刚重新键入的 URL 会生成要传递的整个历史记录。

C:\>curl https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv
DATE,VALUE
2016-08-01,144598.0
2016-07-01,144447.0
...
..
.
1939-03-01,30280.0
1939-02-01,30101.0
1939-01-01,29923.0

一旦我们向普通的URL 添加更多参数,远程端(HttpServer)会将回复更改为我们感兴趣的一行:

C:\>curl -G --data rows=1 --data exclude_column_names=true https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv
2016-08-01,144598.0

酷,看起来很棒,几乎是我们想要的单一价值!

但魔法来了。

本地进程(现在是 curl,但后来是 MetaTrader 终端)之间的真正交换(对话)看起来是这样的(在 curl 命令行中使用 --verbose 选项):

C:\>curl --verbose -G --data rows=1 --data exclude_column_names=true https://www.quandl.com/api/v3/datasets/FRED/PAYEMS.csv
*   Trying 54.174.87.84...
* Connected to www.quandl.com (54.174.87.84) port 443 (#0)
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 1/3)
* schannel: checking server certificate revocation
* schannel: sending initial handshake data: sending 70 bytes...
* schannel: sent initial handshake data: sent 70 bytes
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 2/3)
* schannel: encrypted data buffer: offset 4096 length 4096
* schannel: encrypted data length: 4017
* schannel: encrypted data buffer: offset 4017 length 4096
* schannel: received incomplete message, need more data
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 2/3)
* schannel: encrypted data buffer: offset 4569 length 5041
* schannel: sending next handshake data: sending 318 bytes...
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 2/3)
* schannel: encrypted data buffer: offset 51 length 5041
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with www.quandl.com port 443 (step 3/3)
* schannel: incremented credential handle refcount = 1
* schannel: stored credential handle in session cache
> GET /api/v3/datasets/FRED/PAYEMS.csv?rows=1&exclude_column_names=true HTTP/1.1
> Host: www.quandl.com
> User-Agent: curl/7.45.0
> Accept: */*
>
* schannel: client wants to read 16384 bytes
* schannel: encdata_buffer resized 17408
* schannel: encrypted data buffer: offset 0 length 17408
* schannel: encrypted data got 653
* schannel: encrypted data buffer: offset 653 length 17408
* schannel: decrypted data length: 623
* schannel: decrypted data added: 623
* schannel: decrypted data cached: offset 623 length 16384
* schannel: encrypted data buffer: offset 0 length 17408
* schannel: decrypted data buffer: offset 623 length 16384
* schannel: schannel_recv cleanup
* schannel: decrypted data returned 623
* schannel: decrypted data buffer: offset 0 length 16384
< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Disposition: attachment; filename=FRED-PAYEMS.csv
< Content-Transfer-Encoding: binary
< Content-Type: text/csv
< Date: Wed, 07 Sep 2016 12:47:20 GMT
< ETag: W/"adfdb97850c493cdd03e2036574bc404"
< Server: openresty
< Vary: Origin
< X-API-Version: 2015-04-09
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Rack-CORS: preflight-hit; no-origin
< X-RateLimit-Limit: 50
< X-RateLimit-Remaining: 42
< X-Request-Id: c609e92d-22d2-40e7-b7d4-cacb07467c76
< X-Runtime: 0.023534
< X-XSS-Protection: 1; mode=block
< Content-Length: 20
< Connection: keep-alive
<
2016-08-01,144598.0
* Connection #0 to host www.quandl.com left intact

注意这一行GET /api/v3/datasets/FRED/PAYEMS.csv?rows=1&amp;exclude_column_names=true

所以魔术是让 MetaTrader 终端组装相同,同时允许配置中允许列表中的 URL(您已经在另一篇文章中完成)。

也可能已经注意到,HTTP GET 只发送&lt;HttpServer_relative_part_of_the.URL&gt;


神奇之处在于让 MQL4 代码发送与上述相同的请求并取回数据。

WebRequest() 必须使用 HTTP GET,因为 Quandl HttpServer 不响应同一请求示例的 HTTP POST 版本,返回 0 字节(只需省略上面curl 示例中的-G 开关)。

同时满足所有条件应该会导致接收2016-08-01,144598.0并使用:

int    anAmountOfBytesRECVd   = 0;          // how many bytes Quandl sent 
string headers_FromHttpSERVER;              // stores as a string
char   anAnswerFromHttpSERVER[];            // stores as a byte-array ( char[] )
double y_value = NULL;

anAmountOfBytesRECVd = WebRequest( "GET",   // MUST use HTTP GET <- Quandl tested
                                    ...
                                    anAnswerFromHttpSERVER,
                                    headers_FromHttpSERVER
                                    );

y_value = StrToDouble( CharArrayToString( anAnserFromHttpSERVER, // [2|0|1|6|-|0|8|-|0|1|,|1|4|4|5|98|.|0]
                                          11,                    //-----------------------^_______________( -1 == TILL EndOfSTRING )
                                          -1
                                          )
                       );

【讨论】:

那么我是否应该在我的问题中将该代码脚本添加到我的初始脚本中?我仍然对此非常不确定 - 我感谢您的努力和您的回答,因为它们非常有帮助,但是,我对 MQL4 还是很陌生。我应该将它们全部编译并保存为脚本吗? WebRequest() 已确认允许从 EA 和脚本代码类型中调用。代码本身需要调整,以正确传递“属性”,如 GET 示例中所示,curl --verbose,因此会进行轻微调整,但是远程 httpServer 响应文本解析为单个 double y_value如上所示,将为您提供所需的转换。

以上是关于MQL4:如何从 URL 读取 CSV的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:如何从 google drive public 读取 CSV 文件?

如何从字符向量中解析 CSV 数据以提取数据框?

如何使用熊猫读取共享文件夹中的csv文件?

使用 SSIS 从网站 (URL) 读取多个 CSV 文件?

使用 pandas.read_csv 从 URL 读取压缩的 CSV 文件时出错

mql4如何自定义画图