
前回、「みんかぶFX 経済指標カレンダー 予想&速報」からGoogle Apps Scriptで、HTMLをスクレイピングして「重要度」「前回変動幅」を取得しました。
今回は、MetaTraderからGoogle Apps Scriptの関数を呼び出してJSONデータを取得し、チャート上に経済指標を表示してみます。
仕様とポイント
それではざっくりと仕様を決めていきます。
- みんかぶFXの経済指標を取得して、指標発表時刻に垂直線を引く
- 経済指標は、Google Apps Scriptを経由してJSON形式で取得する
- 経済指標は30分に1回取得する(過剰なトラフィックを発生させないようにするため)
こまかい仕様の調整は、ざっくりと作ったあとにトライ&エラーで行えますが、骨格部分は作り直すと結構な手戻りになってしまいます。
なので、この程度の仕様はコーディングにかかる前に決めておきましょう。
完成イメージはこんな感じです。
今回は、HTTP(S)通信、JSONのパース、指標データの内部管理など、いくつか注意するところがありますので事前にポイントを説明します。
WebRequest関数はインジケーターでは使えない
見出しそのままなのですが、WebRequest関数(HTTP(S)通信)はインジケーターでは使えません。
つまり、WebRequest関数はエキスパートアドバイザーかスクリプトからしか呼ぶことができないため、必然的に今回のように定期的にWebRequestを呼び出すためにはEAとして作成する必要があります。
1つのチャートで複数のEAを適用することはできませんので、この点は留意する必要があります。
アクセスするドメインは限られている
たいしたポイントでも制限でもありませんが、WebRequest関数でアクセスするドメインは事前に設定しておく必要があります。
MetaTrader(MetaEditorではありません)メニューの「ツール」ー「オプション」の「エキスパートアドバイザー」タブに、「WebRequestを許可するURLリスト:」にチェックを入れ、その下の一覧にドメイン名を記載します。
今回はGoogle Apps Scriptへのアクセスを許容するため、「https://script.google.com」を追加します。
このような面倒な設定が必要な理由は、セキュリティだと思われます。
自作のEAではなく、他人が作ったEAをソースではなく実行ファイル(.ex4)の状態で入手して使う場合、意図しないサイトへアクセスするようなプログラムがあっても防ぎようがありません。
Dos攻撃のようなスクリプトになっている可能性も否めません。
それらを防ぐための安全装置と思えばよいでしょう。
JSONのパースライブラリを使う
前回まで解説してきましたが、みんかぶFXの経済指標の結果をJSON形式で取得しまので、MQLでJSONをパース(構文解析)する必要があります。
JSONは比較的なフォーマットですが、イチから解析するプログラムを書くのはたいへんです。
そこで、今回は「MetaTrader 4のためのMQL4ライブラリソースコード」に掲載されている、JSON Parserを使用しました。
こういう便利なライブラリを提供してくれている先人に感謝です。
指標データの管理はCArrayクラスを使う
みんかぶFXで公開されている直近の経済指標は、当日を含めて6日分ありますので、取得するJSONの要素数も複数になります。
これらすべての要素の垂直線を引くことを考えると、プログラムの内部では配列として管理するのが自然です。
しかも、経済指標は毎日更新されますので、動的な配列(要素数が随時変わる)で管理する必要があります。
これもすでに提供されているライブラリを使うことにします。
MetaEditorに最初から含まれているCArrayクラス(Include/Arrays/ArrayObj.mqh)で実装しました。
経済指標を取得する
それでは実際に、経済指標を取得する部分のプログラムを見ていきます。
EAが起動したあと、しかるべきタイミングで経済指標を取得にいくのですが、処理が結構なボリュームがありますので、取得する部分を別関数(GetMinkabu())として定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
void GetMinkabu() { char post[], result[]; string cookie, headers; // Google Apps Scriptを実行する int ret = WebRequest( "GET", "https://script.google.com/macros/s/XXXXXXXXXXXXXXXXXX/exec", cookie, NULL, 10000, post, 0, result, headers); // 正常に取得できなかった場合は戻る if (ret != 200) { return; } // 取得したJSONを文字列化 string jsonStr = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8); // JSONのパース JSONParser *jp = new JSONParser(); if (jp) { JSONValue *jv = jp.parse( jsonStr ); if (jv) { JSONArray *ja = jv; int jaSize = ja.size(); // 配列要素をクリア gArray.Clear(); int available = gArray.Available(); if (available < jaSize) { gArray.Reserve(jaSize); } for (int i = 0; i < ja.size(); i++) { JSONObject *jo = ja.getObject(i); CEconomicAnnounce *ei = new CEconomicAnnounce ; ei.name = jo.getString("Name"); ei.desc = jo.getString("Description"); ei.year = jo.getInt("Year"); ei.month = jo.getInt("Month"); ei.day = jo.getInt("Day"); ei.hour = jo.getInt("Hour"); ei.min = jo.getInt("Min"); ei.star = jo.getInt("Star"); ei.pips = jo.getDouble("Pips"); gArray.Add(ei); } delete jv; } delete jp; } } |
具体的にやっていることは、大きく3つステップになります。
- WebRequest関数でGoogle Apps Scriptを呼び出す
- JSON形式で経済指標を取得
- 発表予定の指標1つずつの要素(指標名、発表時刻、重要度・・など)を配列に格納
7〜21行目:WebRequest関数呼び出し
この関数は引数が多く、何を設定していいのかがイマイチわかりづらいですが、今回のように「とりあえず指定のURLを呼び出して結果だけ受け取る」のは、そんなに難しくありません。
第1引数に”GET”、第2引数にURL(自作したGoogle Apps ScriptのURL)、第8引数に受け取る結果の変数を設定するのがキモです。
第3,6,9引数は使いませんが、とりあえずなにか変数を指定しておけばOKです。
また、第5引数はタイムアウト時間をミリ秒で指定します。アクセス先のURLが、ここで指定した時間以上レスポンスを返さない場合は処理をやめて、エラーとして処理します。ここでは10000(10秒)を指定しています。
戻り値は、HTTPのレスポンスコードになります。正常終了の200のみ以降の処理を継続します。
24〜44行目:JSONをパース
Google Apps Scriptから取得したJSONを分解していきます。
まずはじめに、HTTPのレスポンスをMQLで取り扱いやすいように、文字列(string型)に変換します。
Google Apps Scriptから取得したJSONはUTF-8で符号化されているため、そのままstring型の変数に代入しても正しく処理されません。
(ちなみに、string型はWindowsでいうUnicode、UTF-16で符号化されています)
24行目のCharArrayToString関数は、UTF-8のバイト列をstring型に変換します。
27行目から34行目までは、JSONをパースするためのクラスを生成して、配列に格納して要素数を取得しています。
37行目から44行目は、経済指標を保存している配列の管理です。
1回で取得する経済指標は合計で6日分なので、だいたい20〜30件分のデータがあります。
以降の処理を考え配列で管理します。
以下のようにグローバル変数で配列を定義して、EA初期化のタイミングで100件分の空の配列を作っておきます。
1 2 3 4 5 6 7 |
CArrayObj gArray; int OnInit() { gArray.Reserve(100); ・・・・ } |
42行目で取得した経済指標の件数をチェックして、初期化時に確保した配列の件数(100)より大きい場合は、43行目で配列を拡張します。
46〜64行目:経済指標を配列に格納
JSONデータをMQLで取り扱いやすいように、独自定義したクラスに格納します。
クラスといっても必要な変数をまとめただけのただの箱だと思ってください。メソッドもほとんど実装していないので、ただの構造体です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
class CEconomicAnnounce : public CObject { public: CEconomicAnnounce() { } ~CEconomicAnnounce() { ObjectDelete(0, objName); } datetime getDatetime() { string dateStr = IntegerToString(year) + "." + IntegerToString(month) + "." + IntegerToString(day) + " " + IntegerToString(hour) + ":" + IntegerToString(min) + ":00"; datetime dt = StrToTime(dateStr); return dt; } string name; string desc; int year; int month; int day; int hour; int min; int star; double pips; string objName; }; |
すべてのメンバー変数、メソッドをpublicで宣言しているので、内部のデータに好きなようにアクセスできます。
発表時刻の時分秒それぞれも取得できますし、getDatetimeメソッドを使ってMQLの日付型であるdatetime形式で取得できるようにもしています。
また、デストラクタ(~CEconomicAnnounce)では、EA全体のグローバル変数gArrayを初期化するときに、VLINEのオブジェクトを削除するようにしています。
データ管理と画面制御を同じクラスでやるのは、設計思想上どうかと思いますが、とりあえずよしとします。
JSONで取得したそれぞれのデータを、CEconomicAnnounceクラスのオブジェクトに格納して、gArrayで保存・管理します。
経済指標の発表時刻に垂直線を描画する
経済指標はFXでトレードをする際に、ポジションを保有したり手放す判断のポイントになるかと思います。
トレードに夢中になっても忘れないように、発表時刻に垂直線を描画します。
経済指標を格納したgArray配列から、指標内容を取り出して線を描画するShowMinakbu関数を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
void ShowMinkabu() { for (int i = 0; i < gArray.Total(); i++) { CEconomicAnnounce *e = gArray.At(i); // VLINEオブジェクト datetime dt = e.getDatetime(); dt -= ((9 - GMTOffset) * StrToTime("1970.01.01 01:00")); string objName = "EInd_V_" + IntegerToString(i); ObjectCreate(objName, OBJ_VLINE, 0, 0, 0); ObjectMove(objName,0, dt, 0); ObjectSet(objName, OBJPROP_COLOR, VL_Color); ObjectSet(objName, OBJPROP_STYLE, VL_Style); ObjectSet(objName, OBJPROP_WIDTH, VL_Width); // 指標の需要度を★で表示 string str, star = "☆☆☆☆☆"; switch(e.star) { case 1: star = "★☆☆☆☆"; break; case 2: star = "★★☆☆☆"; break; case 3: star = "★★★☆☆"; break; case 4: star = "★★★★☆"; break; case 5: star = "★★★★★"; break; } // VLINEのテキスト str = IntegerToString(e.year,4, '0') + "/" + IntegerToString(e.month, 2, '0') + "/" + IntegerToString(e.day, 2, '0') + " " + IntegerToString(e.hour, 2, '0') + ":" + IntegerToString(e.min, 2, '0'); str += " " + e.name + " " + star + " " + DoubleToStr(e.pips, 1) + "pips"; ObjectSetString(0, objName, OBJPROP_TOOLTIP, str); e.objName = objName; } } |
やっていることは、
垂直線を引いて、指標内容をテキスト(ツールチップ)表示するのを、指標の個数分繰り返す
だけです。
1つ気をつけるところは、MetaTrader4で表示しているブローカーの時間にあわせるところくらいです。
それでは、コードを見ていきます。
3〜5行目:配列から指標を取り出す
gArrayに格納された経済指標のデータを個数分取り出します。
CArrayの配列で、i番目にアクセスするには、
10 11 12 |
CEconomicAnnounce *e = gArray.At(i); |
と記述します。
8〜9行目:ブローカーの時間に合わせる
みんかぶFXの経済指標発表時刻は、日本時間で統一されていますが、MetaTrader4の時刻は、ブローカーによってまちまちです。
たとえば、XMTradingはタイムゾーンについて、FAQで以下のように記載されています。
弊社の取引サーバーは冬時間は常にGMT+2、夏時間は常にGMT+3となっております。
カテゴリー別よくあるご質問 – 「XMTradingホームページ」
日本はGMT+9ですので、日本が23時のとき、MetaTraderの現在時刻は冬であれば16時、夏であれば17時になります。
これを「みんかぶFX」の経済指標の発表時刻に対して補正(-7 or -6)すればよいのです。
6 7 8 9 |
// VLINEオブジェクト datetime dt = e.getDatetime(); dt -= ((9 - GMTOffset) * StrToTime("1970.01.01 01:00")); |
GMTOffsetがブローカーのタイムゾーン(上記の例であれば、+2か+3が入る)です。
MQLのdatetime型は、1970年1月1日0時0分が起算時刻ですので、1970年1月1日1時0分という時刻を設定すると、「1時間」を設定したことと同じことになります。ちょっとしたテクニックですので、覚えておいて損はないと思います。
この「1時間」にタイムゾーンの差(9 – GMTOffset)を乗算することで、ブローカーのタイムゾーンへの補正が完了です。
以降は、垂直線オブジェクトを任意の書式で描画(10〜15行目)、指標内容をツールチップ(オブジェクトにマウスカーソルをあわせることで表示されるテキスト)に設定(18〜34行目)しています。
さいごに
「みんかぶFX」から経済指標を取得するGetMinkabu関数を1時間おき位に呼び出し、ShowMinkabu関数で垂直線を描画すれば完成です。
経済指標の予定はかわることはないので、1日1回くらいの頻度で取得すれば大丈夫ですが、1時間おきくらいで動かしても問題ないでしょう。
Google Apps Scriptで「みんかぶFX」の経済指標を取得するJavaScriptのソースコードと、EAの実行ファイルを置いておきますので、よかったら使ってみてください。
不具合、要望などありましたらコメント欄にお願いします。
ダウンロード
2017/12/6(水)
MinkabuLite.zip(Ver.1.0 zip : 57,968バイト)
解凍後:minkabu.js MinkabuShihyoLite.ex4
補足
- minkabu.jsのコードをGoogle Apps Scriptにコピーし、「ウェブアプリケーションとして公開」、アプリケーションにアクセスできるユーザーは「全員(匿名ユーザーを含む)」としてください。
- MetaTraderには、エキスパートアドバイザーとして保存・実行してください。
- MetaTraderの「ツール」-「オプション」-「エキスパートアドバイザー」タブからWebRequestを許可するURLリストにチェックをいれ、https://script.google.comを追加してください。
下記の免責事項を確認してダウンロードしてください。ダウンロードした場合は、免責事項に同意したものとみなします。
日本語版OSのみ確認済み、VPSや日本国外では動作確認はしておりません
免責事項
このEA、プログラムを利用した事によって何かしらの損害を被った場合でも、当サイト管理者は責任を負いません。
また、プログラムを改造、リバースエンジニアリングなど、本来の目的と異なる利用方法により、何かしらの損害を被った場合でも、当サイト管理者は責任を負いません。
管理人 様
はじめまして、経済指標表示のEAダウンロードさせていただきました。
Google App Scriptで、以下のエラーが出てしまうのですが、どうすればよろしいでしょうか。
ReferenceError: “Parser” is not defined. (line 13, file “Code”)
富山さん
コメントありがとうございます。
Parserライブラリが、プロジェクトに追加されていないために発生するエラーです。
https://fx-shakariki.com/mt_economic_ind_2/
の「Google Apps Scriptへライブラリの追加」を参考にParserを追加してみてください。
管理人 様
経済指標表示のEAありがとうございます。
プログラミングはあまり得意ではないのですが、以下のようにやってみました。
Google App ScriptにダウンロードしたJSのコードをコピペする
Parserライブラリを追加
ダウンロードしたEx4ファイルをMT4のExpertのフォルダに入れてチャートに入れる
プロパティーのインプットタブのURLに自分のScript.google.comのURLを入力
経済指標の最終取得日時は表示されるのですが、肝心の経済使用がチャート上に表示されません。
何かやりかたが間違っているのでしょうか?
よろしくお願いします。
はじめまして、経済指標表示のEAダウンロードさせていただいたのですが
指標がチャート上に表示されません。EAはニコちゃんマークで更新時間が表示されますが垂直線、テキストが非表示、グーグルの設定済です。
はじめまして。経済指標表示のEAダウンロードさせていただきました。
Google Apps Scriptにどのコードをコピペしたらいいのか分かりません。
スクリプト初心者です。
管理人様
初めまして、ダウンロードさせていただいたのと自身のEAでも表示できるかなと思い打ち込んでみたのですが
”’
dt -= ((timeZone + TimeGMTOffset()) * StrToTime(“1970.01.01 01:00″));
・・・
ObjectSet(objName, OBJPROP_COLOR, clrWhite);
ObjectSet(objName, OBJPROP_STYLE, STYLE_DOT);
ObjectSet(objName, OBJPROP_WIDTH, 2);
”’
の部分GNTOffSet→TimeGMTOffset()
VL~~~→clrWhite,STYLE_DOT,2
と変更したのですが合っていますか?表示されずにどこが間違えているのかわからず…
管理人様
初めまして、ダウンロードさせていただいたのと自身のEAでも表示できるかなと思い打ち込んでみたのですが
”’
dt -= ((timeZone + TimeGMTOffset()) * StrToTime(“1970.01.01 01:00″));
・・・
ObjectSet(objName, OBJPROP_COLOR, clrWhite);
ObjectSet(objName, OBJPROP_STYLE, STYLE_DOT);
ObjectSet(objName, OBJPROP_WIDTH, 2);
”’
の部分GNTOffSet→TimeGMTOffset()
VL~~~→clrWhite,STYLE_DOT,2
と変更したのですが合っていますか?表示されずにどこが間違えているのかわからず…ご教授いただけると嬉しいです