English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MQL5 (MQL4)から MySQL データベースにアクセスする方法

MQL5 (MQL4)から MySQL データベースにアクセスする方法

MetaTrader 5統合 | 23 12月 2015, 15:37
5 683 4
Eugeniy Lugovoy
Eugeniy Lugovoy

はじめに

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 プログラムをとおして)は以下のコンポーネントの助けを借りて実装することができます。

MQL と MySQL の連携スキーム

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 関数によって)。

コマンドが正常に実行される場合、この関数は真を、それ以外は偽を返します。エラー詳細については、 MySQLErrorNumberMySqlErrorDescriptionを使用します。

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 ステートメントはデータベースからデータを取得するてめに使用されます。以下のアクションのシーケンスはデータ選択と選択結果取得に使用されます。

  1. SELECT ステートメントの準備
  2. カーソルのオープン
  3. クエリが返す行番号取得
  4. クエリの行をすべてループし取得
  5. ループ内で MQL 変数に対するデータフェッチ
  6. カーソルのクローズ

もちろんこれは一般的スキームですから、すべての処理がすべての場合に必要なわけではありません。たとえば、テーブルにある行が存在する(任意の基準によって)ことを確認したいなら、クエリを準備、カーソルオープン、行番号取得、カーソルクローズ、で十分です。実際、必須部分は 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ファイルでお手持ちのデータベースに接続するパラメータの指定を忘れないでください。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/932

添付されたファイル |
MQLMySQL_for_MQL4.zip (1124.85 KB)
MQLMySQL_for_MQL5.zip (1125.19 KB)
最後のコメント | ディスカッションに移動 (4)
Freemans Core
Freemans Core | 8 1月 2017 において 16:11
Hello I have a question (Please forgive me because I am Japanese because it is a bad sentence for English translation) Selecting multi-byte characters in Mysql garbles characters. Does this program support multibyte characters?
Eugeniy Lugovoy
Eugeniy Lugovoy | 19 4月 2017 において 20:19
Freemans Core:
Hello I have a question (Please forgive me because I am Japanese because it is a bad sentence for English translation) Selecting multi-byte characters in Mysql garbles characters. Does this program support multibyte characters?


Not yet, I'm working on next release with support of multi-byte charachters

現時点では - いいえ。 私はマルチバイト文字サポートで次のリリースに取り組んでいます

lucker8
lucker8 | 6 4月 2018 において 18:10

Hello, I read this document interestingly.

Could I ask you a question?

I wanna know how to confirm the connection with MySQL.

Please teach me how the way to confirm the connection.


about original japanese: そして月曜日、マーケットが開始されるとプロジェクトにエラーが見つかります。よってサーバーの設定で指定したタイムアウトよりも小さい時間間隔でデータベースへの接続および/または再接続を確認することを強くお薦めします。

that means: After then, You will find out an error in your project on Monday. So, I recommend you to confirm that the connection is alive or dead at a time interval shorter than the timeout server settings.


Thank you.

lucker8
lucker8 | 8 4月 2018 において 05:36

Hello, 

I wrote the code for the time being like below.

1. Create a table that has a time record when confirm the connection.

2. UpSert (Insert or Update) that record  at hourly intervals.

3. If the UpSert will be failed, try resync with MySQL.

Please tell me if some methods exists to confirm the connection.

Thank you.

//+------------------------------------------------------------------+
//| MySQLの接続確認と再接続                                           |
//+------------------------------------------------------------------+
bool DBAccess::resync(void)
{
    string  qry = "";

    string  update_time = (string)TimeCurrent();

    qry += "INSERT INTO `" + sync_table + "` (id, update_time) ";
    qry += "VALUES (\'sync\', \'" + update_time + "\') ";
    qry += "ON DUPLICATE KEY UPDATE update_time = \'" + update_time + "\';";
    
    if (MySqlExecute(DBID, qry))    { return true; }
    
    echo("[Try] Database has been disconnected. EA will try resynchronization.");

    bool    sync        = syncDB();
    
    if(!sync)   { return false; }

    return true;
}
MQL5 ウィザード:計算された価格での発注、ストップロスおよびテイクプロフィット設定標準ライブラリ拡張 MQL5 ウィザード:計算された価格での発注、ストップロスおよびテイクプロフィット設定標準ライブラリ拡張
本稿は MQL5 標準ライブラリの拡張について説明します。それは MQL5 ウィザードを用いてインクルードされたモジュールから受信する価格によって Expert Advisors を作成し、発注し、ストップロスおよびテイクプロフィットを設定することを可能にするものです。この方法はモジュール数に追加の制限は何も設けず、その連携動作において競合が発生することはありません。
売買ロボット物語:余計なものがない方がいい? 売買ロボット物語:余計なものがない方がいい?
2年前『最後の聖戦』でひじょうに興味深い、しかし現在広く使用されていないマーケット情報表示方法-ポイント&フィギュアチャート を再検討しました。ここで私はみなさんにポイント&フィギュアチャートで検出されるパターンに基づく売買ロボットを書いてみることを提案します。
仮想ホスティングに移植するためにトレードアカウントを準備する方法 仮想ホスティングに移植するためにトレードアカウントを準備する方法
MetaTrader クライアントターミナルはトレーディング戦略を自動化するためには完璧なものです。売買ロボット開発者にとって必要なツールをすべて備えています。-力強い C++ 言語ベースのMQL4/MQL5 プログラム言語、便利な開発環境、MQL5 クラウドネットワークで分散コンピューティングをサポートするマルチスレッドのストラテジーテスタ。本稿では、お手持ちのクライアントターミナルをカスタムエレメントをすべて備えた仮想環境に移動する方法をみつけることでしょう。
3つのラインブレイクチャートを作成するためのインディケータ 3つのラインブレイクチャートを作成するためのインディケータ
本稿は Steve Nison 氏が著書 "Beyond Candlesticks" で提案している「3つのラインブレークチャート」について取り上げます。このチャートの最大のメリットはそれにより前の変動に関して価格のマイナー変動にフィルターを描けることができることです。チャート作成の原則、インディケータのコード、それに基づくトレーディング戦略例についてお話していこうと思います。