Mql5自定义品种 中国金融产品: A股票、期货、债券、数字货币的应用(1)

Mars Yuan  

引言

       Mql5自定义品种中国 A股票 期货 债券品种;使用Http 协议 通过Post模式,将Tushare金融开源数据,导入中国 A股票(除权、复权)期货 债券分钟、日线、周、月历史数据的应用。

       交易是门古老而又现代的学科,是人类社会运转基础。每天全球金融产品交易有价证券市场的交易量大约为3000亿美元,而每天外汇交易量将近6万亿美元。有价证券交易70%和外汇交易90%以上都是通过自动程序及算法交易完成,对比中国金融及资本市场发展现状还有非常大的改善空间。特别是机器程序交易EA在中国基本是空白2019年各大中国券商都开始内测程序化交易平台,2019年12月中国第二个指数期货沪深300ETF开埠。这意味中国金融衍生品及高阶交易市场重新步入发展轨道,对于中国当前的资产定价失锚和重构起到举足轻重作用。

      将Metatrader5(MQL5)作为金融工程仿真和交易平台引入中国金融工程学科研究和量化自动交易构建,促进金融工程学科在中国发展和全球交易体系对接实践。



1、建立自定义品种方法

      自Metatrader5 开始处了通过券商接口提供数据的品种外,还提供“自定义品种”的接入方式及函数组https://www.mql5.com/zh/docs/customsymbols;对于品种对象集合系统应用可参阅:METATRADER 程序的函数库(第十五部分):品种对象集合  https://www.mql5.com/zh/articles/7041

      本文只通过CustomSymbolCreate()函数创建股票、指数自定义品种目录,再利用CustomRatesReplace()函数将通过Http读取的Tushare金融数据源数据的MqlRates结构数组的数据导入自定义品种的历史数据。自定义品种的应用有两个要点:

第一点:是自定义品种功能应用应用,如何将自定义品种显示和隐藏在交易品种栏,并通过交易品种自定义品种的历史数据导出、导入(先有系统自带外汇货币对品种数据练习测试),熟悉自定义品种在metatrader5功能应用,如下图例:

自定义品种的历史数据导出 及导入

第二点:是Http调用外部数据最重要的选择,通过MetaQuotes的工具——设置——EA交易选项 新增 Http访问地址,图例如下:

添加 Tushare地址:http://api.waditu.com

注意:此选项在交易系统MetaQuotes中, 而不是MQL5的代码编辑MetaEditor里。如果没有进行此项选择MetaEditor的程序是无法访问外部Http端口。本图例添加了Tushare社区金融数据访问地址:http://api.waditu.com




