市場シミュレーション(第6回):MetaTrader 5からExcelへの情報の転送
はじめに
MetaTrader 5ユーザーの多くが直面する課題のひとつは、プラットフォーム自体にいくつかの機能が備わっていないということです。
多くの人、特にプログラマーではない人は、MetaTrader 5と他のプログラムとの間で情報をやり取りすることは非常に難しいと感じます。その代表的な例がExcelです。多くのユーザーは、リスク管理や運用管理の手段としてExcelを利用しています。Excelは優れたプログラムであり、VBAプログラマーでなくても比較的容易に扱うことができます。しかし、MetaTrader 5とExcelの間で情報をやり取りする作業は、プログラミングの知識がない場合、決して簡単ではありません。
それでも、この連携は非常に有用です。Excelを運用リスク管理のツールとして使用しながら、取引自体はMetaTrader 5でおこないたいユーザーにとって、作業を大幅に簡素化できるからです。しかし、十分なプログラミング知識がない場合、正体の分からない外部プログラムに依存せざるを得なくなったり、あるいはMetaTrader 5からExcelへ情報を転送できないことを理由に、プラットフォームの利用を諦めてしまうこともあります。
幸いなことに、Excelにはこの問題を解決するための興味深い方法がいくつか用意されています。これらについては後ほど詳しく説明します。ただし残念ながら、MetaTrader 5には情報を直接Excelへ送信するための組み込み機能はありません。そのため、何らかのプログラミング手法を用いるか、情報転送を実現する外部ツールを利用する必要があります。
問題の理解
まず、MetaTrader 5とExcelの間でデータを転送する際に直面する基本的な課題と、最も一般的な方法について整理してみましょう。代表的な方法の一つに、RTD(リアルタイムデータ)やDDE(ダイナミックデータ交換)の利用があります。しかし、どちらの方法もCOM(コンポーネントオブジェクトモデル)インターフェースのプログラミング知識を必要とします。実際には、多くのプログラマーでさえこのスキルを持っていないことが多いです。仮にこのような仕組みを構築できたとしても、柔軟性の高いソリューションにはなりにくいのが現実です。
RTDやDDEはいずれも一方向の通信方式です。つまり、あるシステムから別のシステムへの橋渡しをおこなうだけであり、Excelを扱う上で特に便利な高度な機能を提供するわけではありません。それでも、Excelがこれらの仕組みを標準でサポートしているため、リアルタイム通信の手段としては一定の価値があります。
ここで少し視点を広げて考えてみましょう。Excelで本当にリアルタイムデータが必要となる場面はどれほどあるでしょうか。ほとんどの場合、多少の遅延は問題になりません。ここで言っているのは、Excelを自動売買ロボットの制御システムとして利用したい場合の話ではありません。MetaTrader 5を使用しているのであれば、計算はプラットフォーム内でおこなうべきです。Excelにポジション計算を任せ、その結果をもとにMetaTrader 5のエキスパートアドバイザー(EA)が判断する、という方法は合理的とは言えません。
しかし、ポジションを2日以上保有する取引や、ロング/ショートペア取引をおこなう場合には、Excelが資金管理やリスク管理の補助として非常に有用になります。このようなケースでは、Excelに自動的に価格情報や関連データを受け取らせることが重要です。たとえば、ロング/ショートペアを扱い、同時に20ポジションを保有しているとしましょう。戦略によっては、毎日あるいは毎時間、40の価格情報を手動で更新しなければなりません。
この作業には時間がかかるだけでなく、入力ミスのリスクも非常に高くなります。40の価格情報を一つずつ手動で転記する作業は、まさに大きな負担です。
こうした理由から、多くのユーザーがこの課題を解決する方法を模索しています。その1つの解決策として、ウェブ上から直接取得した価格情報を利用する方法があります。
Webソリューション
ここで紹介するWebソリューションは、Excel自体に更新処理を自動的におこなわせる方法に基づいています。ただし、この方法には小さな問題があります。
作成は容易ですが、理想的とは言えません。その理由は、取得される価格情報に遅延が発生するためです。この遅延は状況によって大小があり、主に多くの金融情報サービスが有料で提供されていることに起因します。
特に金銭が関わる分野において、「無料で完全なサービス」が存在しないことは言うまでもありません。
ここで、こうしたサービスが有料であることの是非を論じるつもりはありません。重要なのは、すでにMetaTrader 5という取引プラットフォームを利用しているにもかかわらず、なぜこの方法を使う必要があるのか、という点です。
この種のソリューションを利用する場合、まずGoogleアカウントに関連付けられたオンラインスプレッドシートを開き、その中で次のコマンドを入力します。
GoogleFinance
このコマンドをオンラインスプレッドシートのセルに追加することで、対象とする資産に関するさまざまなデータを取得できます。これらのデータは一定間隔で自動更新されますが、通常は更新に遅延が発生します。数日単位で変化するポジションを管理している場合、この遅延は大きな問題になりません。いわゆるバイ・アンド・ホールド戦略であれば、この方法で十分対応できます。しかし、短期取引をおこなう場合には事情が異なります。
本題に戻ると、オンラインスプレッドシートを完全に設定した後、それを保存し、別の用途向けにエクスポートすることが可能です。ただし、ここで言う「エクスポート」は厳密な意味でのエクスポートではありません。実際には、GoogleFinance関数によって取得された値を抽出し、それをローカル環境にある別のスプレッドシートへ転送し、快適に作業できるようにすることが目的です。
この方法は多くのケースで有効ですが、すべての状況に適しているわけではありません。実際には、遅延を最小限に抑えた価格情報(多くの場合、価格そのもののみ)が必要となる場面も多く存在します。しかし、この方法では、どのように工夫しても更新間隔を1分未満にすることはできません。その点は図01からも確認できます。

図01:プロパティウィンドウ
図01は、Excelに取り込まれるコンポーネントの更新頻度を設定するプロパティウィンドウを示しています。このウィンドウを見たことがない、あるいは存在を知らなかったとしても問題ありません。後ほど、表示方法を説明します。ただし、ここで注意すべき点があります。仮に最小更新間隔を1分に設定したとしても、GoogleFinance関数自体がそれほど頻繁に更新されるわけではありません。
したがって、ここでおこなっていることの本質を正しく理解する必要があります。本記事で紹介しているのは、約1分の遅延を伴って資産価格を取得する方法です。価格変動のたびに更新されるリアルタイムのクオートを取得したい場合には、ここで示した方法とは異なるアプローチが必要になります。それでもなお、この方法は多くの状況や幅広い問題に対して十分に有効です。その理由は、必要となるプログラミングが非常にシンプルで理解しやすく、かつMetaTrader 5とExcel間の連携を効率的に実現できるためです。
実装の理解
リアルタイムの価格情報を取得するために、Pythonを利用したより複雑なソリューションや、RTDやDDEを使った簡易的な方法も存在します。しかし、ここで紹介する方法はMQL5だけで開発でき、簡単かつ迅速に実装できるうえ、同時に洗練されて使いやすいという特徴があります。
まず理解しておくべきことは、MetaTrader 5には基本となるアプリケーションタイプが4種類あるという点です。それぞれ用途に応じて適しています。
- EA:よく知られる自動売買ロボットで、注文や取引リクエストをサーバーに送信するためのMetaTrader 5アプリケーションです。主に取引実行を目的として設計されています。
- インジケーター:チャート上に情報を表示したり追加したりするためのプログラムです。価格の監視や、特定の計算結果や情報を視覚化する目的で使用されます。
- スクリプト:特定のタスクを実行するためのプログラムです。通常、チャートに一瞬だけアクセスして処理をおこない、その後はすぐに終了します。ただし、常に特定のチャートに紐付けられています。
- サービス:スクリプトと同様に特定のタスクを実行しますが、チャートに紐付けられることはありません。MetaTrader 5のターミナル上でチャートが開かれていない場合でも常に動作し続けます。
ご覧のとおり、MetaTrader 5の各アプリケーションタイプには明確な用途があります。その中で、サービスのみがチャートに依存せず独立して動作できるため、今回のソリューションには最適な選択肢となります。
注記:サービスとスクリプトは動作に違いがあります(スクリプトはチャートに紐付くため)が、コード自体はほぼ同一です。サービスとスクリプトを区別する唯一の要素は、以下のプロパティです。
#property service
この行がスクリプト内にある場合、そのスクリプトはサービスとして動作します。
したがって、今回のソリューションではサービスとして作成することになります。ただし、前述のようにスクリプトとして利用することも可能です。その場合は、チャートに紐付けられることになります。必要なコード変更は、上記プロパティ行を削除するだけです。実際のコードを確認する際に、ここについても改めて説明します。
実装の開始
この記事の読者の中には、Excelにあまり詳しくない方もいるかもしれません。そのため、ここでは必要な手順の基本をExcel上でどのようにおこなうかを説明します。もしExcelの操作に慣れている場合は、次のセクションに進み、MQL5でサービスを実装し、MetaTrader 5からExcelに直接データを送信する方法を確認してください。
まず最初に、MetaTrader 5で後ほど使用する小さなファイルを作成し、編集する必要があります。ただし、このファイルを任意の場所に保存することはできません。MQL5ではセキュリティ上の理由から、コンピュータ上の任意の場所にアクセスすることが制限されているためです。そのため、正しい手順として、MetaEditorを開き、ナビゲーションペインで以下の手順(アニメーション01参照)をおこないます。

アニメーション01:正しいディレクトリへのアクセス
これをおこなうと、OSのファイルエクスプローラーが開き、MQL5ディレクトリ内のFILESフォルダが表示されます。ここに、作成するファイルを最初に置く必要があります。以下の内容のファイルを作成してください(これはあくまで例です)。
PETR4; VALE3; ITUB3;
このファイルをQUOTE.CSVという名前で保存します。ただし、この時点でファイルエクスプローラーは閉じないでください。次の手順でファイルの場所を指定する際に使用します。
次に、空白のワークシートを開いたExcelで、QUOTE.CSVをこのスプレッドシートにリンクする手順をおこないます。

図02
図02に、必要なオプションの場所が示されています。お使いのExcelのバージョンによっては、このオプションが見当たらない場合があります。その場合は、[データの取得](Get Data)から探してください。ここでは、テキストファイルからデータをインポートするオプションを選択します。Webからのデータインポートと似ていますが、今回はローカルファイルを使用します。

図03
図02でオプションを選択すると、ファイルブラウザが開きます。先ほど確認したMQL5ディレクトリのQUOTE.CSVまで移動し、ファイルを選択します。すると図03のように内容が表示されます。図03の上部に表示されているファイル読み込み設定に注意してください。設定が正しければ、[読み込み]ボタンの横の矢印をクリックし、[読み込み先...](Load To...)を選択します。すると図04の画面が表示されます。

図04
ここで、データをスプレッドシートのどこに配置するかを選択できます。今回はデモンストレーションのため、図のハイライト部分の設定のままにしてください。。[OK]をクリックすると、図05のようにデータが表示されます。

図05
これでデータはスプレッドシートに読み込まれました。しかし、まだ欠けているものがあります。それは、Excelに対してデータをどのように、いつ更新するかを指示することです。RTDやDDEサーバーは使用していないため、Excelに明示的に更新タイミングを伝えないと、データは自動で更新されません。VBAの知識があれば、より高度な仕組みを作ることも可能です。しかしここでは、誰でも簡単に実現できる方法に限定します。QUOTE.CSVのデータをExcelが自動更新するように設定するには、図06の手順を実行します。

図06
スプレッドシート上でテーブルを選択すると、[クエリ](Query)タブがアクティブになります。このタブで[プロパティ](Properties)を選択してください。クリックすると、まず図07のウィンドウが表示されます。

図07
図07をよく見てください。図07のウィンドウでは、Excelが自動的にデータを更新できるように、いくつかの設定を変更します。ただし、更新対象はQUOTE.CSVから作成したテーブルだけであることに注意してください。設定内容は図08のように調整してください。

図08
[OK]をクリックして変更を確定すると、Excelは設定に従って動作します。これにより、おおよそ60秒ごとにスプレッドシートのデータがQUOTE.CSVの内容に応じて更新されます。実際に確認するには、テキストエディタでQUOTE.CSVを開き、以下のような値を追加して保存してください。
PETR4;30.80 VALE3;190.31 ITUB3;25.89
テキストエディタを閉じる必要はありません。しばらく待つと、Excelが自動的に更新され、図09のように表示されます。

