MQL5 (MQL4)から MySQL データベースにアクセスする方法
Eugeniy Lugovoy | 23 12月, 2015
はじめに
MQL とデータベースの連携問題は新しいものではありませんが、それでも関連性のあるものです。データベースの利用は MetaTrader の機能を大いに強化します。:価格履歴の格納と分析、あるトレーディングプラットフォームから別のプロットフォームへのトレードコピー、サーバー側での思い分析的計算および/またはスケジュールの使用、モニター、ウェブ技術を利用しての遠隔でのアカウント管理。
いずれにしてもMQL と MySQLの組合せで利益を得ようとする試みは数多くあります。ソリューションの中には CodeBaseで利用可能なものもあります。
たとえば "MySQL wrapper - library for MetaTrader 4" はプロジェクトで、そこから多くのプログラマーが更なる追加を加えて自分自身の開発を始めるのです。私見ですが、このソリューションの欠点のひとつはデータベースからデータを読むための特殊配列の割当てです。
もうひとつ別のプロジェクト "MySQL logger 1 - EA for MetaTrader 4" は専門性の高いのもので、標準ライブラリlibmysql.dll にアクセスするのにそれはラッパーを使用しません。. そのため、MetaTrader4 Build 600+では動作しません。char 文字タイプが wchar_tで置換され、 TMYSQLストラクチャポインターの代わりに int タイプを使用するとプロジェクト内でメモリリークを起こしてしまうためです(割り当てられたメモリが制御/解放できません)。
その他興味深いプロジェクトは "EAX_Mysql - MySQL library - library for MetaTrader 5"です。それはひじょうにすぐれた実装です。著者によるデメリットのリストはそれを使用するのにくらか制限を課します。
プロジェクト内でデータベースを使用する必要のある人には選択肢が2つあります。:自分でソリューションを作成し、隅々まで知るか、または第三者ソリューションを使用/採用し、それの使用法を学びプロジェクト支障をきたす可能性のある欠陥をすべて検出するかです。
私はそのような必要性があり、かなり複雑な売買ロボット開発中にその2つの選択肢に直面しました。既存のプロジェクトを検索し、ひじょうに多くのソリューションを調査して、私はみつけた実装がどれとして私の売買ロボットを『プロレベル』にする役に立たないのが判ったのです。
また、異常なソリューションもありました。たとえば、DML/DDL 処理(挿入/更新/データ削除/データベース内オブジェクトの作成/ドロップ)が標準 libmysql.dll を使用して行われたり、データ選択(SELECT)は実際に HTTP リクエスト(inet.dllを使用して)としてMySQL サーバー側のウェブサーバーに置かれている PHP スクリプトに実装されていたのです。SQL クエリは PHP スクリプト内に書かれています。
別の言い方をすれば、プロジェクトを実行するためには、次のコンポーネントが利用可能であるようにし構成されており、実行し続ける必要があります。:MySQL サーバー、Apache/IIS ウェブサーバー、サーバー側の PHP/ASP スクリプトなど。かなり多数の技術の組合せです。もちろんある状況ではこれは可能かもしれませんが、ただ一つのタスクがデータベースからのデータ選択であれば、これはナンセンスです。その上、そのような面倒なソリューションをサポートすることは時間がかかります。
ソリューションのほとんどはデータ挿入、オブジェクト作成などすになにも問題はありません。問題はデータ選択です。データは環境を呼びだすために返されるためです。
私はこの目的で配列を使用することは実用的でなく不便であると思います。それは単純に開発/デバッグ/メインプロジェクトのサポートの過程でデータベースに対してクエリを選択することは変更可能で、一方で配列に対する正しいメモリ割り当てを管理する必要があるためです。これは避けられるし、避けるべきです。
これ以降、話の対象となる MQL ⇔MySql 間の連携はOracle PL/SQL、 MS SQL T-SQL、AdoDB で使用される典型的な方法に基づきます。カーソル使用です。このインターフェースはプログラミング、管理を容易にし、プラスコンポーネントを最小にすることを目標として作成されました。それは標準ライブラリ libmysql.dll に対する 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 または <Terminal>\MQL5\Libraries(<Terminal>\MQL4\LibrariesのMetaTrader 4 向け)
実際、それはデータベースにクエリを送信し、結果を取得します。
接続のオープン/クローズ、 DML/DDL クエリの実行とデータ選択などの主なポイントについて深くお話します。
1.1. 連結の開始と終了
MySqlConnect 関数は MySQL データベースとの接続をオープンするために実装されています。
タイプ |
名前 |
パラメータ |
説明 |
int |
MySqlConnect |
この関数はデータベースとの連結を実装し、連結識別子を返します。この ID はデータベースに問い合わせをするのに必要とされます。 連結が失敗した場合、戻り値は"-1" です。エラー詳細については、変数MySQLErrorNumber および MySqlErrorDescriptionを確認します。 この関数は一般的に MQL プログラム内でOnInit() イベントを処理するときに呼ばれます。 |
|
string pHost |
MySQL サーバーの DNS 名、または IP アドレス |
||
string pUser |
データベースユーザー(たとえばルート) |
||
string pPassword |
データベースユーザーのパスワード |
||
string pDatabase |
データベース名 |
||
int pPort |
データベースの TCP/IP ポート(通常 3306) |
||
string pSocket |
Unix ソケット(Unix ベースシステム向け) |
||
int pClientFlag |
特殊フラグの組合せ(通常 0) |
MySqlDisconnect インターフェース関数は連結を終了するために実装されています。
タイプ |
名前 | パラメータ | 説明 |
void |
MySqlDisconnect |
この関数は MySQL との接続を終了します。 この関数は一般的に MQL プログラム内でOnDeinit() イベントを処理するときに呼ばれます。 |
|
int pConnection |
連結識別子 |
MySQL データベースはハードウェア不良、ネットワークの混雑、タイムアウト(長時間クエリがまったくデータベースに送信されない場合)の場合自分で接続を終了することができることに注意が必要です。
開発者はデータベースにデータを書くのにe OnTick() イベントを使うことがよくあります。ただし、週末がやってきてマーケットが閉まると、接続はまだ『ハング』しています。この場合、はタイムアウト(デフォルトで8時間)で閉じます。
そして月曜日、マーケットが開始されるとプロジェクトにエラーが見つかります。よってサーバーの設定で指定したタイムアウトよりも小さい時間間隔でデータベースへの接続および/または再接続を確認することを強くお薦めします。
1.2. DML/DDL クエリの実行
データ操作のためにDML 処理が利用されます(Data Manipulation Language)。データ操作には次のステートメントセットが入っています。:INSERT、 UPDATE、DELETE。
データ定義にはDDL 処理が使用されます(Data Definition Language)。これにはデータベースオブジェクト(テーブル、ビュー、格納された手続き、トリガなど)の作成(CREATE)とその変更(ALTER)、削除(DROP)が入ります。
それは DML/DDL ステートメントのすべてではなく、それ以上にDC(Data Control Language)がデータアクセスを分離するのに使用されますが、SQLの特徴については細かく調べません。これらコマンドはいずれもMySqlExecute インターフェース関数によって実行されます。
タイプ |
名前 |
パラメータ |
説明 |
bool |
MySqlExecute |
この関数は、データベースとの接続が正常におこなわれたあと、SQL の非SELECT ステートメントを実行するのに使用されます( MySqlConnect 関数によって)。 コマンドが正常に実行される場合、この関数は真を、それ以外は偽を返します。エラー詳細については、 MySQLErrorNumber と MySqlErrorDescriptionを使用します。 |
|
int pConnection |
連結識別子 |
||
string pQuery |
SQL クエリ |
SQL クエリとしてデータベースを選択するのに USE コマンドを使用することもできます。マルチステートメントのクエリの使用についてお話したいと思います。それは SQL コマンドのセット文字 ";" によって分離されます。
マルチステートメントモードを有効にするには、データベースとの接続は CLIENT_MULTI_STATEMENTS フラグでオープンする必要があります。
... int ClientFlag = CLIENT_MULTI_STATEMENTS; // Setting the multi-statements flag int DB; DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); // Connection to the database if (DB == -1) { // Handling the connection error } ... // Preparing a SQL query to insert data (3 rows in one query) string SQL; SQL = "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3601,1.3632);"; SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3621,1.3643);"; SQL = SQL + "INSERT INTO EURUSD(Ask,Bid) VALUES (1.3605,1.3629);"; ... if (!MySqlExecute(DB,SQL)) { // Showing an error message } ...
このフラグメントでは、データベースへの呼び出し1件で EURUSD テーブルに3エントリーが挿入されます。SQL 変数に格納されるクエリはすべて ";" によって区切られます。
頻繁に挿入/更新/削除するにはこの方法が利用されます。必要なコマンドセットが一つの『パッケージ』にコンバインされ、そのためネットワークトラフィックは緩和され、データベースのパフォーマンスは向上します。
MySQL 内の INSERT 構文は例外処理に関してはひじょうによくできています。
たとえば、バーの日付と時刻はユニークであるため、タスクが価格履歴を移動することであれば、datetime タイプの主キーを持つ通貨ペアに対してテーブルが作成されます。その上、任意の個別バーのデータがデータベースに存在するか確認します(データ移植の安定性を向上するため)。MySQL ではこの確認は必要さりません。それは INSERT ステートメントが ON DUPLICATE KEY をサポートするためです。
簡単に言えば、データ挿入が試みられ、テーブルがすでに同じ日時のエントリーを持っていると、 INSERT ステートメントが無視されるか、この行については UPDATE と置き換えられます(http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.htmlを参照ください)。
1.3. データ選択
SQL SELECT ステートメントはデータベースからデータを取得するてめに使用されます。以下のアクションのシーケンスはデータ選択と選択結果取得に使用されます。
- SELECT ステートメントの準備
- カーソルのオープン
- クエリが返す行番号取得
- クエリの行をすべてループし取得
- ループ内で MQL 変数に対するデータフェッチ
- カーソルのクローズ
もちろんこれは一般的スキームですから、すべての処理がすべての場合に必要なわけではありません。たとえば、テーブルにある行が存在する(任意の基準によって)ことを確認したいなら、クエリを準備、カーソルオープン、行番号取得、カーソルクローズ、で十分です。実際、必須部分は SELECT ステートメントの準備、カーソルのオープンとクローズです。
カーソルとは?これはコンテキストメモリ領域の参照で、実際には結果の値セッです。SELECT クエリを送信すると、データベースが結果に対してメモリを割り当て、ある行から別の行に移動するある行に対するポインターを作成します。よってクエリによって決められるキュー( SELECT ステートメントのORDER BY 節)のオーダー内の行すべてにアクセスすることは可能なのです。
データ選択には以下のインターフェース関数が使用されます。
カーソルのオープン
タイプ |
名前 |
パラメータ |
説明 |
int |
MySqlCursorOpen |
この関数は SELECT クエリに対してカーソルをオープンし、正常にオープンした場合にはカーソル識別子を返します。それ以外は "-1" を返します。エラー原因を見つけるには、変数MySQLErrorNumber および MySqlErrorDescriptionを使用します。 |
|
int pConnection |
データベースとの接続識別子 |
||
string pQuery |
SQL クエリ(SELECT ステートメント) |
クエリによって返される行ナンバー取得
タイプ |
名前 |
パラメータ |
説明 |
int |
MySqlCursorRows |
この関数はクエリによって選択される行ナンバーを返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
クエリ行をフェッチ
タイプ |
名前 |
パラメータ |
説明 |
bool |
MySqlCursorFetchRow |
クエリによって返されるデータセットから1行をフェッチ正常に実行したら、 MQL 変数に対するデータを取得します。この関数は正常にフェッチされると真と、それ以外は偽を返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
クエリ行フェッチ後の MQL 変数へのデータフェッチ
タイプ |
名前 |
パラメータ |
説明 |
int |
MySqlGetFieldAsInt |
この関数は int データタイプを使用してテーブルフィールド値の表示を返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
||
int pField |
SELECT リストのフィールドナンバー(番号は0から始まります) |
||
double |
MySqlGetFieldAsDouble |
この関数は double データタイプを使用してテーブルフィールド値の表示を返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
||
int pField |
SELECT リストのフィールドナンバー(番号は0から始まります) |
||
datetime |
MySqlGetFieldAsDatetime |
この関数は datetime データタイプを使用してテーブルフィールド値の表示を返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
||
int pField |
SELECT リストのフィールドナンバー(番号は0から始まります) |
||
string |
MySqlGetFieldAsString |
この関数は string データタイプを使用してテーブルフィールド値の表示を返します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
||
int pField |
SELECT リストのフィールドナンバー(番号は0から始まります) |
MySQL によって返されるデータはすべてネイティブ表現を持ちます(タイプや文字列なしで表される)。
よってこれら関数を使用して選択したデータを希望のタイプにキャストすることができます。唯一のマイナス面は名前ではなく SELECT リスト内で列ナンバー(番号はは0から始まります)を指定することです。ただ、アプリケーション開発の際には、SELECTステートメントの準備と結果取得はほとんどつねに1ページに収まり、データフェッチのロジックを指示するとき SELECT クエリを確認することができます。
よってつねにSELECT リスト内のフィールドナンバーがわかるのです(この方法は AdoDB を使用してデータにアクセスするときにも使います)。ところで、この部分は将来に改定する可能性があります。ただこれは作成のソリューションの機能にほとんど影響はありません。
カーソルのクローズ
タイプ |
名前 |
パラメータ |
説明 |
void |
MySqlCursorClose |
この関数は指定のカーソルをクローズしメモリを解放します。 |
|
int pCursorID |
MySqlCursorOpenによって返されるカーソル識別子 |
カーソルのクローズは重要な処理です。 カーソルのクローズを忘れないでください。
カーソルをオープンしてクローズするのを忘れるのを想像してください。データがe OnTick() イベントを処理する間、ティックごとにデータがカーソルに対して取得され、毎回新規カーソルがオープンし、メモリがそこに割り当てられるとします(クライアント側、サーバー側両方で)。ある時点で、サーバーが動作を拒否します。なぜならオープンしているカーソルの限界に達し、これはバッファのオーバーフローを生じるためです。
もちろんこれは大げさです。libmysql.dll と直接連携しているとそのような結果はありえます。ただし、MQLMySQL.DLL 動的ライブラリはカーソルにメモリを配布し、許容限度を超えたカーソルがオープンされるのを拒否します。
実タスクを実装するときは2~3カーソルをオープンしていれば十分です。カーソルはすべてデータのデカルト測定を行うことができます。;2~3のカーソルを同時に使用することは(たとえば 1 カーソルがパラメトリックに別のカーソルに依存する場合ネスト化)二次元または三次元をカバーします。これはほとんどのタスクにとって完璧に良いものです。その上、複雑なデータ選択の実装に対しては、常にこれらオブジェクトを使用し、データベース(VIEW)を表し、サーバー側でそれらを作成し、テーブルのように MQL コードからそれらにクエリを送信することができるのです。
1.4. 追加情報
以下で追加の機能についてお話します。
1.4.1. .INI ファイルからのデータ読み出し
タイプ |
名前 |
パラメータ |
説明 |
String |
ReadIni |
INI-file の与えられたセクションのキー値を返します。 |
|
string pFileName |
INI ファイル名 |
||
string pSection |
セクション名 |
||
string pKey |
キー名 |
MQL データベース(サーバーの IP アドレス、ポート、ユーザー名、パスワードなど)への接続についての情報を直接コード MQL(またはのパラメータ、スクリプトのインディケータ)で格納することは合理的でないことが多くあります。それはサーバーが移動しそのアドレスが動的に変わるなどの理由です。この場合は MQL コードを変更する必要があります。よってこれらデータは標準的な .INI ファイルに格納するのが得策です。同時に、その名前だけ MQL プログラムに記載します。それから ReadINI 関数を使用して接続パラメータを読み出し、それらを利用します。
たとえばINI ファイルには次の情報が入っています。
[MYSQL] サーバー = 127.0.0.1 ユーザー = root パスワード = Adm1n1str@t0r データベース = mysql ポート = 3306
サーバーの IP アドレスを取得するには以下を実行します。
string vServer = ReadIni("C:\\MetaTrader5\\MQL5\\Experts\\MyConnection.ini", "MYSQL", "Server");
INI ファイルは "MyConnection.ini" という名前で C:\MetaTrader5\MQL5\Experts にあります。MYSQL セクションの Server キーにアクセスします。1つの INI ファイルにご自身のプロジェクトを使用してさまざまなサーバーへの設定を格納することができます。
1.4.2. 問題部分の追跡
インターフェースでライブラリは追跡モードを提供します。それは MQLプログラムのどこででも SQL クエリのデバッグに対して有効にすることができます。
問題領域で以下を指定します。
SQLTrace = 真
それから
SQLTrace = 偽
MQL プログラムの冒頭で追跡を有効にし、無効にしないとデータベースに対するすべての呼び出しがログに入れられることとなります。ログはターミナルコンソールで維持されています。(Print コマンドによって)。
2. 例
このセクションでは接続と作成したライブラリの使用例が数点提供されます。それらを確認し、ソフトウェアソリューションのユーザビリティについて推定します。
MySQL-003.mq5 例は次のことを示します。データベースへの接続(接続パラメータは .ini ファイルに格納されます)、テーブル作成、データ挿入(マルチステートメントも使用して)、データベースからの切断。
//+------------------------------------------------------------------+ //| MySQL-003.mq5 | //| Copyright 2014, Eugene Lugovoy | //| https://www.mql5.com | //| Inserting data with multi-statement (DEMO) | //+------------------------------------------------------------------+ #property copyright "Copyright 2014, Eugene Lugovoy." #property link "https://www.mql5.com" #property version "1.00" #property strict #include <MQLMySQL.mqh> string INI; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { string Host, User, Password, Database, Socket; // database credentials int Port,ClientFlag; int DB; // database identifier Print (MySqlVersion()); INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini"; // reading database credentials from INI file Host = ReadIni(INI, "MYSQL", "Host"); User = ReadIni(INI, "MYSQL", "User"); Password = ReadIni(INI, "MYSQL", "Password"); Database = ReadIni(INI, "MYSQL", "Database"); Port = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port")); Socket = ReadIni(INI, "MYSQL", "Socket"); ClientFlag = CLIENT_MULTI_STATEMENTS; //(int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag")); Print ("Host: ",Host, ", User: ", User, ", Database: ",Database); // open database connection Print ("Connecting..."); DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); if (DB == -1) { Print ("Connection failed!Error: "+MySqlErrorDescription); } else { Print ("Connected!DBID#",DB);} string Query; Query = "DROP TABLE IF EXISTS `test_table`"; MySqlExecute(DB, Query); Query = "CREATE TABLE `test_table` (id int, code varchar(50), start_date datetime)"; if (MySqlExecute(DB, Query)) { Print ("Table `test_table` created."); // Inserting data 1 row Query = "INSERT INTO `test_table` (id, code, start_date) VALUES ("+(string)AccountInfoInteger(ACCOUNT_LOGIN)+",\'ACCOUNT\',\'"+TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS)+"\')"; if (MySqlExecute(DB, Query)) { Print ("Succeeded: ", Query); } else { Print ("Error: ", MySqlErrorDescription); Print ("Query: ", Query); } // multi-insert Query = "INSERT INTO `test_table` (id, code, start_date) VALUES (1,\'EURUSD\',\'2014.01.01 00:00:01\');"; Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (2,\'EURJPY\',\'2014.01.02 00:02:00\');"; Query = Query + "INSERT INTO `test_table` (id, code, start_date) VALUES (3,\'USDJPY\',\'2014.01.03 03:00:00\');"; if (MySqlExecute(DB, Query)) { Print ("Succeeded!3 rows has been inserted by one query."); } else { Print ("Error of multiple statements: ", MySqlErrorDescription); } } else { Print ("Table `test_table` cannot be created. Error: ", MySqlErrorDescription); } MySqlDisconnect(DB); Print ("Disconnected. Script done!"); }
例 MySQL-004.mq5 はスクリプト "MySQL-003.mq5" によって作成されたテーブルからのデータ選択を示しています。
//+------------------------------------------------------------------+ //| MySQL-004.mq5 | //| Copyright 2014, Eugene Lugovoy | //| https://www.mql5.com | //| Select data from table (DEMO) | //+------------------------------------------------------------------+ #property copyright "Copyright 2014, Eugene Lugovoy." #property link "https://www.mql5.com" #property version "1.00" #property strict #include <MQLMySQL.mqh> string INI; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { string Host, User, Password, Database, Socket; // database credentials int Port,ClientFlag; int DB; // database identifier Print (MySqlVersion()); INI = TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Scripts\\MyConnection.ini"; // reading database credentials from INI file Host = ReadIni(INI, "MYSQL", "Host"); User = ReadIni(INI, "MYSQL", "User"); Password = ReadIni(INI, "MYSQL", "Password"); Database = ReadIni(INI, "MYSQL", "Database"); Port = (int)StringToInteger(ReadIni(INI, "MYSQL", "Port")); Socket = ReadIni(INI, "MYSQL", "Socket"); ClientFlag = (int)StringToInteger(ReadIni(INI, "MYSQL", "ClientFlag")); Print ("Host: ",Host, ", User: ", User, ", Database: ",Database); // open database connection Print ("Connecting..."); DB = MySqlConnect(Host, User, Password, Database, Port, Socket, ClientFlag); if (DB == -1) { Print ("Connection failed!Error: "+MySqlErrorDescription); return; } else { Print ("Connected!DBID#",DB);} // executing SELECT statement string Query; int i,Cursor,Rows; int vId; string vCode; datetime vStartTime; Query = "SELECT id, code, start_date FROM `test_table`"; Print ("SQL> ", Query); Cursor = MySqlCursorOpen(DB, Query); if (Cursor >= 0) { Rows = MySqlCursorRows(Cursor); Print (Rows, " row(s) selected."); for (i=0; i<Rows; i++) if (MySqlCursorFetchRow(Cursor)) { vId = MySqlGetFieldAsInt(Cursor, 0); // id vCode = MySqlGetFieldAsString(Cursor, 1); // code vStartTime = MySqlGetFieldAsDatetime(Cursor, 2); // start_time Print ("ROW[",i,"]: id = ", vId, ", code = ", vCode, ", start_time = ", TimeToString(vStartTime, TIME_DATE|TIME_SECONDS)); } MySqlCursorClose(Cursor); // NEVER FORGET TO CLOSE CURSOR !!! } else { Print ("Cursor opening failed. Error: ", MySqlErrorDescription); } MySqlDisconnect(DB); Print ("Disconnected. Script done!"); }
上記の例には実際のプロジェクトで使用される展開的なエラー処理が入っています。
実際、MQL プログラムで使用されるクエリはすべて任意の MySQL クライアントでデバッグされます(PHPMyAdmin、DB Ninja、 MySQL コンソール)。私は個人的にデータベース開発用の専門的ソフトウェアである MySQL向けQuest TOAD を使用しており、それをお薦めします。
おわりに
本稿はMicrosoft Visual Studio 2010 (C/C++) 環境で開発された MQLMySQL.DLL の実装詳細は説明していません。このソフトウェアソリューションは実用のために設計されており、 MQL ソフトウェア開発の多様な領域において問題なく実装された例が100例以上あります(複雑なトレーディングシステム作成からウェブ発表まで)。.
- MQL4 および MQL5 向けライブラリのバージョンは以下に添付があります添付にはMQLMySQL.DLLのソースコードを持つ zip ファイルもインクルードされています。
- ドキュメンテーションはアーカイブに入っています。
- 例を使用するには、\Scripts\MyConnection.iniファイルでお手持ちのデータベースに接続するパラメータの指定を忘れないでください。