3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MQL5でデータベースを扱う、MT5とSQLiteの連携の基本操作

Last updated at Posted at 2021-11-23

 MQL5ではSQLiteを使用したデータベースを操作するための関数が用意されてます。この記事ではMQL5での基本的なデータベース操作方法をまとめています。

 実際にMQL5プログラム上からデータベースの操作を操作するには「MT5で用意されている専用関数」と「SQLiteのコマンド」の両方知っておく必要があります。

SQLiteの基礎知識

image.png
 これは実際にMQL5プログラム上から作成したSQLiteの中身です。今回はローソク足の4本値をMQL5で取得してデータベースに追加しています。

1.テーブル
 Excelでいうブックのようなもの。データベースを作成してそこにデータを保管していきます。
2.カラム
 保管するデータを整理するための分類、属性を指します。または列を表すときにもカラムと呼ぶことがあります。通常はカラムごとにデータの型を指定することが多いです。
3.レコード
 実際に保管されているデータをレコードといいます。レコードは基本的にカラムの数だけ存在します。(空白NULLである場合もあります。)または行を表す「ロウ」と同じ意味で使われる場合もあります。
4.フィールド
 Excelでいうセルのようなもの。レコードを構成する要素のことです。

SQLiteとMQL5のデータ型の比較

SQLite MQL5 説明
NULL NULL値
INTEGER int,longなど 符号付整数。1, 2, 3, 4, 6, 8(いずれか) バイト
REAL double 浮動小数点数。8バイト
TEXT string 文字列
BLOB ビデオや音声、圧縮ファイル、実行ファイルなど

データベースにデータを保管

 データベースにデータを保管するには大まかに

  1. 保管するSQLiteファイルを指定、または新規作成
  2. テーブルがなければ新規作成
  3. データを追加する
     という手順が必要です。

保管するSQLiteファイルを指定、または新規作成

 操作したいSQLiteファイルを指定するにはDatabaseOpen()関数を使用します。

操作したいSQLiteファイルを開く.mq5
// 指定したファイル名のDBを開く、なければ新規作成
[データベースハンドル]=DatabaseOpen([SQLiteファイル名], DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);

// 指定したファイル名のDBを読み取り専用で開く
[データベースハンドル]=DatabaseOpen([SQLiteファイル名], DATABASE_OPEN_READONLY |DATABASE_OPEN_COMMON);

テーブルを新規作成

 テーブルを新規作成する専用の関数は用意されていません。その代わりにSQLiteコマンドを実行するDatabaseExecute()関数を使います。

指定したファイル名のDBでSQLiteコマンドを実行.mq5
DatabaseExecute([データベースハンドル],"[SQLiteコマンド]");

DatabaseExecute()関数内に[SQLiteコマンド]のところにテーブル作成するためのSQLiteコマンドをstring型で入れます。

テーブル作成するためのSQLiteコマンド.sqlite
// テーブル作成
CREATE TABLE テーブル名(カラム名1, カラム名2, ...);

// カラムにデータ型を指定してテーブルを作成
CREATE TABLE テーブル名(カラム名1 データ型, カラム名2 データ型, ...)

データを追加する

 データを追加する場合も専用の関数は用意されていませんのでDatabaseExecute()関数を使います。

指定したファイル名のDBでSQLiteコマンドを実行.mq5
DatabaseExecute([データベースハンドル],"[SQLiteコマンド]");
データを追加するためのSQLiteコマンド.sqlite
// 全てのカラムに値を指定してデータを追加する
INSERT INTO テーブル名 VALUES(値1, 値2, ...);

// 特定のカラムだけに値を指定してデータを追加する
INSERT INTO テーブル名(カラム1, カラム2, ...) VALUES(値1, 値2, ...);

 データの追加はレコード単位で行います。テーブルのカラムの数と追加するデータの数を一致させないとエラーになるため、空欄にしたいときはNULLをいれるか、カラムを指定してデータを追加する必要があります。

 DatabaseExecute()関数内の[SQLiteコマンド]はMQL5上ではすべてstring型で扱います。SQLite側ではINTEGER型など文字列でなくとも、MQL5から渡す[SQLiteコマンド]はstring型になるので注意が必要です。

実際にデータベースにデータを保管してみる

.cpp
void OnStart()
  {
   // SQLiteファイル名
   string FileName="Test.sqlite", TableName="TestTable";
   
   // 指定したファイル名のDBを開く、なければ新規作成
   int DBHandle=DatabaseOpen(FileName, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);
   if(DBHandle==INVALID_HANDLE)
     {
      Print("DB: ", FileName, "新規作成 エラーコード: ", GetLastError());
      return;
     }
   
   // DB内のテーブルの存在を確認
   if(DatabaseTableExists(DBHandle, TableName))
     {
      // テーブルが既に存在する場合は、それを削除
      if(!DatabaseExecute(DBHandle, "DROP TABLE "+TableName))
        {
         Print("テーブルの削除に失敗しました。"+TableName+" エラーコード: ", GetLastError());
         DatabaseClose(DBHandle);
         return;
        }
     }
   
   // テーブルの新規作成
   if(!DatabaseExecute(DBHandle, "CREATE TABLE "+TableName+"("
                       "Open              REAL NOT NULL,"
                       "High              REAL NOT NULL,"
                       "Low               REAL NOT NULL,"
                       "Close             REAL NOT NULL );"))
     {
      Print("DB: ", FileName, "テーブル新規作成 エラーコード: ", GetLastError());
      DatabaseClose(DBHandle);
      return;
     }
   
   // DBに4本値のデータを10個追加する
   for(int i=0;i<10;i++)
     {
      if(!DatabaseExecute(DBHandle, "INSERT INTO "+TableName+" (Open,High,Low,Close) "
                              "VALUES ("
                              +DoubleToString( iOpen(_Symbol,PERIOD_CURRENT,i),_Digits)+","
                              +DoubleToString( iHigh(_Symbol,PERIOD_CURRENT,i),_Digits)+","
                              +DoubleToString( iLow(_Symbol,PERIOD_CURRENT,i),_Digits)+","
                              +DoubleToString( iClose(_Symbol,PERIOD_CURRENT,i),_Digits)
                              +");"))
        {
         Print("DB: ", FileName, "データの追加 エラーコード: ", GetLastError());
         DatabaseClose(DBHandle);
         return;
        }   
     }
   // DBを閉じる
   DatabaseClose(DBHandle);
  }
  1. 指定したファイル名のDBを開く、なければ新規作成
  2. DB内のテーブルの存在を確認し、あれば削除
  3. テーブルの新規作成
  4. テーブルにデータを追加する
  5. DBを閉じる

 という動作をするスクリプトです。プログラムの最後はDBを閉じるためのDatabaseClose()関数が必要なので記述漏れがないように注意します。

 MT5を開いて、実際にチャート上で動作されてみてください。ログにエラーメッセージが出なければ正常に動作していると思います。

確認方法

 再度MetaEditorを開いてください。DB作成が成功していると \MetaQuotes\Terminal\Common\Files
に作成したDBファイル(今回の例ではTest.sqlite)があります。

  1. 「ファイル」→「開く」
  2. \MetaQuotes\Terminal\Common\Files 内のTest.sqliteを開く
  3. 「ナビゲーター」→「データベース」を選ぶ

image.png
 先ほど作成したTest.sqliteの中にTestTable(テーブル名)があるのでTestTableをダブルクリック

image.png
 このような画面が開いたら左上の実行を押す

image.png
 データベースに保管した4本値のデータが出てくれば成功です。

データベースからデータを取得

 データベースからデータを取得するには大まかに

  1. 取得するSQLiteファイルを指定
  2. 取得したいデータをリクエスト
  3. ほしいデータを選んで取得
     という手順が必要です。

取得するSQLiteファイルを指定

 操作したいSQLiteファイルを指定するにはDatabaseOpen()関数を使用します。データベースにデータを保管するときと同じですが、データを取得するだけが目的なら読み取り専用でもOKです。

操作したいSQLiteファイルを開く.mq5
// 指定したファイル名のDBを開く、なければ新規作成
[データベースハンドル]=DatabaseOpen([SQLiteファイル名], DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);

// 指定したファイル名のDBを読み取り専用で開く
[データベースハンドル]=DatabaseOpen([SQLiteファイル名], DATABASE_OPEN_READONLY |DATABASE_OPEN_COMMON);

取得したいデータをリクエスト

 データを取得するためにデータ取得用SQLiteコマンドを明記してリクエストハンドルを作成する必要があります。

取得したいデータをリクエスト.mq5
[リクエストハンドル]=DatabasePrepare([データベースハンドル],"[データ取得用SQLiteコマンド]");
データ取得するためのSQLiteコマンド.sqlite
// 全てのカラムの値を取得する
SELECT * FROM テーブル名;

// 特定のカラムだけ値を取得する
SELECT カラム名1, カラム名2, ... FROM テーブル名;

// 特定の条件を満たしたレコードだけ値を取得する
SELECT カラム名 , ... FROM テーブル名 WHERE 条件式;

ほしいデータを選んで取得

 リクエストが終わった段階では複数のカラム、レコードが選ばれている状態です。DatabaseRead()関数を使い、レコードをひとつずつ選択して、選択中のレコードの中から必要な箇所のデータを取得します。

レコードを選択.mq5
// リクエストしたデータからレコードをひとつずつ選択
DatabaseRead([リクエストハンドル]);

DatabaseRead()関数は最後のレコードを選択し終えたらfalseを戻り値で返します。

 DatabaseRead()関数によってレコードが選ばれている状態でどのフィールドのデータを取得するかを記述します。

データを取得(一部抜粋).mq5
// int型を取得
DatabaseColumnInteger([リクエストハンドル],[フィールド番号],[受け取る変数]);

// long型を取得
DatabaseColumnLong([リクエストハンドル],[フィールド番号],[受け取る変数]);

// double型を取得
DatabaseColumnDouble([リクエストハンドル],[フィールド番号],[受け取る変数]);

// string型を取得
DatabaseColumnText([リクエストハンドル],[フィールド番号],[受け取る変数]);

 これらデータを取得する関数は戻り値がbool型で引数に受け取る変数を指定しての参照渡しで受け取ることになります。

実際にデータベースからデータを取得してみる

.cpp
# property strict
# property script_show_confirm //実行前に確認ウィンドウ表示

void OnStart()
  {
   // SQLiteファイル名
   string FileName="Test.sqlite", TableName="TestTable";
   
   // 指定したファイル名のDBを開く、なければ新規作成
   int DBHandle=DatabaseOpen(FileName, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE |DATABASE_OPEN_COMMON);
   if(DBHandle==INVALID_HANDLE)
     {
      Print("DB: ", FileName, "新規作成 エラーコード: ", GetLastError());
      return;
     }
   
   // DB内のテーブルの存在を確認
   if(!DatabaseTableExists(DBHandle, TableName))
     {
      Print("DB: ", FileName, "テーブルがない テーブル名:", TableName);
      return;
        }

     
   // リクエストハンドルを作成
   int request=DatabasePrepare(DBHandle, "SELECT * FROM "+TableName);
   if(request==INVALID_HANDLE)
     {
      Print("DB: ", FileName, "リクエスト エラーコード: ", GetLastError());
      DatabaseClose(DBHandle);
      return;
     }
        
   // DB内のデータを取得してPrint()で出力
   double Open,High,Low,Close;
   
   for(int i=0; DatabaseRead(request); i++) // リクエストのレコードの数だけ繰り返す
     {
      if(   DatabaseColumnDouble(request,0,Open)
         && DatabaseColumnDouble(request,1,High)
         && DatabaseColumnDouble(request,2,Low)
         && DatabaseColumnDouble(request,3,Close))
        {
         Print(i," Open:",Open," High:",High," Low:",Low," Close:",Close);
        }
      else
        {
         Print(i, " データを取得  エラーコード: ", GetLastError());
         DatabaseFinalize(request);
         DatabaseClose(DBHandle);
         return;
        }
     }
   // 作成されたリクエストを削除
   DatabaseFinalize(request);
     
   // DBを閉じる
   DatabaseClose(DBHandle);
  }
  1. 指定したファイル名のDBを読み取り専用で開く
  2. DB内のテーブルの存在を確認
  3. リクエストハンドルを作成
  4. DB内のデータを取得してPrint()で出力
  5. リクエストを削除してDBを閉じる

 という動作をするスクリプトです。プログラムの最後はリクエストを削除するためのDatabaseFinalize()関数と、DBを閉じるためのDatabaseClose()関数が必要なので記述漏れがないように注意します。

 MT5を開いて、実際にチャート上で動作されてみてください。
image.png
先ほど作ったDBから値を取得してログにメッセージとして出力できていれば成功です。

 
最後にMQL5データベースの操作関数のページのリンクを載せておきます。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?