図09
値を変更して確認することで、Excelが自動更新される仕組みを理解できます。これにより、複雑な手法や冗長なソリューションを使わなくても、多くの操作が簡単におこなえることが分かります。さらに興味深い点として、ローカルネットワークを介した共有も可能です。この場合、ExcelとMetaTrader 5は異なるPC上でも動作させることができ、必ずしも同じマシンである必要はありません。
MQL5でのサービスの実装
前のセクションでは、使用するファイルとその設置場所について説明しました。ここからは、実際にMetaTrader 5で動作するサービスを作成する手順を示します。ただし心配はいりません。ここでの実装は非常にシンプルで、作成も利用も容易です。記事の最後には、システムの動作を確認できるデモ動画も用意しています。
まず一点、デモ動画で表示されているように、気配値表示に対象の資産を表示する必要はありません。動画では手順を追いやすくするために表示していますが、通常の運用では不要です。サービスを実行するだけで、気配値表示の資産やMetaTrader 5の動作に影響を与えることはありません。
前のセクションで説明したファイルを作成済みであれば、次にサービスのコードを見て、実際にどのように動作するかを理解できます。サービスの完全なコードは以下の通りです。
01. //+------------------------------------------------------------------+ 02. #property service 03. #property copyright "Daniel Jose" 04. #property description "Quote sharing service between" 05. #property description "MetaTrader 5 and Excel" 06. #property version "1.00" 07. //+------------------------------------------------------------------+ 08. input string user01 = "Quote.csv"; //FileName 09. //+------------------------------------------------------------------+ 10. class C_ShareAtExcel 11. { 12. private : 13. string szSymbol[], 14. szFileName; 15. int maxBuff; 16. bool bError; 17. //+------------------------------------------------------------------+ 18. inline void Message(const string szMsg) 19. { 20. PrintFormat("Sharing service with Excel: [%s].", szMsg); 21. } 22. //+------------------------------------------------------------------+ 23. public : 24. //+------------------------------------------------------------------+ 25. C_ShareAtExcel(string szArg) 26. :bError(true), 27. maxBuff(0), 28. szFileName(szArg) 29. { 30. int file; 31. string sz0, szRet[]; 32. 33. if ((file = FileOpen(szFileName, FILE_CSV | FILE_READ | FILE_ANSI)) == INVALID_HANDLE) 34. { 35. Message("Failed"); 36. return; 37. } 38. while (!FileIsEnding(file)) 39. { 40. sz0 = FileReadString(file); 41. if (StringSplit(sz0, ';', szRet) > 1) 42. { 43. ArrayResize(szSymbol, maxBuff + 1); 44. szSymbol[maxBuff] = szRet[0]; 45. StringToUpper(szSymbol[maxBuff]); 46. maxBuff++; 47. } 48. } 49. FileClose(file); 50. bError = false; 51. Message("Started"); 52. } 53. //+------------------------------------------------------------------+ 54. ~C_ShareAtExcel() 55. { 56. ArrayResize(szSymbol, 0); 57. Message("Finished"); 58. } 59. //+------------------------------------------------------------------+ 60. void Looping(int seconds) 61. { 62. string szInfo; 63. int file; 64. 65. while ((!_StopFlag) && (!bError)) 66. { 67. szInfo = ""; 68. for (int c0 = 0; c0 < maxBuff; c0++) 69. szInfo += StringFormat("%s;%0.2f\r\n", szSymbol[c0], iClose(szSymbol[c0], PERIOD_D1, 0)); 70. if ((file = FileOpen(szFileName, FILE_TXT | FILE_WRITE | FILE_ANSI | FILE_SHARE_WRITE)) != INVALID_HANDLE) 71. { 72. FileWriteString(file, szInfo); 73. FileClose(file); 74. }; 75. Sleep(seconds * 1000); 76. } 77. } 78. //+------------------------------------------------------------------+ 79. }; 80. //+------------------------------------------------------------------+ 81. C_ShareAtExcel *share; 82. //+------------------------------------------------------------------+ 83. void OnStart() 84. { 85. share = new C_ShareAtExcel(user01); 86. 87. share.Looping(2); 88. 89. delete share; 90. } 91. //+------------------------------------------------------------------+
サービスのソースコード
ご覧の通り、コードは非常にコンパクトです。ただし、筆者の習慣としてここではクラスを使用しています。将来的に他の目的で再利用できるようにするためです。しかし、同じロジックをすべてOnStart関数内に書くことも可能です。
では、コードの詳細を説明します。これにより、MQL5初心者でもExcelに他の情報を送信する用途に応用できます。注記:ここではExcelへの転送を例にしていますが、他のプログラムやシステムに送ることも可能です。
2行目では、MQL5にこのコードをサービスとして扱うよう指示するプロパティディレクティブがあります。もしスクリプトとして使用したい場合は、2行目を無効化するか削除してください。コードの動作には影響せず、単にチャートにスクリプトをアタッチして実行できるようになります。
8行目では、使用するファイルをユーザーが定義できるようにしています。ファイルは前のセクションで説明した方法で作成し編集しておく必要があります。そうでない場合、システムは正しく動作しません。
10行目でクラスの定義を開始します。12行目にprivate宣言があることに注意してください。これは、この行以降のすべてがクラス内でのみ有効で、外部からアクセスできないことを意味します。その後、クラス用のグローバル変数を宣言し、18行目ではターミナルに表示するメッセージを標準化する手続きを作成します。これらのメッセージは、サービスが何をしているかを示します。
24行目ではpublic宣言をしています。この行以降、クラス内のすべてはクラスのインターフェースとして外部からアクセス可能です。26行目ではクラスのコンストラクタを作成しています。このコンストラクタは使用するファイル名を引数として受け取ります。ここでは、クラスがサービスコードの一部ではないかのようにプログラミングがおこなわれています。これがオブジェクト指向プログラミング(OOP)で正しい方法です。8行目に情報があるにもかかわらず、あたかも情報がないかのように考え、後で渡す形になっています。
33行目で指定されたファイルを開こうとします。読み取り用に開けなかった場合、35行目でユーザーに通知し、36行目で処理を終了します。ファイルにアクセスできた場合は、読み取りを開始します。読み取りは38行目で始まるループでおこなわれ、40行目でファイルから1行を読み込みます。41行目で、その行から銘柄名を抽出します。ここではセミコロン(;)を区切り文字として使用しています。
41行目で有効なデータがあれば、新しいメモリ領域を確保し、そこに銘柄名を保存します。銘柄名は大文字にする必要はありませんが、45行目で正規化しています。また、銘柄名が実際に存在するかどうかを確認するチェックはありません。つまり、正しい銘柄名を提供するのはユーザーの責任です。しかし、ここでは厳密な検証は不要です。もし間違えても、Excelが奇妙な結果を表示し、すぐに気づいて修正できます。したがって、MQL5内での銘柄名検証は必須ではありません。
すべてが順調に進めば、ファイルを閉じ、サービスがアクティブであることをターミナルに通知します。これは51行目でおこなわれます。
次にクラスのデストラクタがあり、54行目で開始します。わずか2行で、割り当てたメモリを解放し、クラスがシステムタスクリストから削除されることを通知します。
60行目にはプログラムのメイン手続きがあります。この手続きはサービスが停止されるまでクラスをループで実行し続けます。ループは65行目で開始します。注意してください。このループはプロセッサやプラットフォームに負荷をかけない方法で実行されます。各反復の間に一定時間待機し、他のタスクが実行されるようにしています。この待機は秒単位で指定され、75行目で次のループ反復前に一時停止しています。
ここからがループ内の実際の「マジック」です。67行目で、ファイルに書き込む文字列の内容をクリアします。Excelがファイルを読み込んでいる最中に書き込みをできるだけ速くおこなうため、68行目でループを実行します。このループで69行目に書き込むデータを構築します。この時点で、内容は何でも構いません。本当に何でも入れられます。
68行目のループが終了したら、70行目でファイルにアクセスを試みます。通常、他のアプリケーションがファイルを読み込んでいるときに書き込みをおこなうとアクセスエラーが発生します。これによりデータ転送が失敗することもあります。この種の問題は、プロデューサー–コンシューマーアルゴリズムでよく知られています。しかし幸いなことに、MQL5ではFILE_SHARE_WRITEフラグを使用でき、同時アクセスを許可することができます。
ファイルへの書き込みに成功した場合は、72行目で一括して書き込み、73行目で即座にファイルを閉じます。
こうしてサイクルが完了し、サービスが動作している限りループが続きます。
結論
本記事では、MetaTrader 5からExcelにデータを非常に簡単かつ効果的に転送する方法を学びました。この方法は、ポートフォリオの監視や、リアルタイム更新を必要としない取引管理に最適です。
下の動画では、システムの動作を確認でき、金融データ利用に関する細かい疑問も解消できます。システムは非常にシンプルで、記事の説明だけで誰でもコードを使用できます。そのため添付ファイルはありません。実際に監視したい資産は、各自で選択してください。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11794
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
Pythonを使用したボラティリティ予測インジケーターの作成
リスク管理(第2回):グラフィカルインターフェースでのロット計算の実装
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
市場シミュレーション(第5回):C_Ordersクラスの作成(II)
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
quote.csv "ファイルのエンコーディングはANSIで保存する必要があります。
まだうまくいっていません。別のエラーがあります。