質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MQL4

MQL4とは、MT4(MetaTrader4)で用いられるプログラム言語です。MT4は無料で使えるチャートソフトあり、MQL4を使うことで分析ツールのオリジナルスクリプトの作成ができます。

Q&A

2回答

1330閲覧

MQL4でのEA作成 トレードを実行する「通貨ペア」以外のチャート(過去データ)を「エントリー条件」に取り込む方法

chahiro

総合スコア0

MQL4

MQL4とは、MT4(MetaTrader4)で用いられるプログラム言語です。MT4は無料で使えるチャートソフトあり、MQL4を使うことで分析ツールのオリジナルスクリプトの作成ができます。

0グッド

0クリップ

投稿2022/03/07 06:15

編集2022/03/07 12:39

米国の代表的な株価指数である「S&P500」のチャートは、ほとんどのFX業者で表示させることができます。
また、米国の株価指数の上昇・下落は、翌日の東京市場の「米ドル/円」の値動きと強い相関関係があると言われています。
(「SP500」「US500」「SPXm」など、FXブローカーによって表記は様々ですが、ここでは
「SP500]と記載します。)

これらを利用し、前日のS&P500の終値(標準(冬)時間 米国時間16時 MT4時間23時 日本時間翌6時)が、前々日のS&P500の終値(同)よりも「0、5%」以上高ければ、その日の日本時間8時に「米ドル/円」を買い
反対に、前日のS&P500の終値(同)が、前々日のS&P500の終値よりも「0、5%」以上低ければ、その日の日本時間8時に「米ドル/円」を売る

つまり、
if(前日「SP500」(MT4時間22時59分(CLOSE)) ≧ 前々日「SP500」(同)×1、005)
午前8時(OPEN) USD/JPY OP_BUY
if(前日「SP500」(同) ≦  前々日「SP500」(同)×0、995
午前8時(OPEN)   USD/JPY OP_SELL
といったEAの構築を考えているのですが、なかなか上手くいきません。

上述のように、USD/JPYのトレードのエントリー条件に「S&P500」の値動き(過去のデータ)を取り込むためには、どのようなソースファイルを書けばよろしいのでしょうか?
また、米国の株式市場も日本同様に土、日、祝日、年末年始等は休場のため、「前日」「前々日」という指示では上手く実行されないかと思うのですが、どのようなソースファイルを書くのが最も適切なのでしょうか?

どなたか、MQL4に詳しい方がおられましたら、アドバイスを宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんな感じでどうでしょう?
サマー時間を求める関数は分からないので、ロジックで書いてみました。
日本時間をもとに 米国サマー時間を求めているので、米国時間に直してからチェックした方がいいかもしれません。
ただ、 日曜日が切り替わりなので問題はないかと思います。

終値の時間 15時, 14時のデータがなかった場合、その直前の時間を終値としています。

以上.

double Array[][6]; int nums; void xxx() { int time = ( CheckSummerTime_US( TimeLocal() ) ) ? 14: 15; // サマータイムによるチェック nums = ArrayCopyRates( Array, "SPX.pro", PERIOD_H1 ); // double_array[][6]配列に物理的にコピー int yesterday, before_yesterday; if ( ! GetSP500( Array, nums, time, yesterday,before_yesterday ) ) { Print ( "前日か、前々日のデータが見つけられなかった。" ); } else { Print ( "本日     : ", TimeLocal() ); Print ( "前日     : ", (datetime) Array[ yesterday][0], " 終値: ", Array[ yesterday][4] ); Print ( "前々日    : ", (datetime) Array[before_yesterday][0], " 終値: ", Array[before_yesterday][4] ); double d = Array[yesterday][4] / Array[before_yesterday][4]; if ( d >= 1.005 ) { // USD/JPY Buy } else if ( d <= 0.995 ) { // USD/JPY Sell } } } //+------------------------------------------------------------------+ // S & P 500の前日、前々日のポインターを求め。 // ary[][6] : 1時間足データ // nums : データ数 // time : 求める時間 // pos1 : 前日ポインタ // pos2 : 前々日ポインタ bool GetSP500( double &ary[][6], int nums, int time, int &pos1, int &pos2 ) { MqlDateTime dt; int ed, bd; int ep, bp; pos1 = -1; pos2 = -1; // 最初の前日データを探す for ( ep=0; ep < nums; ep++ ) { TimeToStruct( ary[ep][0], dt ); if ( dt.day != Day() ) break; // 今日ではない } if ( ep >= nums ) return ( false ); // 前日が見つからない。 ed = dt.day; // 前日 // 前日の中で、指定時間のデータを探す for ( ; ep < nums; ep++ ) { TimeToStruct( ary[ep][0], dt ); if ( dt.day != ed ) return ( false ); // 前日の指定時間のデータが無かった。 if ( dt.hour <= time ) break; } // 最初の前々日データを探す for ( bp=ep; bp < nums; bp++ ) { TimeToStruct( ary[bp][0], dt ); if ( dt.day != ed ) break; } if ( bp >= nums ) return ( false ); // 前々日が見つからない。 bd = dt.day; // 前々日 // 前々日の中で、指定時間のデータを探す for ( ; bp < nums; bp++ ) { TimeToStruct( ary[bp][0], dt ); if ( dt.day != bd ) return ( false ); // 指定時間のデータが無かった。 if ( dt.hour <= time ) { pos1 = ep; // 前日の指定時間データポインタ pos2 = bp; // 前々日の指定時間データポインタ return ( true ); // 前日、前々日のデータがあった。 } } return ( false ); // // 前々日の指定時間のデータが見つからない。 } //+------------------------------------------------------------------+ // 米国におけるサマータイムチェック 注. 時差による補正、現地時間の考慮はしていない。 // dt : 日本時間 (TimeLocal) // true : summer time // false : winter time bool CheckSummerTime_US( datetime dt ) { MqlDateTime dts ; MqlDateTime dts1; int dy; TimeToStruct( dt, dts ); if ( dts.mon < 3 ) return ( false ); else if ( dts.mon == 3 ) // 3月 { dts1 = dts; dts1.day= 1; dt = StructToTime( dts1 ); TimeToStruct( dt, dts1 ); // 3月1日の曜日を求める。 dy = ( 8 - dts1.day_of_week ); if ( dy == 8 ) dy = 1; // 8なら日曜日が1日 dy += 7; // 3月 第2日曜日 return ( dts.day >= dy ); // 夏時間? } else if ( dts.mon > 11 ) return ( false ); else if ( dts.mon < 11 ) return ( true ); else // 11月 { dts1 = dts; dts1.day= 1; dt = StructToTime( dts1 ); TimeToStruct( dt, dts1 ); // 11月1日の曜日を求める。 dy = ( 8 - dts1.day_of_week ); if ( dy == 8 ) dy = 1; // 8なら日曜日が1日 return ( dts.day <= dy ); // 夏時間? } } /**/ コード

投稿2022/03/09 11:31

編集2022/03/10 02:54
yu-ima

総合スコア249

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chahiro

2022/03/10 05:58 編集

貴重なアドバイスを有難うございます。 レベルの高いソースファイルですので、今から拝見し、時間を掛けて熟読させていただきます。
guest

0

私も使ったことは無いのですが、
ArrayCopyRates : 配列に価格データをコピーし、コピーしたバー数を返す関数が使えるのではないでしょうか?

以下のように、[0][4]に前日の終値、[1][4]に前々日の終値が入ります。
前日、前々日とは、あくまでも営業日の事です。
時間を指定する場合は、PERIOD_H1として配列にある時間[?][0]をサーチしてから参照すればいいと思います。
また、配列の参照には、配列数(n)を確認して参照してください。

double double_array[][6]; // 0 - 時間
// 1 - 始値
// 2 - 安値
// 3 - 高値
// 4 - 終値
// 5 - 出来高
int n;

n = ArrayCopyRates( double_array, "SPX.pro", PERIOD_D1 ); // BigBossの場合

投稿2022/03/07 14:50

編集2022/03/07 16:01
yu-ima

総合スコア249

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chahiro

2022/03/09 01:28

yu-imaさん、お早うございます。 早速の的確なご回答を有難うございます。 ご指摘のとおり、1時間足(PERIOD_H1)の価格データをコピーし、 double double_array[][6]  int n = ArrayCopyRates( double_array, "SPX.pro", PERIOD_H1 )でサーチすることにより、S&P500の終値時間のバーの位置を確認した上で、無事コンパイルすることができました。 適切なアドバイスを有難うございました。 浅学な私でも、 if( Array[10][4]  ≩  Array[34][4] ) USD/JPY OP_BUY if( Array[10][4]  ≨  Array[34][4] ) USD/JPY OP_SELL といったソースファイルを書くことで、何とか考えているEAを構築出来そうです。 重ね重ねのお尋ねで大変恐縮なのですが、「釈迦に説法」となってしまいますが、米国の金融市場(株式市場、先門市場等々)は、サマータイム制度を導入しており、3月第2日曜から11月第1日曜までの期間では各金融市場は1時間早く始まり1時間早くクローズしてしまうために、   標準時間 期間      SP500オープン 9時30分(米国現地時間)   クローズ  15時59分59秒(同)   夏時間 期間     SP500オープン 8時30分(同)        クローズ  14時59分59秒(同) となってしまいます。 バックテストを行う際に、SP500の終値(Array[n][4])がズレてしまいますと、バックテストの意味がなくなってしまうのですが、標準(冬)時間・夏時間の「1時間のズレ」を解決できるような良いコードというものは無いでしょうか? もしご存じでしたら、引き続きアドバイスをいただけましたら幸いです。
yu-ima

2022/03/09 09:07 編集

もう暫くお待ちください。 ソースをテストしています。 上のソースを見ますと、前日、前々日の15時を固定の添え字、10, 34としておられますが、1時間足での価格データが必ず24個あるとは限りません。 また、調べる時間が決まった時間とは限りませんので、 固定では問題があると思います。
chahiro

2022/03/10 06:07 編集

yu-imaさん、こんにちは。 お世話になります。 ご返信、有難うございます。
chahiro

2022/03/11 01:53 編集

yu-imaさん、お早うございます。 お世話になっております。 色々と貴重なアドバイスをいただき、有難うございます。 ご指摘のとおり、私が利用しておりますTrade Viewで「SP500」の1時間足チャートを確認してみましたところ、24時台(=0時台 日本時間1時台)のローソク足は存在していませんでしたので、1日23本のバー数となっていました。 また、yu-imaさんがおっしゃる通り、バーの位置の指定が「固定」の添え字では上手く実行されないということにも、遅ればせながら気付きました。 日本時間の「午前8時過ぎ」あたりでのエントリーを考えておりますので、8時(MT4時間 1時)を「起点」としますと、前日のSP500のクローズ(MT4時間22時59分59秒 米国現地時間15時59分59秒)は「2本前」のバー(24時台のバーが無いため)の終値、前々日のそれは「25本前」のバー(同)の終値となりますので、「PERIOD_H1」ですと、    前日 Array[起点から2][4]      前々日 Array[起点から25][4] で間違いないかと思います。 初心者による思い付きなのですが、一旦「サマータイム制」や「決済条件」等を不問にしますと、下記のとおり、まずエントリー条件に「時間的な条件」(8時 ~ 8時14分59秒)を設定し、「RSI」というオシレーター系のテクニカル指標による条件(RSI<30買い RSI>70売り)も追記し、メインの条件である前日のSP500「0、5%以上 上昇」「0、5%以上 下落」の条件を併記した「エントリー条件」(「RSI」による条件が満たされなかった場合には、8時15分00秒にエントリー)としたソースファイルでは、上手く実行されないでしょうか? #property strict  int StartHour = 1 ;    //日本時間午前8時~  int EndHour = 1 ;     int EndMin = 14 ;  int EndSec = 59 ;    // 同 午前8時14分59秒まで  int RSIPeriod = 3 ;   // RSIの期間パラメーター void OnTick() { double RSI0=iRSI(_Symbol,PERIOD_M1,RSIPeriod,PRICE_CLOSE,0)      //最新のRSIであることの宣言 if(TimeCurrent() ≩ StartHour && TimeCurrent() < EndHourEndMinEndSec && RSI0<30 && Array[2][4]≩Array[25][4]*1.005 ) { OrderSend(USD/JPY,OP_BUY,Lots,Ask,0,0,0) }    //前日SP500が前々日SP500より0、5%以上高ければ、日本時間午前8時~8時14分59秒の期間        内で、RSI0がLEVEL30を下回ったタイミングで「買い」エントリー else (TimeCurrent() == Hour1,Min15,Sec00 && Array[2][4]≩Array[25][4]*1.005 ) { OrderSend(USD/JPY,OP_BUY,Lots,Ask,0,0,0) } }    //条件の時間内(8時 ~ 8時14分59秒)にRSI0がLEVEL「30」を下回らなった場合には、      8時15分00秒で「買い」エントリー  「売り」エントリーの場合は、「RSI0>70」「 Array[2][4] ≨ Array[25][4]*0.995」 その他同じ 上記のソースファイルでしたら、時間的条件である8時台が「起点」となるため、前日(Array[2][4])と前々日(Array[25][4])のSP500の終値を指定できているようにも思えるのですが、このようなソースファイルの書き方ではマズイでしょうか? 引き続きご教授いただけましたら、大変幸いでございます。
yu-ima

2022/03/11 05:22 編集

こんにちは。 拝見しました。 Chahiro様が書かれているソース等は、「プログラムする時の概念として書かれている」と思って指摘させていただきます。 1. TimeCurrent()は、サーバータイムです。 TradeViewは、米国にサーバーがあるのですね。   もし、別の国にサーバーがあるとすると、時間がずれるかもしれません。 1.1. iRSIのシフト量は、1かもしれませんね。 0だと、未だ未完成の現在足ですから。 2. OrderSend(OP_BUY)の条件しか書かれていませんが、当然OP_SELLの場合も追記されるのですね。 3. 条件が成立し、OpederSend(OP_BUY/OP_SELL)が行われた後は、引き続き条件を調べてOrder_Sendを行うのですか?    OnTickは、売買がある度に呼ばれます。 条件が成立するとどんどんOederされてしまいます。    一度OrderSendを行ったら、次は条件を調べないか、或いは、もっと特別な条件があるまでスキップする必要があると思います。 4. MT4は、再起動や、チャートの時間足を切り替えると、ローカル変数を初期化し、OnInitから呼び直されます。    従って、上のようなフラグをローカル変数に覚えておいても初期化されてしまいます。 Fileか、グローバル変数に覚える必要があると思います。 5. これは、プログラムが正しく書かれていれば どの様な書き方でも問題ないのですが 私は次のようなことに気をつけて書くようにしています。    1. プログラムのメンテナンスを行うときのため後から分かりやすいようにインデントを付ける。    2. { .... }を使って階層構造に気おつける。    3. 勿論コメントもつける。    4. if文では、入れ子と、階層構造を使用して同じ条件の記述はさける。    など....あくまでも、作者の主観なので正しく動くなら問題ないのですが...... 以上.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問