还剩14页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
如何从MQL5MQL4访问MySQL数据库介绍MQL与数据库的交互问题并非新事物,但它们依然是相关的利用数据库可以极大增强MetaTrader的可塑性:存储并分析__历史,从一个交易平台拷贝交易至另一个平台,提供实时报价/交易,在服务器端定期进行深度分析计算,使用web技术监视并远程控制账户总之,有许多种应用尝试从MQL和MySQL的组合之中获益,一些方案已经在代码库里出现例如 MySQL包装-用于MetaTrader4的链接库https://___.mql
5.com/en/code/8623\t_blank ____的项目,许多程序员开始自己__,在将来还可扩充我认为,这种解决方案的缺点之一是分配特殊数组用来从数据库中读数据另一个项目 MySQL日志1-用于MetaTrader4的EAhttps://___.mql
5.com/ru/code/9815\t_blank 更加专业,它不使用包装来访问标准链接库libmysql.dll因此,它不能在MetaTrader4编译版600+上工作,由于 char 字符类型已经被 wchar_t 替代,且使用 int 类型替代了 TMYSQL 结构指针,导致在项目中产生内存泄漏内存分配不能控制/释放另一个有趣的项目是 EAX_Mysql-MySQL链接库-用于MetaTrader5的链接库https://___.mql
5.com/zh/code/855\t_blank它是十分出色的实现不过__列出了一些缺点,在使用时有强制限制任何人若需要在他们的项目中使用数据库,有两个选项:要么__自己的解决方案,并了解它的每一个部分,或者使用/改编任何第三方解决方案,了解如何使用它们并检测是否会阻碍他们的项目在我__一个相当复杂的自动交易时,就要面对这样的必要性和两个选项依照现有项目经过搜索,且研究了很多的解决方案后,我意识到,已发现的实施方案均无助于把我的自动交易提升到“专业水平”此外,也有些荒谬的方案,例如:使用标准libmysql.dll执行DML/DDL操作插入/更新/删除数据在数据库中创建/废弃对象以及将数据检索SELECT的实现作为HTTP请求使用inet.dll与MySQL服务器端的web服务器上的PHP脚本通信而SQL查询被写在PHP脚本中换句话说,要运行该项目,一定需要保证下述所有部件准备妥当,配置好并运行MySQL服务器,Apache/IISWeb服务器,在服务器端的PHP/ASP脚本...大量技术的组合当然,在某些情况下,这是可以接受的,但当唯一的任务就是从数据库中查询数据-那么这些全无意义此外,支持如此累赘的方案也耗费时间大部分的方案在插入数据,创建对象等等操作时没有问题问题在于数据查询,因为数据将会被返回调用环境我认为出于此目的而使用数组是不切实际的和不方便的,简单的原因就是在主程序的__/调试/支持过程中,数据库查询是可以变化的,而您也要正确控制为数组分配的内存..那么,这些可以,而且必须要避免下文讨论的MQL-MySql的接口基于OraclePL/SQLMSSQLT-SQLAdoDB等产品内使用的典型方式-使用游标这个接口的__目标是易于编程和维护,再加上最少元部件它作为DLL包装器实现,连接标准链接库libmysql.dll,且接口函数__作为一个.mqh文件
1.MQL-MySQL接口在MetaTrader终端之间交互通过MQL程序可以在如下元部件的帮助下实现:
1.接口库MQLMySQL.mqh.使用 #include 语句将它加到项目工程里,并且可以按照您的喜好进行修改它包含的指令用于导入MQLMySQL.dll动态库的函数,以及调用它们和处理错误的函数
2.MQLMySQL.dll动态库这是一个包装器,用来访问标准库libmysql.dll的功能此外,MQLMySQL.dll链接库处理操作的结果并共享访问数据库的连接和游标这意味着您可以在同一时间创建和使用多个连接来自一个或多个MQL程序保持少量的打开游标查询一个或多个数据库互斥则用于分隔访问共享资源
3.标准动态链接库libmysql.dll是本地访问驱动器您可以从任何MySql数据库的发布位置C:\Windows\Sytem32或终端\MQL5\Libraries对于MetaTrader4在终端\MQL4\Libraries中拷贝它事实上,它负责发送查询到数据库并接收检索结果让我们来详述要点,诸如:打开/关闭连接执行DML/DDL查询和数据检索
1.
1.打开和关闭连接该MySqlConnect函数已经实现了打开与MySQL数据库的连接:类型名称参数描述intMySqlConnect该功能已实现与数据库的连接并返回一个连接标识符这个ID在数据库查询时需要在连接失败情况下,则返回值-1对于错误详情,检查变量 MySQLErrorNumber 和 MySqlErrorDescription典型地,这个函数在MQL程序处理 OnInit __时调用string pHost这是MySQL服务器的域名或IP地址string pUser数据库用户名例如rootstring pPassword数据库用户的口令string pDatabase数据库名称int pPort数据访问的TCP/IP端口通常是3306string pSocketUnix套接对于Unix基准的系统int pClientFlag特殊标志组合通常是0该MySqlDisconnect接口函数已实现关闭连接:类型名称参数描述voidMySqlDisconnect此函数关闭与MySQL数据库的连接典型地,这个函数在MQL程序处理 OnDeinit __时调用int pConnection连接标识符应当注意的是,MySQL数据库在硬件故障时,网络拥塞或超时若长时间无查询发送到数据库,能够自行关闭连接__者经常利用 OnTickhttps://___.mql
5.com/zh/docs/basis/function/events\lontick\t_blank __写数据至数据库然而,当周末来临,市场闭市,连接仍然在“悬挂”在此情况下MySQL将超时关闭省缺是8小时而周一,当市场开市,系统发现连接错误因此,强烈建议每隔一段时间就检查连接,并且/或者重新连接服务器,时间间隔应稍小于MySQL服务器设置中指定的超时数值
1.
2.执行DML/DDL查询DML操作用于数据操纵数据操纵语言数据操纵包括以下语句__:INSERTUPDATE和DELETEDDL操作用于数据定义数据定义语言这些包括创建CREATE数据库对象表视图存储过程触发器等等以及修改ALTER和删除DROP这些不是全部的DML/DDL语句此外DCL数据控制语言用于分隔数据访问但我们不会深入探讨SQL的特性所有这些命令都可以使用MySqlExecute接口函数执行:类型名称参数描述boolMySqlExecute这个函数用来在数据库成功建立之后使用 MySqlConnect 函数,执行非SELECT的SQL语句如果命令执行成功,函数返回true,否则-false有关错误详情使用 MySQLErrorNumber 和MySqlErrorDescriptionint pConnection连接标识符string pQuerySQL查询作为一个SQL查询,您也可以使用USE命令选择数据库我想提醒一下使用复合语句的查询它是SQL命令__,分隔字符;要启用复合语句模式,打开数据库连接时应携带CLIENT_MULTI_STATEMENTS标志:...intClientFlag=CLIENT_MULTI_STATEMENTS;//Settingthemulti-statementsflagintDB;DB=MySqlConnectHostUserPasswordDatabasePortSocketClientFlag;//ConnectiontothedatabaseifDB==-1 { //Handlingtheconnectionerror }...//PreparingaSQLquerytoinsertdata3rowsinonequerystringSQL;SQL=INSERTINTOEURUSDAskBidVALUES
1.
36011.3632;;SQL=SQL+INSERTINTOEURUSDAskBidVALUES
1.
36211.3643;;SQL=SQL+INSERTINTOEURUSDAskBidVALUES
1.
36051.3629;;...if!MySqlExecuteDBSQL { //Showinganerrormessage }...在这个片段中,利用单次调用数据库,3个条目将__入EURUSD表中存储在SQL变量中的每个查询,通过;分隔这种方法可用来频繁插入/更新/删除;必要的命令__组合到一个包中,从而减轻了网络流量,并提高数据库的性能在MySQL中,INSERT语法对异常处理十分出色例如,如果任务是____历史,应该创建一个对应货币对的表,其主键是日期型,因为柱线的日期和时间都是唯一的此外,应该检查是否任意特定的柱线数据都存在于数据库中提高数据迁移的稳定性对于MySQL不需要这项检查因为INSERT语句支持ONDUPLICATEKEY简单来说如果尝试插入数据且表中已经有一个记录带有相同日期和时间则INSERT语句可以被忽视,或此行被UPDATE替换参见http://dev.mysql.com/doc/ref__n/
5.0/en/insert-on-duplicate.htmlhttp://___.mql
5.com/gohttp://dev.mysql.com/doc/ref__n/
5.0/en/insert-on-duplicate.html\ohttp://dev.mysql.com/doc/ref__n/
5.0/en/insert-on-duplicate.html\t_blank
1.
3.数据检索SQLSELECT语句用于从数据库中检索数据下面的操作序列用于检索数据并返回检索的结果
1.准备SELECT语句
2.打开游标
3.获得查询回的行数
4.循环获取结果的每一行
5.在循环内将数据赋值给MQL变量
6.关闭游标当然,这是常用规划,所以并非每种情况都需要全部操作例如,如果您打算确认表中存在一行数据按照任意标准这对于准备查询足够了打开游标得到行数并关闭游标事实上,强制部分是-准备SELECT语句,打开和关闭游标什么是游标?它是针对一片具有逻辑关系的内存区域的引用实际上-结果数值的__当您发送SELECT查询数据库为结果分配内存并创建行指针,您可以利用其在数据行之间__因此,可以按顺序访问按照查询定义的队列的每一行SELECT语句的ORDERBY子句以下接口函数用于数据检索:打开游标:类型名称参数描述intMySqlCursorOpen这个函数为SELECT查询打开一个游标,若成功则返回游标标识符否则函数返回-1为了查找错误原因使用变量 MySQLErrorNumber 和MySqlErrorDescriptionint pConnection数据库连接标识符string pQuerySQL查询SELECT语句获得查询返回的行数:类型名称参数描述intMySqlCursorRows这个函数返回查询的检索行数int pCursorID由 MySqlCursorOpen 返回的游标标识符取查询数据行:类型名称参数描述boolMySqlCursorFetchRow从查询返回的数据__中取一行数据在成功执行之后您可以将数据赋值到MQL变量若成功函数返回true否则返回falseint pCursorID由 MySqlCursorOpen 返回的游标标识符取查询数据行之后,赋值到MQL变量:类型名称参数描述intMySqlGetFieldAsInt函数以 inthttps://___.mql
5.com/zh/docs/basis/types/integer/integertypes\lint\t_blank 数据类型返回数据表字段的值int pCursorID由 MySqlCursorOpen 返回的游标标识符int pField在SELECT中的字段号码起始编号为0doubleMySqlGetFieldAsDouble函数以 doublehttps://___.mql
5.com/zh/docs/basis/types/double\t_blank 数据类型返回数据表字段的值int pCursorID由 MySqlCursorOpen 返回的游标标识符int pField在SELECT中的字段号码起始编号为0datetimeMySqlGetFieldAsDatetime函数以 datetimehttps://___.mql
5.com/zh/docs/basis/types/integer/datetime\t_blank 数据类型返回数据表字段的值int pCursorID由 MySqlCursorOpen 返回的游标标识符int pField在SELECT中的字段号码起始编号为0stringMySqlGetFieldAsString函数以 stringhttps://___.mql
5.com/zh/docs/basis/types/strin__onst\t_blank 数据类型返回数据表字段的值int pCursorID由 MySqlCursorOpen 返回的游标标识符int pField在SELECT中的字段号码起始编号为0所有MySQL返回的数据都有本地表达方式不仅表达为字符串因此,使用这些函数,您可以将所选的数据转换为所需的类型唯一不足的是,在SELECT清单中,用列编号(起始编号为0)替代了它的名字不过,当__一个应用程序时,准备SELECT语句并获取结果几乎都在一个页面,所以当您规定数据获取逻辑时,您可以看到SELECT查询因此,您总能知道在SELECT清单中的字段数量这种方式也同样适用于访问AdoDB的数据好了,这部分可以在以后修改它对方案中的功能__只是略有影响关闭游标:类型名称参数描述voidMySqlCursorClose这个函数关闭指定的游标并释放内存int pCursorID由 MySqlCursorOpen 返回的游标标识符关闭游标是一个关键操作 不要忘记关闭游标想象一下您打开了一个游标,并忘记关闭它设想,每次即时报价到达,处理 OnTickhttps://___.mql
5.com/zh/docs/basis/function/events\lontick\t_blank __时,数据都要通过游标检索,并且每次都打开一个新游标,并为其分配内存客户端与服务器端两者相同在某一时刻,服务器将拒绝服务,因为到达打开游标限制,并且导致缓存区溢出当然,这有点夸张,这样的结果可能在与libmysql.dll直接工作的时候出现不过,MQLMySQL.DLL动态链接库为游标分配内存,并将在超出了允许的限制时拒绝打开新游标当执行实际任务时,保持2-3个打开游标就足够了每个游标可以处理一个笛卡尔尺寸的数据;并发使用二至三个游标嵌套,例如,一个参数依赖于另一个游标可覆盖二至三个维度对于大多数任务这是完全正常的此外,为了实现复杂的数据检索,您可以随时使用这些对象来代表数据库视图,在服务器端创建它们,并从MQL代码里发送查询,就如同数据表一样
1.
4.附加信息下面提到的可以作为附加特征:
1.
4.
1.从一个.INI文件中读取数据类型名称参数描述StringReadIni返回INI文件中给定段落的键值stringpFileNameINI文件名filestringpSection段落名stringpKey键名经常在MQL代码(或在EA、指标、脚本的参数)中直接保存有关数据库连接的信息(服务器的IP地址端口用户名口令等等)是不理性的,因为服务器也许会转移,它的地址也会动态变化,等等在这种情况下您将需要修改MQL代码因此,所有这些数据应该最好被存储在标准.INI文件里,而只将它的名称写在MQL程序中然后,使用ReadINI函数来读取连接参数,并使用它们例如,INI文件包含以下信息:[MYSQL]Server=
127.
0.
0.1User=rootPassword=Adm1n1str@t0rDatabase=mysqlPort=3306为了得到服务器IP地址,执行以下语句:stringvServer=ReadIniC:\\MetaTrader5\\MQL5\\Experts\\MyConnection.iniMYSQLServer;该INI文件被放置于C:\MetaTrader5\MQL5\Experts并且称为MyConnection.ini,您可以访问 MYSQL 段落的 Server 键值在一个INI文件中您可以保存多个您的项目中用到的服务器设置
1.
4.
2.问题区域追踪在接口库中提供了追踪模式,可以启用该模式来调试MQL程序中任意位置的SQL查询在问题区域指定如下:SQLTra__=true;或是SQLTra__=false;如果您在MQL程序开始启用追踪,并且未禁用它,则所有数据库调用都将被记录而记录被保持在终端的控制台里使用Print命令
2.例程这一段提供了一些连接和使用已__的链接库的例程参阅它们并评估软件解决方案的可用性例程 MySQL-
003.mq5 出示如下:连接数据库连接参数保存在.ini文件创建数据表插入数据也用到复合语句以及从数据库断开连接//+------------------------------------------------------------------+//| MySQL-
003.mq5|//| Copyright2014EugeneLugovoy|//| http://___.mql
5.com|//|Insertingdatawithmulti-statementDEMO |//+------------------------------------------------------------------+#propertycopyrightCopyright2014EugeneLugovoy.#propertylink http://___.mql
5.com#propertyversion
1.00#propertystrict#includeMQLMySQL.mqhstringINI;//+------------------------------------------------------------------+//|Scriptprogramstartfunction |//+------------------------------------------------------------------+voidOnStart{stringHostUserPasswordDatabaseSocket;//databasecredentialsintPortClientFlag;intDB;//databaseidentifierPrintMySqlVersion;INI=TerminalInfoStringTERMINAL_PATH+\\MQL5\\Scripts\\MyConnection.ini;//readingdatabasecredentialsfromINIfileHost=ReadIniINIMYSQLHost;User=ReadIniINIMYSQLUser;Password=ReadIniINIMYSQLPassword;Database=ReadIniINIMYSQLDatabase;Port =intStringToIntegerReadIniINIMYSQLPort;Socket =ReadIniINIMYSQLSocket;ClientFlag=CLIENT_MULTI_STATEMENTS;//intStringToIntegerReadIniINIMYSQLClientFlag; PrintHost:HostUser:UserDatabase:Database;//opendatabaseconnectionPrintConnecting...;DB=MySqlConnectHostUserPasswordDatabasePortSocketClientFlag;ifDB==-1{PrintConnectionfailed!Error:+MySqlErrorDescription;}else{PrintConnected!DBID#DB;}stringQuery;Query=DROPTABLEIFEXISTS`test_table`;MySqlExecuteDBQuery;Query=CREATETABLE`test_table`idintcodevarchar50start_datedatetime;ifMySqlExecuteDBQuery { PrintTable`test_table`created.; //Insertingdata1row Query=INSERTINTO`test_table`idcodestart_dateVALUES+stringAccountInfoIntegerACCOUNT_LOGIN+\ACCOUNT\\+TimeToStringTimeLocalTIME_DATE|TIME_SECONDS+\; ifMySqlExecuteDBQuery { PrintSuc__eded:Query; } else { PrintError:MySqlErrorDescription; PrintQuery:Query; } //multi-insert Query= INSERTINTO`test_table`idcodestart_dateVALUES1\EURUSD\\
2014.
01.0100:00:01\;; Query=Query+INSERTINTO`test_table`idcodestart_dateVALUES2\EURJPY\\
2014.
01.0200:02:00\;; Query=Query+INSERTINTO`test_table`idcodestart_dateVALUES3\USDJPY\\
2014.
01.0303:00:00\;; ifMySqlExecuteDBQuery { PrintSuc__eded!3rowshasbeeninsertedbyonequery.; } else { PrintErrorofmultiplestatements:MySqlErrorDescription; } }else { PrintTable`test_table`cannotbecreated.Error:MySqlErrorDescription; }MySqlDisconnectDB;PrintDisconnected.Scriptdone!;}例程 MySQL-
004.mq5 出示从数据表中检索数据,该表通过MySQL-
003.mq5脚本创建 //+------------------------------------------------------------------+//| MySQL-
004.mq5|//| Copyright2014EugeneLugovoy|//| http://___.mql
5.com|//|SelectdatafromtableDEMO |//+------------------------------------------------------------------+#propertycopyrightCopyright2014EugeneLugovoy.#propertylink http://___.mql
5.com#propertyversion
1.00#propertystrict#includeMQLMySQL.mqhstringINI;//+------------------------------------------------------------------+//|Scriptprogramstartfunction |//+------------------------------------------------------------------+voidOnStart{stringHostUserPasswordDatabaseSocket;//databasecredentialsintPortClientFlag;intDB;//databaseidentifierPrintMySqlVersion;INI=TerminalInfoStringTERMINAL_PATH+\\MQL5\\Scripts\\MyConnection.ini;//readingdatabasecredentialsfromINIfileHost=ReadIniINIMYSQLHost;User=ReadIniINIMYSQLUser;Password=ReadIniINIMYSQLPassword;Database=ReadIniINIMYSQLDatabase;Port =intStringToIntegerReadIniINIMYSQLPort;Socket =ReadIniINIMYSQLSocket;ClientFlag=intStringToIntegerReadIniINIMYSQLClientFlag; PrintHost:HostUser:UserDatabase:Database;//opendatabaseconnectionPrintConnecting...;DB=MySqlConnectHostUserPasswordDatabasePortSocketClientFlag;ifDB==-1{PrintConnectionfailed!Error:+MySqlErrorDescription;return;}else{PrintConnected!DBID#DB;}//executingSELECTstatementstringQuery;int iCursorRows;int vId;string vCode;datetimevStartTime;Query=SELECTidcodestart_dateFROM`test_table`;PrintSQLQuery;Cursor=MySqlCursorOpenDBQuery;ifCursor=0 { Rows=MySqlCursorRowsCursor; PrintRowsrowsselected.; fori=0;iRows;i++ ifMySqlCursorFetchRowCursor { vId=MySqlGetFieldAsIntCursor0;//id vCode=MySqlGetFieldAsStringCursor1;//code vStartTime=MySqlGetFieldAsDatetimeCursor2;//start_time PrintROW[i]:id=vIdcode=vCodestart_time=TimeToStringvStartTimeTIME_DATE|TIME_SECONDS; } MySqlCursorCloseCursor;//NEVERFORGETTOCLOSECURSOR!!! }else { PrintCursoropeningfailed.Error:MySqlErrorDescription; } MySqlDisconnectDB;PrintDisconnected.Scriptdone!;}以上例程包含在实际项目中运用的典型错误处理事实上,在MQL程序中使用的每个查询,都应该在任意MySQL客户端上进行调试(PHPMyAdmin中,DBNinja,MySQL控制台)我个人使用并推荐专业数据库__软件QuestTOAD的MySQL版本结论本文并未详细介绍MQLMySQL.DLL如何在MicrosoftVisualStudio2010C/C++环境里__与实现该软件解决方案是专为特别应用设计,并且在多种MQL软件__领域,有超过100种成功实现来自创建复杂的交易系统至Web发布适用于MQL4和MQL5的链接库版本附加在下面附件也包括一个zip文件,内有MQLMySQL.DLL的源代码;文档也包括在存档中;若使用该例程不要忘记在文件\Scripts\MyConnection.ini中指定您的数据库连接参数。