2、Tushare 开源金融数据源接口方式及调用方法

      

       Tushare 开源金融数据源https://tushare.pro是中国几位金融数据爱好者组建的免费开源的金融数据社区,目前在中国Tushare是最全面的开源免费数据,这非常不容易。金融数据提供是有严格法律责任其有效性真实性在中国受到严格法律法规监管。Tushare的创建者是以历史数据的形式提供A股票、期货、债券数据,不提供实时数据;但是区块链及数字货币不涉及中国法规所以提供实时数据。

       Tushare除提供全面的金融数据源 股票 指数 期货 期指 债券 甚至还有区块链 数字货币。国内还有些开源金融数据社区,但是目前在中国金融量化与算法交易的研究平台多数是运用Python语言和Quantopian平台,开源金融数据读取都是用Python访问。Py但Python语言结合Quantopian类平台系统作为专业金融工程仿真研究和交易系统有很多局限。

       首先Python语言虽然有诸多优点如 移植性、快平台、语言便捷等,但是作为专业金融工程研究Python这种胶水类模式的粘结的算法模块大都不能基于Python自身修改、优化等反编译如同Blackbox。其次基于Quantopian类IDE系统的的Zline类功能回溯报告只是最终的收益对比图表,不能如同Meta Editor回溯可以细节观察,这对于指标的效率和优化及调试Bug几乎是致命的。再则Python语言和Quantopian框架对于高频交易和毫秒编程的支持几乎没有便捷方案的可能,这对于未来算法交易及EA的研究是个无法逾越的壁垒。

       作者基于多年的MQL5社区文献资源和系统应用将MQL5作为金融工程仿真及交易平台引入中国金融工程的分析应用具有深远的意义。MQL5作为以C++类语言开发有着无法比拟的优势。目前MQL5接入自定义品类的接口有多种,其系统嵌入了Pyhton通讯模组(METATRADER 5 与 PYTHON 的集成:接收和发送数据   https://www.mql5.com/zh/articles/5691),用户可以建立Python平台的数据访问机制 但是通过Web直接访问数据源更加灵活便捷,一般Web 导入公域金融数据多半是通过财经网页的CSS PHP 爬虫类应用抓取,其数据完整和数据源长期稳定性问题多多,通过Http协议访问专业金融数据源非常简单稳定。而免费开源提供Http协议访问并且丰富金融数据源的开源免费社区只有Tushare。

       Tushare社区开源免费注册,注册后每个用户会被分配唯一Token密码,用户访问数据需要通过Token码才可以访问成功;本文章中的Token码为作者自己申请用于测试,不确保可以长时间使用,需要用户各自申请后替换自己的Token码。因为Tushare的服务性能局限,开源A股日线数据并受到每分钟访问200次以下的限制,如果需要分钟线或者并线多线程访问需要与Tushare社区管理员申请权限。

       Tushare社区开源A股数据Http协议访问时通过Post模式,Http协议访问有几种模式 主要是两种Get和Post。Tushare股票数据和指数数据、股票的日线数据、分钟数据、复权因子都是不同的访问端口和Json数据格式,并且服务器返回的数据格式也略有差异,因此在数据处理过程就需要不同过程,不能通过同一过程函数复用。

      本文结构分别列取了A股列表、A股个股日线数据 、A股个股日线复权数据、指数数据、A股个股分钟线数据等几个不同的数据访问及处理过程详细实例。

      在使用MQL5开发Http协议之前需要测试Tushare端口和通讯Json 文档有效性,一般采用Google 浏览器Chrome扩展其应用Postman,也可以独立下载Postmen类Http访问测试工具软件。具体应用参考:  https://chromecj.com/utilities/2019-09/2957.html

      本文使用Tabbed Postman - REST Client作为测试工具 https://chrome.google.com/webstore/detail/tabbed-postman-rest-clien/coohjcphdfgbiolnekdpbcijmhambjff?utm_source=chrome-ntp-icon;对Tushare测试端口实例如下图:

       

通过Postman的对Tushare访问可以清晰的看到其返回沪深300 399300.SZ Post访问 Json 字符串格式及返回的数据结构。如果测试为返回数据返回code代码错误信息,需要用户自行在Tushare社区申请 token码替换。为方便测试和接下来的数据处理过程理解,特将Tushare的访问实践现将几个重要的访问端口的Json文档内容示例列出,但是具体详实应用文档访问Tushare社区或者联系Tushare社区管理员。

A股指数Http 访问Post 请求Json 文档:

访问Http链接地址:http://api.waditu.com

{
"api_name":"index_daily",
"token":"e5282e6eee67e52c4b0b420c96d5ac6dcb7cf291b06c080547649086",
"params":{"ts_code":"399300.SZ","start_date":"20100101 00:00","end_date":"20191216 00:00"}
}

A股个股日线数据 Http 访问Post 请求Json 文档:

访问Http链接地址:http://api.waditu.com

{
"api_name":"daily",
"token":"e5282e6eee67e52c4b0b420c96d5ac6dcb7cf291b06c080547649086",
"params":{"ts_code":"300015.SZ","asset":"E","adj":"qfq","freq":"D","start_date":"20000101 00:00","end_date":"20200104 11:50"},
"fields":""
}


A股个股1分钟线数据 Http 访问Post 请求Json 文档:

访问Http链接地址:http://api.waditu.com

{
"api_name":"stk_mins",
"token":"e5282e6eee67e52c4b0b420c96d5ac6dcb7cf291b06c080547649086",
"params":{"ts_code":"600886.SH","asset":"E","adj":"qfq","freq":"1min","start_date":"20190101 00:00","end_date":"20191214 00:00"},
"fields":""
}


A股个股复权因子数据 Http 访问Post 请求Json 文档:

访问Http链接地址:http://api.waditu.com

{
"api_name":"adj_factor",
"token":"e5282e6eee67e52c4b0b420c96d5ac6dcb7cf291b06c080547649086",
"params":{"ts_code":"300015.SZ","trade_date":""},
"fields":""
}

注意:不同数据访问 端口api_name的变化和Json数据格式变化。通过利用Postman对Tushare开源金融数据源的测试可以先建立对Http协议Post访问的数据方式及数据结构深入了解更多金融数据源参阅:https://tushare.pro/document/2 Tushare社区数据列表文档。



3、读取A股品种列表目录及数据结构及实例

Post需要 向Http数据服务器发送Json格式的char字符串文件请求信息。这是MQL5应用Http 协议应用的一个难点,MQL5对于复杂字符串转换为Char字符串格式处理没有简便函数处理需要另行处理过程复杂类过程(MQL5社区有相关库提供);本文采取简便的字符标识重组字符串后,利用StringToCharArray()函数便捷转换成Post的Json请求信息char 字符串。通过Mql5的WebRequest()函数向Tushare服务器发送请求。但是Tushare服务器返回的数据格式是为加分隔的数据数组而是连续的长字符串。这需要进一步数据切分和处理过程。

因为指数和个股及复权数据字符数据格式均有差异,根据不同数据请求在下述代码实例中详细列出。

//+------------------------------------------------------------------+
//|                                                 Astock_Stock.mq5 |
//|                                    Copyright 2019, MarsYuan 苑兵 |
//|                                              Mars.yuan@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019,  MarsYuan"
#property link      "https://www.mql5.com/zh/users/marsyuan"
#property version   "1.00"
//+------------------------------------------------------------------+


input  string Token="e5282e6eee67e52c4b0b420c96d5ac6dcb7cf291b06c080547649086";

      
                                
//+------------------------------------------------------------------+
void  OnStart()
{
       string list[];
      
       ReadList(Token,list);
       
       int n=ArraySize(list);
       
       MessageBox("Astock:"+n);

       
       
}    

//-----------------------------------------------------------------------------------------------------------------
//-------------------Http协议Post方式读取股票名称列表并存入数组list------Http post download stock list------------- 

void ReadList(const string &token,string &list[])
{
         //---------Http post Josn string to char Arr-------------------------------------------------------------- 
            char message_data[], result[];
           
            string   RequestMethod     ="POST";
            string   END_POINT_URL     ="http://api.waditu.com";
            string   headers           = "content-type:application/json"+"\r\n";
                     headers           += ",charset=UTF-8" + "\r\n";
            int      timeout           =  10000;
            string   result_headers    =  NULL;
            string   message_text     ;

            
           //--------------------将字符整合成Post接受的Json标准的char 字符串---------
           StringConcatenate(message_text,
                              "{",
                              "\"api_name\"",
                              ":",
                              "\"stock_basic\"", 
                              ",",
                              
                              
                              "\"token\"",
                              ":",
                              "\"",
                              token,
                              "\"",
                              ",",
                              
                              
                              "\"params\"",
                              ":",
                              "{",
                              
                              "\"list_stauts\"",
                              ":",
                              "\"L\"",
                              "}",
                              ",",
                              
                              "\"fields\"",
                              ":",
                              "\"ts_code,name,area,industry,list_date\"",
                              "}"
                            );
                            
           
         
           StringToCharArray(message_text,message_data,0, StringLen(message_text));
           
           //string _jt=CharArrayToString(message_data);
           //MessageBox(_jt);
           //--------------------------------------------------------------------------------------------------------------
           //------------------------------------------Http Post 请求服务器下载数据----------------------------------------
           
           ResetLastError();
         
           int res =WebRequest(RequestMethod, END_POINT_URL, headers, timeout, message_data, result, result_headers);
         
           if (res == -1)
           {
                Print("Error in WebRequest. Error code  =",GetLastError());
               //--- Perhaps the URL is not listed, display a message about the necessity to add the address
                MessageBox("Add the address '"+END_POINT_URL+"' to the list of allowed URLs on tab 'Expert Advisors'","Error",MB_ICONINFORMATION); 
           }
           else
           {
               if (res == 200)
               {
               //------------------------拆分result[] char数组串将导入list数组----------
               
                  //---------------------将Tushare返回的char数组合并成字符串处理过程--------------------------------------
                     string str=CharArrayToString(result,0,-1,0);  
                     
                     string str2=StringSubstr(str,172);
                     //Alert(str2);    
                     //int rc=StringReplace(str2,"\"","");
                     int rc=StringReplace(str2,"[","");
                     rc+=StringReplace(str2,"]","\r\n");
                     
                     
                     //----------------------将处理好的字符串分装到周期字符串数组------------------------------------------- 
                     string sep="\r\n";                            // 分隔符为字符 
                     ushort u_sep;                                 // 分隔符字符代码 
                     //--- 获得分隔符代码 
                     u_sep=StringGetCharacter(sep,0); 
                     //--- 字符串分为子字符串 
                     int k=StringSplit(str2,u_sep,list);     //---用分隔符切分周期字符串并装入数组
                     list[0]=","+list[0];
               
                     //----------------进一步处理周期字符串数组提取股票代码装入list数组中------------------------------------- 
 
                     
                     k=k-2;
                   
                     
                     for(int i=0;i<k;i++)
                     {
                       string list_Arr[];
                       sep=",";
                       u_sep=StringGetCharacter(sep,0);
                       int m=StringSplit(list[i],u_sep,list_Arr); 
 
                       //提取股票代码装入list数组中
                       list[i]=list_Arr[1];
                       rc+=StringReplace(list[i],"\"","");
                       StringTrimLeft(list[i]);
                       
                       //MessageBox(list[i]);
 
                     }            
                     //-------------------------------------------------------------------------------------------------------
               
               }
               else
                   PrintFormat("Error in download '%s', code %d", END_POINT_URL, res);
           }
           

}





附加的文件:
Mars Yuan  
因论坛篇幅64000字和24小时发帖一篇限制,整体文章需要6次6天发完,各个股日线及分钟线将在后续发布
Di Wan  
非常棒的文章,感谢分享!
Chuang  
感谢分享!学到不到东西。
canbaojun  
非常感谢有这样好的文章开源,太难得了,甚至有好些就是把开源的文章换下壳就挂出收费!
Mars Yuan  

1:Mql5自定义品种 A股(1)  ----个股列表数据处理过程

https://www.mql5.com/zh/forum/329854

2:Mql5自定义品种 A股(2)  ----个股日线“除权”数据处理过程

https://www.mql5.com/zh/forum/329945

3:Mql5自定义品种 A股(3)  ----个股日线“复权”数据处理过程

https://www.mql5.com/zh/forum/330159

4:Mql5自定义品种 A股(4)  ----A股指数数据处理过程

5:Mql5自定义品种 A股(5)  ----个股分钟线处理过程
6:Mql5自定义品种 A股(6)  ----指标及EA 应用
reasonliu  
感谢分享,楼主好人
Yu Zhang  
谢谢楼主分享
z44677265  
非常感谢,感谢你的分享
z44677265  
请问Http协议Post方式读取股票名称是中文,但是我们下载下来的却是U开头的字符串,这个要怎么转换
Mars Yuan  
z44677265:
请问Http协议Post方式读取股票名称是中文,但是我们下载下来的却是U开头的字符串,这个要怎么转换

字符串转码啊! Unicode——ASCII

原因: