English Русский 中文 Español Deutsch Português
preview
市場シミュレーション:MQL5でのSQL入門(I)

市場シミュレーション:MQL5でのSQL入門(I)

MetaTrader 5 — テスター |
13 0
Daniel Jose
Daniel Jose

はじめに

皆さん、こんにちは。リプレイ/シミュレーションシステムの構築に関する連載記事の続編へようこそ。

前回の「市場シミュレーション(第24回):SQL入門(VII)」では、SQLの経験がない方でもこれから取り組む内容を理解できるように、私が最も基本的な土台と考える部分を完成させました。 これは、リプレイ/シミュレーションシステムの開発が新たな段階に入るためです。この記事だけでなく、今後の記事を理解するうえでも、SQLの知識が非常に重要になります。

SQLを学び始めたばかりで、これまでの記事で身につけた知識しかないという方も、心配する必要はありません。 これまでの内容を正しく理解し、活用できれば、実際に解決しなければならない多くの課題に対応できるはずです。 まずはSQLiteを使って進めていきたいと考えています。SQLiteはMetaTrader 5に標準で組み込まれているため、DLLやソケットを利用することなく、簡単に扱うことができるからです。

したがって、すでにMQL5のプログラムでSQLiteを利用している方にとっては、この記事に目新しい内容はないでしょう。 しかし、データベースを本格的に扱う必要のあるこの分野に足を踏み入れたばかりで、MQL5を使った実装方法がまだわからないという方は、ぜひ腰を据えて、この記事をじっくりと読んでみてください。 ここでは、MQL5を使ってSQLデータベースの操作を始める方法を解説します。 ただし、今回扱うのは任意のデータベースではなく、SQLiteです。 これまでの記事でも見てきたように、SQLiteを使えば、さまざまな処理を実現できます。 しかも、そのために必要な手間は、MQL5側ではごくわずかです。


MQL5を使用したSQLデータベースの作成

まず最初におこなうのは、 データベースの作成です。 これまでの記事でも見てきたように、これは非常に簡単で、難しい作業ではありません。 MetaEditor上で直接作業することも、コマンドラインから操作することも、SQLスクリプトを編集するための専用ツールを使用することもできます。 ただし、必ずしもこのような方法で作成する必要はないことを理解しておいてください。 目的に応じて、さまざまなプログラミング言語を使い、プログラムから直接データベースを作成することもできます。

調べてみれば、さまざまな言語を使って、同じ処理を異なる方法で説明している記事や解説が数多く見つかるでしょう。 しかし、よく見てみると、基本的にはすべてSQLに行き着くことがわかります。 そして、ここからが最も興味深いところです。 こうした原則を理解していれば、たとえばJavaで書かれた処理を、MQL5で実装できるように応用することも可能になります。 なぜなら、実際にデータを処理し、レコードを操作するのは、最終的にはSQLだからです。 Javaは、特定のユーザー層にとって使いやすいインターフェースを提供する役割を担っているにすぎません。

VBAでも同じ考え方が使われています。たとえば、SQLを使って直接取得したデータを、Excel上に表示するという方法です。 だからこそ、SQL文が実際にどのように動作するのかを理解することが非常に重要なのです。 結局のところ、私たちが使用するのはSQLです。 SQLを利用するための基盤となるプログラミング言語は、SQLによって取得されたデータを表示する役割を担うにすぎません。

仕組みの本質を理解しておけば、後々、大いに役立つはずです。 それでは、最も基本的なところから始めましょう。MQL5を使ってSQLiteのデータベースファイルを作成します。 できるだけわかりやすく説明するために、今回は最も簡単な方法を採用します。 具体的には、MQL5のスクリプトを使用します。 スクリプトであれば、コードの内容を理解しやすく、動作のテストも簡単におこなえるからです。 最初に使用するコードを以下に示します。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Basic script for SQL database written in MQL5"
04. #property version   "1.00"
05. #property script_show_inputs
06. //+------------------------------------------------------------------+
07. input string user01 = "DataBase01";        //FileName
08. //+------------------------------------------------------------------+
09. void OnStart()
10. {
11.     string szFileName = user01 + ".sqlite";
12.     int handleDB;
13.     
14.     if ((handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE)
15.     {
16.         Print("Unable to create or open the file ", szFileName);
17.         return;
18.     }
19.     DatabaseClose(handleDB);
20.     Print("Database file saved successfully..");
21. }
22. //+------------------------------------------------------------------+

MQL5のコード

このコードは、データベースファイルを開く、または新規作成するための最もシンプルな例です。 これらの処理はすべて、MQL5とSQLiteを使用しておこないます。 コードの内容が非常にわかりやすいことがお分かりいただけるでしょう。 7行目では、スクリプトの実行時に、作成または開くデータベースの名前をユーザーが指定できるようにしています。 この時点では、ファイルの拡張子を指定していないことに注意してください。拡張子は後で指定します。 使用する拡張子は11行目で指定しています。 ここでは、ユーザーが入力した名前に、別の文字列(この場合はファイルの拡張子)を連結しています。

拡張子は自由に選べますが、ファイルの種類がわかるものを使用することをお勧めします。 SQLデータベースでは「.db」がよく使われ、SQLiteでは「.sqlite」も一般的です。SQLite固有の機能を利用できるためです。 この点については、これまでの記事ですでに説明しています。 疑問があれば、これまでの記事や、そこで紹介した参考資料を確認して、理解を深めてください。

さて、ファイルを扱うにはハンドルが必要です。 これを12行目で用意しています。 14行目では、MQL5に組み込まれているDatabaseOpen関数を使用して、データベースファイルを開きます。ファイルが存在しない場合は、新規作成することもできます。 ここで、重要な点を一つ押さえておきましょう。 データベースファイルの保存先には、3つのパターンがあります。 いずれも、同じDatabaseOpen関数を使って指定できます。 1つ目はRAM上です。この場合、データベースを閉じると、そのデータベースは消滅します。 これは特定の状況では非常に便利ですが、今回の例では、少なくとも現時点では使用しません。 2つ目と3つ目の保存先は、

DatabaseOpen関数に渡す引数によって決まります。 ここで、掲載したコードでは、DATABASE_OPEN_CREATEとDATABASE_OPEN_READWRITEという引数を使用していることに注目してください。 この指定により、データベースファイルはMQL5\Filesフォルダ内に作成されます。 「フォルダ内のどこか」と説明したのは、ユーザーが入力する名前に、有効なサブディレクトリのパスが含まれている可能性があるためです。 その場合、ファイルは指定されたサブディレクトリ内に作成されます。 いずれにしても、これらの引数を使用する限り、保存先はMQL5\Filesフォルダの配下になります。

ただし、先ほどの引数に加えてDATABASE_OPEN_COMMONを指定すると、保存先が変わります。 MQL5\Filesではなく、COMMON\Filesフォルダが使用されます。 「COMMONフォルダはどこにあるのか。どうすればアクセスできるのか」と疑問に思う方も多いでしょう。 場所がわからない場合は、ローカルディスク上で次のパスを開いてください。

C:\Users\<UserName>\AppData\Roaming\MetaQuotes\Terminal

この場所にCommonフォルダがあり、その中にFilesフォルダがあります。 <UserName>は、Windowsにログインしているユーザー名に置き換えてください。

指定されたファイルの作成やアクセスに失敗した場合は、16行目に記述されたメッセージがMetaTrader 5のターミナルに表示されます。 その直後、17行目でスクリプトが終了します。 一方、すべてが正常に処理された場合は、19行目でデータベースファイルを閉じ、20行目で処理が正常に完了したことを示すメッセージをMetaTrader 5のターミナルに表示します。 その後、MetaEditorでデータベースファイルを開くと、次の画像のような画面が表示されます。

ここまでで、MetaEditor上でSQLを扱う準備ができました。 ただし、今回実際にSQLを操作するのはMQL5からです。 もちろん、MQL5による処理の動作を確認するために、MetaEditorや、これまでSQLを解説した記事で紹介した各種ツールを使用してもかまいません。 MQL5でSQLiteの使い方を学び始めた段階では、処理がどのように進んでいるのかを確認できることが重要です。 そのためには、SQLの基礎知識が非常に役立ちます。 学習をさらに効率よく進めるためにも、以前の記事で紹介した参考資料を活用してください。 これから取り組む内容は、なかなか興味深いものです。

さて、 SQLデータベースファイルを開いたり、新規作成したりする方法がわかったところで、次の段階に進みましょう。 ただし、その前に、誤解を招きやすい点を一つ説明しておきます。 ここでSQLを使ってファイルを開き、データにアクセスし、レコードを追加・変更すると述べているのは、SQLiteを使用することを前提としています。 同じ操作であっても、MySQLやSQL Serverなど、別のSQL実装を使用する場合には、具体的な実行方法が多少異なることがあります。 この点を混同しないようにしてください。

SQLという言語は一つですが、 その実装にはさまざまな種類があり、それぞれで利用できる機能や処理方法が異なります。 今回は、少なくとも実装の初期段階では、SQLiteだけを使用します。 将来、別の実装に切り替える可能性もあります。その場合には、SQLiteから別のSQL実装へ移行する方法についても説明します。 ただし、SQLを学ぶことを恐れる必要はありません。SQLという言語は、それを使用するアプリケーションや実装が変わっても基本的に同じです。


最初のテーブルを作成する

SQLコマンドについて解説したときと同様に、今回もそれに近い方法で進めていきます。 これは、SQLだけでプログラミングする方法から、他のコードにSQLを組み込んで使用する方法へ、スムーズに移行できるようにするためです。今回は、MQL5のコードからSQLコマンドを実行します。 この場合、これらのコマンドを受け取るのはMQL5のコードです。 幸いなことに、MQL5の開発者たちは優れた仕組みを用意してくれており、データベースの操作は非常に理解しやすく、簡単におこなえるようになっています。 そのため、MQL5で利用できるデータベース操作用の関数のうち、まず使い方を覚える必要があるのは6つだけです。 「では、ほかの関数は必要ないのでしょうか?」いいえ、そういう意味ではありません。 私が言いたいのは、まず6つの関数の使い方を覚えればよい、ということです。 これら6つの関数の使い方を理解し、SQLについてもある程度の知識があれば、関連するさまざまな処理に問題なく対応できるようになります。 少なくとも、MQL5に組み込まれているSQLiteを扱う場合には、そう言えます。

DLLを介してSQLiteを利用する場合は、DLLに含まれるSQLiteを直接呼び出すことになるため、ここで説明する方法とは多少異なります。 その場合はDLLファイルに含まれるSQLiteを使用して直接呼び出すすることになるためです。 したがって、DLLを介してSQLiteを利用するのであれば、その方法について解説したドキュメントを読むことをお勧めします。今回取り上げる方法とは、いくつか異なる点があるからです。

それでは、使い方を覚える必要がある関数を確認しましょう。 すでに紹介したDatabaseOpenとDatabaseCloseに加えて、 DatabaseExecute、DatabasePrepare、DatabaseReadBind、DatabaseFinalizeも必要になります。 もちろん、ほかの関数についても使い方を理解しておけば、さまざまな場面で大いに役立ちます。 しかし、SQLプログラミングの基礎知識が十分に身についていれば、これら6つの関数を使うだけで、ほとんどあらゆる処理を簡単に構築できるようになります。

これまでの記事で学んだことを活用すれば、すでにかなり興味深い処理を実現できるはずです。 さらに、他の多くの人には難しいような処理も、皆さんなら実現できるようになるでしょう。 ただし、以前お約束したとおり、誰もが内容を理解しながら読み進められるよう、すべてを段階的に説明していきます。

さて、 これまでの記事を読んで、私たちが行う処理は、何らかの形で常にテーブルと関係していることにお気づきかもしれません。そこで、まずはテーブルの基礎から始めましょう。 今回使用する新しいスクリプトを以下に示します。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Basic script for SQL database written in MQL5"
04. #property version   "1.00"
05. #property script_show_inputs
06. //+------------------------------------------------------------------+
07. input string user01 = "DataBase01";        //FileName
08. //+------------------------------------------------------------------+
09. void OnStart()
10. {
11.     string szFileName = user01 + ".sqlite",
12.              szRequestSQL;
13.     int handleDB;
14.     
15.     if ((handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE)
16.     {
17.         Print("Unable to create or open the file ", szFileName);
18.         return;
19.     }
20.     szRequestSQL = "CREATE TABLE IF NOT EXISTS tb_Symbol(id PRIMARY KEY, symbol NOT NULL UNIQUE);";
21.     if (!DatabaseExecute(handleDB, szRequestSQL))
22.     {
23.         Print("Request execution failed.");
24.         DatabaseClose(handleDB);
25.         return;
26.     }
27.     DatabaseClose(handleDB);
28.     Print("Database file saved successfully.");
29. }
30. //+------------------------------------------------------------------+

MQL5のコード

このスクリプトをMetaTrader 5で実行すると、次のような結果が得られます。

「すごいですね。 でも、これはどのように実現したのでしょうか?」答えは簡単です。 これまでSQLについて解説してきた記事で学んだことだけを使っています。 ただし、今回はそのすべてをMQL5で実装しました。 どのように実現したのでしょうか。 前のセクションで紹介したスクリプトをベースに、コードに数行追加しただけです。 ただし、一つ注意点があります。このコードは、まだ適切な構造にはなっていません。 ここでは、以前紹介した処理をMQL5でどのように実現できるかを示すことが目的です。 まず、12行目を追加します。ここでは、実行したいSQLコマンドを格納するための文字列変数を宣言しています。 そして20行目で、その変数に実行するSQLコマンドを指定します。 今回の場合は、データベース内にtb_Symbolという名前のテーブルが存在しない場合に、新しく作成するようSQLに指示しています。

その直後に、DatabaseExecute関数を使って、SQLiteにSQLコマンドの実行を指示します。 この処理に失敗した場合は、23行目に記述されたメッセージがMetaTrader 5のターミナルに表示されます。 すでにデータベースを開いているので、最後に閉じる必要があります。これを24行目で行っています。 そして25行目で、MetaTrader 5のスクリプトの実行を終了します。

ここで、一つ注意しておきたい点があります。 MetaTrader 5に組み込まれているSQLiteを使用する場合、SQLiteに実行させたいコマンドは、すべてDatabaseExecute関数を通じて送信します。 ただし、この関数が適しているのは、SQLコマンドを実行する場合に限られます。 クエリを実行する場合には、ほかの関数も使用する必要があります。 このように、それぞれの機能がうまく連携することで、必要な処理を構築できるわけです。

さて、クエリの操作に進む前に、このMQL5スクリプトをもう少し汎用的なものにし、これから構築するデータベースでより使いやすい形にしておきましょう。 コードの構造は変更できるので、同じスクリプトをクラスとして作り直すことができます。 この段階では単純な変更に思えるかもしれませんが、これは非常に重要です。コードの再利用性を高めることができ、その結果、より安全で安定したコードを実現できるからです。 それでは、先ほどのコードを、クラスを使用した次のコードに書き換えてみましょう。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Basic script for SQL database written in MQL5"
04. #property version   "1.00"
05. #property script_show_inputs
06. //+------------------------------------------------------------------+
07. input string user01 = "DataBase01";         //FileName
08. //+------------------------------------------------------------------+
09. class C_DB_SQLite
10. {
11.     private :
12.             int     m_handleDB;
13.     public  :
14. //+------------------------------------------------------------------+
15.             C_DB_SQLite(const string szFileName)
16.                     :m_handleDB(INVALID_HANDLE)
17.                     {
18.                             if ((m_handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE)
19.                             {
20.                                     Print("Unable to create or open the file ", szFileName);
21.                                     return;
22.                             }
23.                     }
24. //+------------------------------------------------------------------+
25.             ~C_DB_SQLite()
26.                     {
27.                             DatabaseClose(m_handleDB);
28.                             Print("Closing Database...");
29.                     }
30. //+------------------------------------------------------------------+
31.             bool Command(const string szRequestSQL)
32.                     {
33.                             bool ret = DatabaseExecute(m_handleDB, szRequestSQL);                           
34.                             Print("Request execution: ", (ret ? "Success" : "Failed"), "...");
35.                             return ret;
36.                     }
37. //+------------------------------------------------------------------+
38. };
39. //+------------------------------------------------------------------+
40. void OnStart()
41. {
42.     C_DB_SQLite *DB;
43.     
44.     DB = new C_DB_SQLite(user01 + ".sqlite");
45.     
46.     (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Symbol(id PRIMARY KEY, symbol NOT NULL UNIQUE);");
47.     
48.     delete DB;      
49. }
50. //+------------------------------------------------------------------+

MQL5のコード

データベースを操作するための構造が、以前よりもかなり複雑になっていることに注目してください。 これは、データベースにコマンドを送信する際、開いているデータベースが1つであっても数十個であっても、 必ず正しいデータベースにコマンドが送られるようにするためです。 今回のコードでは、9~38行目で定義したクラスの内部で関数を使用しているため、この仕組みが実現できています。しかも、これはまだ始まりにすぎません。 それでも、すでにクラスが提供する安全性の恩恵を受けることができます。

たとえば、初期化されていないハンドルを使用することはできません。 初期化はクラスのコンストラクタを通じておこなわれるため、常に有効なハンドルを使用できることが保証されます。 そのことは、33行目でハンドルを使ってSQLコマンドを送信している箇所からも確認できます。

ここで、次の点に注目してください。SQLiteとの通信をカプセル化するためにクラスを使用したり、そもそもクラスを作成したりするのは、やりすぎだと考える人もいるでしょう。しかし、少し視点を変えて考えてみてください。おそらく、その考えも変わるはずです。 たとえば、次のように考えるかもしれません。「MetaTrader 5に組み込まれているSQLiteを使うだけなのに、なぜクラスを作る必要があるのだろう。 MQL5の関数を直接使ったほうが、ずっと簡単ではないか。 特に、プログラムの中でSQLをそれほど頻繁に使うつもりがないのなら、なおさらだ。」この考え方については、私もそのとおりだと思います。しかし、もう少し広い視点から考えてみましょう。 MQL5を使えば、MetaTrader 5に組み込まれたSQLiteに簡単にアクセスできます。 それは確かです。 しかし、そこだけに目を向けるべきではありません。

MetaTrader 5に組み込まれたSQLiteを利用するアプリケーションをいくつも開発したり、あるいは一つのシステム全体を構築したりする場合を考えてみてください。その際、MQL5の関数だけを使用していると、いずれMetaTrader 5に組み込まれたSQLiteしか使えないという制約に直面することになります。 DLLファイルに組み込んだ独自のSQLiteを利用することもできなくなります。 さらに厄介なのは、将来、MySQLやSQL Serverなど、別のSQL実装を使うことにした場合です。必要な依存関係に対応するため、コード全体を書き直すことになり、多くの作業が発生します。 ここで例に挙げたMySQLやSQL Serverは、MQL5から直接アクセスできるファイルシステムを使用していないためです。 もちろん、MQL5を使ってアクセスすること自体は可能ですが、そのためには別の仕組みが必要になります。 この連載ですでに紹介した、ソケットがそれに当たります。

つまり、クライアントサーバーアーキテクチャを採用したデータベースにアクセスするには、ソケットを使用する必要があります。 最初から実装の詳細を隠蔽するクラス構造を採用していれば、クラスを変更し、ソケット通信に必要な機能を追加したり、既存の機能を調整したりするだけで済みます。 これによって、開発プロセス全体が大幅に簡素化されます。 たとえば、MetaTrader 5に組み込まれたSQLiteから、DLLにコンパイルした独自のSQLiteに切り替える必要が生じた場合も、簡単に対応できます。

実装方式を変更する場合も同じです。 ファイルベースのSQLiteからクライアント・サーバー型のSQLデータベースに移行するときも、大きな問題は生じません。 クラスの動作を変更するだけで、その変更は残りのコードにも反映されます。 とてもシンプルです。 ですから、将来、アプリケーションの動作方式が変わる可能性を見越して開発することの利点を、過小評価しないでください。 テクノロジーは時間とともに変化します。 特定の技術に固定され、切り離せなくなるような実装を選ぶのは、最善の方法ではありません。


いくつかの重要なポイント

先に進む前に、ぜひ理解しておいてほしい重要な点があります。 次のことを考えてみましょう。 これまでの記事では、リレーショナルデータベースを構築するために、テーブル間のリレーションシップを作成しました。 また、リレーショナルモデルに基づいてデータベースを構成する方法と、そのメリットとデメリットについても説明しました。 しかし、MetaTrader 5に組み込まれたSQLiteを使って多数のSQLコマンドを実行する場合には、いくつか注意しなければならないことがあります。 より正確に言えば、安全性を高めるための仕組みを考える必要があります。

ここで紹介する内容は、次の記事でいくつかの判断を迫ることになります。 以下のMQL5コードを注意深く確認してください。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Basic script for SQL database written in MQL5"
04. #property version   "1.00"
05. #property script_show_inputs
06. //+------------------------------------------------------------------+
07. input string user01 = "DataBase01";        //FileName
08. //+------------------------------------------------------------------+
09. class C_DB_SQLite
10. {
11.     private    :
12.         int    m_handleDB;
13.     public    :
14. //+------------------------------------------------------------------+
15.         C_DB_SQLite(const string szFileName)
16.             :m_handleDB(INVALID_HANDLE)
17.             {
18.                 if ((m_handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE)
19.                 {
20.                     Print("Unable to create or open the file ", szFileName);
21.                     return;
22.                 }
23.             }
24. //+------------------------------------------------------------------+
25.         ~C_DB_SQLite()
26.             {
27.                 DatabaseClose(m_handleDB);
28.                 Print("Closing Database...");
29.             }
30. //+------------------------------------------------------------------+
31.         bool Command(const string szRequestSQL)
32.             {
33.                 bool ret = DatabaseExecute(m_handleDB, szRequestSQL);                
34.                 Print("Request execution: ", (ret ? "Success" : "Failed"), "...");
35.                 return ret;
36.             }
37. //+------------------------------------------------------------------+
38. };
39. //+------------------------------------------------------------------+
40. void OnStart()
41. {
42.     C_DB_SQLite *DB;
43.     
44.     DB = new C_DB_SQLite(user01 + ".sqlite");
45.     
46.     (*DB).Command("PRAGMA FOREIGN_KEYS = ON;");    
47.     (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Symbols"
48.                   "("
49.                     "id PRIMARY KEY,"
50.                     "symbol NOT NULL UNIQUE"
51.                   ");");
52.     (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Quotes"
53.                   "("
54.                     "of_day NOT NULL,"
55.                     "price NOT NULL,"
56.                     "fk_id NOT NULL,"
57.                     "FOREIGN KEY (fk_id) REFERENCES tb_Symbols(id)"
58.                   ");");    
59.     delete DB;
60. }
61. //+------------------------------------------------------------------+

MQL5のコード

MQL5のコード内で、コマンドがどのように配置されているかに注目してください。 これは、SQLコマンドを実行するうえで重要なことです。 多くのコードを書いていると、何らかのミスをしてしまうことは珍しくありません。 では、次のスクリプトを見てみましょう。

01. PRAGMA FOREIGN_KEYS = ON;
02. 
03. CREATE TABLE IF NOT EXISTS tb_Symbols
04. (
05.     id PRIMARY KEY,
06.     symbol NOT NULL UNIQUE
07. );
08. 
09. CREATE TABLE IF NOT EXISTS tb_Quotes
10. (
11.     of_day NOT NULL,
12.     price NOT NULL,
13.     fk_id NOT NULL,
14.     FOREIGN KEY (fk_id) REFERENCES tb_Symbols(id)
15. );

SQLiteのコード

このスクリプトを先ほどのものと比較してください。 後者では純粋なSQLを使用しており、記述中に構文をチェックできます。しかし、SQL文をMQL5のコード内に文字列として直接埋め込んだ場合、同じようにチェックすることはできません。 これが、MQL5からMetaTrader 5に組み込まれたSQLiteエンジンとやり取りする仕組みです。 つまり、MQL5のコード内で文字列としてSQL文を記述する際にタイプミスをすると、SQLエンジンはそのコードを正しく実行できません。 その結果、MQL5や、さらにはMetaTrader 5自体に問題があると考えてしまうかもしれません。しかし、それは大きな間違いです。 ただし、どちらのバージョンのコードでも、リレーションシップを持つテーブルを備えたデータベースを作成している点は同じです。 ところが、もし誤ってテーブル名tb_Symbolsをtb_Symbolと記述してしまうと、次の図に示すものとはまったく異なる結果になります。

なお、前の図に示したものと同じ構造をMetaEditor上で確認しようとしても、それはできません。 この点については、以前の記事ですでに説明しました。 何が起きているのか分からない場合は、SQLの仕組みや、SQLをより効率的に利用するために必要なプログラムの入手方法について解説した記事を読んでみることをお勧めします。

ここで私が強調したいのは、まさにこの点です。 文字列の中にSQLコードを記述すると、気づきにくいエラーが含まれてしまうことがあります。 しかし、SQLコードを解析できるエディタを使用すれば、次の例のように、こうしたエラーをはるかに簡単に見つけることができます。

独立したSQLスクリプトであれば、エラーを見つけるのはずっと簡単です。 先ほども述べたように、プログラマーがタイプミスをすることは決して珍しくありません。 したがって、適切なツールを使えば、あるコードがなぜ動作するのか、あるいは動作しないのかを調べるために費やす時間を大幅に節約できます。 多くの場合、原因はコマンドを入力する際の単純なタイプミスなのです。


最後に

今回の記事では、MQL5のコード内でSQLを使用する方法について学び始めました。 データベースをどのように作成するか、 より正確に言えば、MQL5に組み込まれた機能を使ってSQLiteのデータベースファイルを作成する方法を見てきました。 また、テーブルの作成方法や、主キーと外部キーを使ってテーブル間にリレーションシップを設定する方法についても、同じくMQL5を使って確認しました。 これらすべてを、今回もまた、MQL5を使って実現しています。 さらに、実装の詳細を隠蔽するクラスを利用すれば、後から別のSQL実装へ移行できるコードを簡単に作成できることも分かりました。

そして何より重要なのは、SQLを使用する際には、さまざまな箇所で問題が発生する可能性があることを確認した点です。 MQL5のコード内では、SQLコードを文字列として記述することになります。 そのため、タイプミスによってSQL文の実行に問題が生じる可能性が高くなります。 しかし、こうした問題を回避するための仕組みを、今後構築していくことができます。それによって、より自由度の高い開発が可能になるだけでなく、SQLスクリプトを読みやすくするために設計されたエディタを活用して、入力ミスを防ぐこともできるようになります。

次回の記事では、こうした移植性を高めるための仕組みを作成します。 ある程度経験のある方なら、すでに何をしようとしているのか見当がついているかもしれません。 まだ分からなくても心配はいりません。次回、具体的な方法を見ていきます。 そして、引き続きSQLの分野で作業を進めますが、今度はMQL5を実行の基盤として使用します。 これは、MetaTrader 5上で、私たちのリプレイ/シミュレーションシステムがデータベースを利用できるようにするために必要なことです。 それでは、引き続き学習を進めてください。すべてがさらに面白くなる次回の記事で、またお会いしましょう。

ファイル 説明
Experts\Expert Advisor.mq5
Chart TradeとEAの連携を示す(操作にはMouse Studyが必要)
Indicators\Chart Trade.mq5 送信する注文を設定するためのウィンドウを作成します(操作にはMouse Studyが必要)。
Indicators\Market Replay.mq5 市場のリプレイ/シミュレーションサービスを操作するためのコントロールを作成します(操作にはMouse Studyが必要)。
Indicators\Mouse Study.mq5 グラフィカルコントロールとユーザー間の対話機能を提供します(リプレイ/シミュレーションシステムと実際の市場の両方で必要)。
Services\Market Replay.mq5 市場のリプレイ/シミュレーションサービスを作成し、管理する、システム全体の中核となるファイルです。
Code VS C++\Servidor.cpp C++で開発されたサーバーソケットを作成し、管理します(ミニチャット版)。
Code in Python\Server.py MetaTrader 5とExcelの間で通信するためのPythonソケットを作成し、管理します。
Indicators\Mini Chat.mq5 インジケータを使ってミニチャットを実装できるようにします(動作にはサーバーが必要)。
Experts\Mini Chat.mq5 EAを使ってミニチャットを実装できるようにします(動作にはサーバーが必要)。
Scripts\SQLite.mq5 MQL5でSQLスクリプトを使用する方法を実演します。
Files\Script 01.sql 外部キーを持つシンプルなテーブルの作成方法を示します。
Files\Script 02.sql テーブルへの値の追加方法を示します。

MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/13062

添付されたファイル |
Anexo.zip (571.71 KB)
市場シミュレーション:MQL5でのSQL入門(V) 市場シミュレーション:MQL5でのSQL入門(V)
前回の記事では、クエリ機能を追加する方法について説明しました。 これにより、MQL5のコード内でSQLを自由に活用し、SQLのSELECTクエリを実行してデータを取得できるようになります。 しかし、実装すべき関数がもう一つ残っています。 それがDatabaseReadBind関数です。 この関数を正しく理解するには、もう少し詳しい説明が必要となるため、前回の記事では取り上げず、今回の記事で解説することにしました。 今回は比較的広範囲な内容となるため、さっそく本題に入りましょう。
MetaTrader 5における取引銘柄の時間帯別値動きと銘柄間スプレッドの分析 MetaTrader 5における取引銘柄の時間帯別値動きと銘柄間スプレッドの分析
移動平均線を組み込んだProSpread季節性指数インジケータは、価格変動における季節性パターンを特定し、特定の取引時間帯における値動きを分析するテクニカル分析ツールです。 単一の取引銘柄だけでなく、2つの資産間のスプレッドにも対応しており、価格が特定の方向に動く統計的な確率も可視化します。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
取引におけるニューラルネットワーク:異質性を考慮したメタパラメータ学習(HimNet) 取引におけるニューラルネットワーク:異質性を考慮したメタパラメータ学習(HimNet)
時空間適応の柔軟性と高い計算効率を兼ね備えたHimNetフレームワークをご紹介します。このフレームワークは、金融時系列データの高精度かつ安定した予測を可能にします。 主要な構成要素がどのように連携し、複雑なアルゴリズムを実用的で扱いやすいアーキテクチャへと落とし込んでいるのかを詳しく解説します。