相場の価格変動をCSV出力するEA(基準時間からの価格を取得)

CSV分析

どうも潤奈です( ・Д・)

今回は波のゆくさきArmadaさんがnoteに書かれているゴトー日を研究してEAを作ろう!の記事の途中過程にある、価格変動を日本時間基準でCSV出力させるコードを参考したCSV出力用EAを書いて行きたいと思います( ・Д・)

エキスパートアドバイザ作成

まずはMetaEditorで新規作成「エキスパートアドバイザ」を作成します。

任意の名前を決めてそのまま「次へ」をクリック。

そのまま「次へ」をクリック。

「OnTester」にチェックを入れて「完了」をクリックして下さい。
※OnTesterがCSV出力させるタイミングで必要になります。

ソースコード

ではコードを書き込んで行きます。

パラメーター作成

#property~の4行は作成した段階で挿入されている定型文なので、その下から入力して行きます。

1文づつの構成は、「修飾子 型 固有名=値; //コメント」となります。

まずMT4のサーバー時間は日本時間とタイムゾーン(GMT)が違うのでその差を修正する為に、GMT_Adjust変数でその時間差を宣言します。(証券会社によっては日本時間表示のMT4もあるのでチャートを開いて確認して下さい。)

【GMT(グリニッジ標準時間)とは】
イギリスのグリニッジ天文台(経度0度)を基準とした、世界各国の標準時でMT4のサーバー時間はGMT+2/+3を採用しているFX会社が多く、日本時間はGMT+9となります。

次に基準となる時間からの価格変動を取得したいので、基準となる「sHour=時」と「sMinutes=分」をそれぞれ宣言し、その基準からどこまで(eHour=時)取得するのか?の変数を宣言します。

全体に関わる変数/配列を宣言

それぞれの変数/配列の説明はコメントで加えていますので詳細は割愛します。

ここで宣言する理由としては、{ }で閉じた中で宣言すると、別の{ }内で値を引き継いで利用が出来ない為(方法はありますが)、{ }の外であるこの段階で宣言します。

OnInit()内のコード

OnInit()はチャートに適用した時や、チャートの時間軸を変更した時に最初に呼び出される関数です。
なので、1回だけ計算すれば良い物などはここに書いてしまいます。

point→pipsに変換用の値を求める

_Digits変数で適用したチャートの通貨ペアの価格の小数点以下の桁数を取得します。
その取得した桁数をswitch処理で一致するcase(条件)に進み処理を行い、break処理でswitch処理から抜けます。

小数点以下の桁数が2桁と3桁の業者があったり、決済通貨(右側)が円かドルなどでも桁数が違うのでこういった調整が必要になります。

配列数の準備

各配列には各分毎×時の値を入れる為の箱数が必要なので、eHour=遡る時間に60分を掛けた値をpNum変数に入れておきます。

次にArrayResize関数でそれぞれの配列サイズ(数)を指定します。
+1にしているのは、基準となる時間も1枠必要なので〇〇時間+1分の配列サイズが必要になります。

例)10:00を含む10分後までの必要な配列サイズは、10分+1分必要になります。

計測開始年月日を取得

最初に処理される所なので、計測開始年月日としてここで現在年月日を取得し、「+」で連結させてsTime変数に入れておきます。

Year()の頭に(string)が付いているのは、datetime型であるYear()をstring型に変換する。という意味になります。

IntegerToString関数は、指定した桁数に足らない場合、指定した文字で埋める関数です。
例えばMonth()=1の場合、1桁しかないので’0’で文字埋めして2桁にするようにしているので01となります。

OnTick()内のコード

OnTick()はティックを受信する度に処理される関数です。

サマータイム切り替え日を求める

アメリカ基準時刻の業者では夏時間:3月第2日曜日で切替わり、冬時間:11月第1日曜日で切替わります。
MT4には第〇〇曜日が〇日です。という事を求める関数がないので計算しないといけません。

夏時間と冬時間の求め方は同じで、StrToTime関数で現在年と”.03.14″(冬は”.11.07″)を連結させた文字をdatetime型の時間に変換して、SummerTime(WinterTime)変数に入れます。
そしてTimeDayOfWeek関数でその年月日の曜日を取得(日曜日:0~土曜日:6)して86400を掛けて秒数に変換します。
その値をSummerTime変数の年月日から減算(-=)します。

つまり、その年の3月14日が日曜日であれば0なので値に変更なしで、水曜日であれば3×86400=3日分の秒数を引いた3月11日が日曜日という事になります。

サマータイム判定

TimeCurrent()関数でサーバー時間を取得してCurrentTime変数に入れます。
Summer変数には0を代入しておきます。
そしてif()関数で先ほど求めた夏時間と冬時間の切り替え日の間に、現在のサーバー時間が該当すれば、Summer変数に1を入れます。

日本時間を求める

GMT+2(夏時間GMT+3)のブローカーの場合、日本時間はGMT+9なので9-2=7をGMT_Adjust変数にパラメーターで設定します。
よってサーバー時間にGMT差7×3600(7時間分の秒数)を足した日本時間をjTime変数に入れます。

サマータイムの場合、MT4のサーバー時間はGMT+3になる為、GMT差は6になります。

次にTimeHour()関数とTimeMinute()関数を使って、日本時間の時と分を取得してjH変数に時、jM変数に分を入れます。

計測開始時分を確認して処理{ }

if()文でパラメーターで設定した時と分が現在の日本時間と同じか確認します。

次に基準となる現在の始値Open[0]と現在の時間Time[0]をそれぞれの変数に入れます。
Blank変数には0を、First変数にはstatic変数をint型の前に書いて初回だけ0が入るようにしておきます。

最後に計測するループ処理後にFirst変数に1を入れます。

計測する分数のループ処理

for()文で現在値0から遡る分数の回数ループ処理させます。
ここでのi変数に入る数は基準時間からの〇分前の数になります。

まずif()文で計測開始時間cTimeの時間(分)とこれから取得する時間(分)が同じかを確認します。
同じ場合はrate[i]配列に、取得した始値から基準価格の差(point)の値を、Pips変数で割ってpoint→Pipsに単位を変換して配列に加算(+=)します。
Count[i]配列には、加算した回数として1を足して行きます。

}else{ は、もし時間が違う場合は、ヒストリカルデータの欠損が考えられるので、Blank変数にその回数を足して行きます。

ところで、Time[i-Blank]という書き方をしているのは何故かについて詳しく説明します。

まずi変数は〇分前という数で使用しますので以下の表のようになります。

しかし、例えば9:54のヒストリカルデータが欠損していたとしたら次の表のように、欠損した所から1分ズレてしまいます。(これが結構あるんです…)
理想の挙動としては欠損していた場合、もう一度同じi変数の値から取得して行かないといけません。

なので取得したい時間と違った場合、Blank変数に1を足してTime[i-Blank]とする事で欠損していた場合は値を取得せずに、次の処理でもう一度同じ値を取得するという処理になるようにしています。

1列目の時間情報を取得して格納

出力させるイメージはA列のようなデータです。
これは変動するデータではないので1回だけ処理出来れば良いです。

if()文で初回のみ処理させます。
まず、日本時間jTimeからループで回ってくるi=〇分に60を掛けた秒数を引いて、その時間(時)をtHour変数に入れます。
次にcTime変数の時間(分)をtMinute変数に入れます。

そして、rateTime[]配列に取得した時間(時、分)を文字列として繋げて入れます。

if()文を抜けた所で、cTime変数の時間を手動で60秒減算(-=)しておきます。

更に、for()文を抜けた所でFirst変数に1を入れます。そうする事で最初のfor()文のループ処理だけrateTime[]配列にデータを入れる処理をする事が出来ます。

OnTester()内のコード

OnTester()関数はバックテストをした際、最後に処理される関数です。
ここにCSV出力のコードを書いて行きます。

計測終了年月日を取得

コード構成は開始年月日を取得時と同じです。
この最後に処理されるタイミングの年月日を取得して繋げたデータをeTime変数に入れます。

CSVファイル準備

ファイルデータの名前として必要な情報を連結してfName変数に入れます。
CSVファイルなので最後に”.csv”を付け忘れないように注意して下さい。

【ファイル名に使用出来ない文字】
MT4上ではエラーは出ませんが正しく出力されない可能性があります。
\ / : * ? ” < > |

FileDelete()関数でfName変数の名前のデータがあれば削除させます。

FileOpen()変数でcsvファイルを作成します。
各引数はCSVファイルを作成するのに必要な引数として覚えて頂いたら問題ないです。

【バックテスト後の注意】
実際にバックテストした後にファイルを開くと思います。そのファイルを開いたまま再度バックテストするとMT4ではそのファイルを操作出来ないので必ずCSVファイルを閉じて下さい。

見出しを書き込む

FileOpen関数で開いているファイルfOpenに”日本時間”,”Pips”を書き込みます。それぞれの要素を「,」で区切る事でセルが分かれます。

FileSeek関数で行末(ファイルの最後)に移動します。

各分毎のデータを書き込む

for()文でi変数には取得した分数を入れて、減算させながらループ処理させて行きます。

まず価格変動幅を入れる変数pRangeを宣言します。
そのpRange変数に取得合計したrate[]配列を取得回数Count[]配列で割って平均値を入れます。

FileWrite関数で指定ファイルfOpenに時間rateTime[]と変動幅(平均)pRangeを書き込みます。
FileWrite関数はファイルの書き込み後に改行文字が追加されるので自動で改行されます。

すべて書き込み後、FileClose関数で指定ファイルfOpenを閉じます。

まとめ

今回は指定した時間に該当した時点からの価格変動幅を取得しましたが、そこに日付条件を入れる事で特定の日の動きや、インジケーターである条件になった時の動きなど応用は沢山出来ます。

バックテストなどで勝てるロジック(結果を見て)探すのも良いですが、そのベースになるローソク足(価格の動き)を分析する事はロジックを考える上でもかなり重要だと思います。

そういった点で波のゆくさきArmadaさんのnoteにはその考え方が書かれておりとても勉強になります( ・Д・)

【免責事項】

※当ソースコードにおける如何なる損失もご自身の自己責任となります。投資資産における運用の結果生じた損害の全部若しくは一部について一切の責任及び負担を負わないものとします。
※当ソースコードにつきましても、バグや不具合がないことを保証するものではありません。

※当ソースコードについてはサポート等については行っておりません。
※このブログで掲載されている情報は、投資等の勧誘又は推奨を目的としたものではありません。
※掲載されている内容は予告なしに変更することがあります。

EAの全ソースコード

以下の記事をご購入頂きましたら今回のEAの全ソースコードをまとめて閲覧する事が出来ますので、コピーして作成すればすぐにバックテストで試す事が出来ます( ・Д・)

尚、この無料記事にすべて記述していますので、模写して行けば同じ物が出来ます。

時短を考える方、この記事を評価して頂ける方だけご購入ご検討下さい( ・Д・)

CSV分析
スポンサーリンク
#潤奈FXをフォローする
スポンサーリンク
MT4でEA自作ブログ【潤奈FX】

コメント

  1. きき より:

    CSV_Analysis003 USDJPY,M1: array out of range in ‘CSV_Analysis003.mq4’ (83,47)
    とエラーが出て、CSVが出力できなくなりました。
    何が原因かわかりますか?
    お手数ですがよかったら教えてください。

  2. きき より:

    追記
    始値のみのビジュアルモードにチェックを入れたら吐き出されますがそういった仕様なのでしょうか??

    • 潤奈FX 潤奈FX より:

      お問合わせありがとうございます!
      まずarray out of rangeのエラーに関しては、恐らく全ティックでのバックテストを行った際に発生していると思われます。
      こちらに関して、私でも事象を確認致しましたが、原因の特定には至っていません。
      このコードは1分毎のデータを取得する為の物ですので、バックテスト時のモデルは「始値のみ」で問題ありません。勿論、期間は「M1」に設定して下さい。
      そしてビジュアルモードにチェックは入れなくても処理はされるはずですので、お試し下さい( ・Д・)

  3. もとのり より:

    特定の時間におけるRSIやMAの数値を条件に入れたいのですが、思い当たる場所に何個かコードを入れたのですが価格変動が取得できませんでした。どこに条件文を挿入すればよろしいでしょうか?

    if(rsi>70 && Close[1]>Open[1] && hour==10 && minute==45)
    のようなコードを入れてこの条件での価格変動を取得したいです。

    お手隙の際にご返信いただけますと幸いです。

    • 潤奈FX 潤奈FX より:

      すみません。RSIやMAを「条件」に入れて価格を取得したい意味がよく分からないかもです。
      例に書いて頂いている条件がEA等のエントリー条件なら分かるのですが。
      価格変動は条件で絞って取得するのではなく、前後のデータも拾ってその変動を見るものだと思います。
      その結果、10時45分が高値になりやすいけど、精度を上げる為にRSIで条件を絞ってエントリー。という使い方ではないでしょうか。

      もしくはやりたい事はこちらでしょうか?
      RSIの値をRSI変動として取得して、RSIが70以上になりやすい時間帯を探す。であれば、こちらの記事のコードは参考になると思います。
      Open[i]→iRSI(_Symbol,0,14,PRICE_CLOSE,i)に置き換えるような形で調整してみては如何でしょうか。( ・Д・)

      • もとのり より:

        説明不足ですみません。
        EAのエントリー条件です。その条件でエントリーした時のみの前後の価格変動を取得するという意味でした。

        • 潤奈FX 潤奈FX より:

          返信が遅くなりました。
          質問の意図が上手く汲み取れずすみません。
          記事の通りでは価格変動取得出来ましたか?要は特定の条件下のみでの価格変動に絞って取得したいという事ですね!
          それであれば最初のコメントに書いて頂いているif文の中で問題ないかと思うのですが、取得出来ないというのが何故でしょうね( ・Д・)?
          全く取得出来ていないのか、取得している回数が極端に少ない場合は条件が思ったより厳しいのかもしれません。
          if文内に入った回数をカウントする変数を用意してみるのもいいかもしれません( ・Д・)

          • もとのり より:

            記事の通りで条件を入れなければ取得することができました!非常に有益な記事を記述してくださりありがとうございます。

            エントリーの条件式をif文で{計測時間~OnTick終了}の手前まで囲ってテスターを回しましたが、CSVに価格変動は反映されませんでした。条件式は通過してカウントされているので原因がわかりませんでした。

            //条件式
            int count = 0;
            double rsi = iRSI(NULL,PERIOD_M1,14,PRICE_CLOSE,1);
            double rsi2 = iRSI(NULL,PERIOD_M1,14,PRICE_CLOSE,2);

            if(rsi>=70&&rsi2Open[1]){

            //計測開始時分を確認して処理{ }
            if(jH==sHour && jM==sMinutes){ //計測開始時分の確認
            double kOpen=Open[0]; //基準時間の始値を入れる
            datetime cTime=Time[0]; //計測開始の時間を入れる
            int Blank=0; //データがないローソク足計測用
            static int First=0; //初回だけ動かしたい処理制御に使用
            …….

          • 潤奈FX 潤奈FX より:

            if文で囲っているのに条件式を通過してカウントしているのは謎ですね。
            ちなみにコメントで書いて下さっている条件式でrsi2とOpen[1]を比較しているのは記入間違いですか?
            RSI値と価格は比較出来ないと思いますので気になりました。
            ただ、rsi>=70は正しいと思いますので通過しているのが謎です。
            バックテストしている条件が分かりませんが、RSI値を1分足から取得している様ですのでrsiとrsi2をPrint関数で値を表示してみて正しく取得出来ているか確認してみて下さい。
            何か分かるかもしれません( ・Д・)

タイトルとURLをコピーしました