今回は、MT4のEAサンプルソース(FX用)を公開します。
トレードに使うトリガーは時間です。
はじめに
最近、東京時間(主に午前8時~午後3時)に家にいる事が多くFXのドル円チャートをずっと眺めているんですが、東京時間ってよくロング方向に動いてる?と疑問に思いました。
こういう時ってEAは便利ですよね。早速、EAを使って検証してみる事にしました。
2021年の1月1日~現在2021年6月4日にかけての情報となります。
※過去2005年~のトレード結果も最終的に確認しています
過去データで検証
まず、検証の内容です。
- 開始規定時間が来れば米ドル/円を無条件にロングエントリー
- 開始規定時間は午前8時とする
- 終了規定時間が来ればポジションを決済
- 終了規定時間は午後1時とする
- ポジションは1ポジション
- 損切り、利確幅は1円(100pips)
要は、朝8時にロングエントリーして午後1時になったら強制決済するという、ごく簡単なトレード手法となります。この内容で今年2021年の1月1日~検証してみます。
検証結果です。10万通貨でトレードして約21万円の利益となったのでやはり結構プラスになっている事が分かります!
とりあえずプラスの結果が得られたので良かったですが、時間を調整すればもっと良い結果になるのでは?と思って色々試してみました。
エントリー開始時間をはやくする
エントリーする時間を午前8時から午前7時に1時間はやめてみます。
検証結果です。なんと成績が倍良くなりました。10万通貨でトレードして約42万円の利益となったのでかなりのプラスですね。
決済時間を遅くする
決済する時間を午後1時から午後2時に1時間は遅くしてみます。
※ちゃんと比較するためエントリー時間は午前8時に戻しています
検証結果です。成績は10万円ほど良くなりました。先ほどのエントリー時間をはやめる方と比べるとそれほどインパクトは無いですが、成績は良くなったので決済時間をもう少し遅くすればいい結果に変わるかもしれないですね。
最善の時間帯を調査する
これまで確認した情報を元に、実際に何時から何時までロングしていれば一番良かったのかを確認していきます。
時間帯 | 有効性(PF) | 利益 | 勝率 | 取引回数 |
---|---|---|---|---|
午前8時~午後1時 | 1.43 | 212,200 | 52.78% | 108 |
午前7時~午後1時 | 2.00 | 420,600 | 60.19% | 108 |
午前7時~午後2時 | 2.10 | 434,200 | 58.33% | 108 |
午前7時~午後3時 | 2.04 | 452,200 | 60.19% | 108 |
午前7時~午後4時 | 2.35 | 654,700 | 56.48% | 108 |
午前7時~午後5時 | 1.95 | 621,100 | 59.26% | 108 |
結果はこんな感じです。※アルパリのヒストリカルデータで確認しています
午前7時~午後4時までが一番良さそうな感じになりました。かなり良い結果だと思います。
ゴトー日に絞ればもっと良い成績になるのでは?
東京時間にロングエントリーのトレードというと、ゴトー日や仲値関連のトレードを思い浮かべる方も多いのではないかと思います。
ということで、取り合えず日付別の利益率をクオンツアナライザーで見てみる事にしました。
こちらが日付単位の成績ですが、特にゴトー日が強いという事はなさそうです。9日がちょっと弱いですが誤差レベルだと思います。
もっと時間を限定して午前10時までのトレードとか、仲値トレード寄りに絞ったら結果は変わるかもしれませんが今回は仲値トレードは特に意識していないため無視しました。
このトレードを永遠続けたら勝てるんじゃないの?
今年に限らず、このトレード手法ずっとやってれば勝てるんじゃないの?と不覚にも思ってしまったので、2005年から通して確認してみました。
全然ダメでした!
2010年には資金が尽きるという結果になってしまったので、この手法は最近だけの一時的なものだという事がわかりますね。2016年の後半あたりから一応何とか横ばいからプラスになってくるような感じでした。
ダウンロード
上記のEAファイルになります。
“東京時間にロングするEA” をダウンロード 14_TokyoLong.ex4 – 2434 回のダウンロード – 17.16 KBサンプルソース
今回調査用に作ったEAのサンプルソースも一応掲載します。調査用に作ったので大雑把ですが調査要件は満たしています。
//+------------------------------------------------------------------+
//| TokyoTime.mq4 |
//| Copyright 2020, mef Software. |
//| https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, mef Software."
#property link "https://fx-prog.com/"
#property version "1.00"
input int STOP_LOSS = 1000; //ストップロスの値(1000=100pips)
input int TP = 1000; //プロフィット(利確)の値(1000=100pips)
input int A_SPREAD = 10; //エントリー及び決済時に許容するスプレッドの値です(10 = 10pips)
input double Lots = 1; //ロット数です(0.01=1000通貨)
datetime prevtime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
int start()
{
int orderPtn=0; //0:何もしない 1:買い 2:売り
int total=0;
double ea_order_stop_price=0,ea_order_good_price=0; //ストップロスレート,利確レート,エントリーレート
bool OrderKekka;
//---
//新しい足ができた時だけやる
if(Time[0] != prevtime){
prevtime = Time[0];
}else{
return(0);
}
//***売買判断箇所***//
//午前7時or8時にロング
if(IsSummerTime()==true){
if(Hour() == 1){
orderPtn=1;
}
}else{
if(Hour() == 2){
orderPtn=1;
}
}
//***売買判断箇所***//
//***決済判断箇所***//
total=OrdersTotal();
//午後4時に決済
if(total ==1 && Hour() == 10){
OrderKekka = funcOrder_Close();
}
//新規注文
if(total ==0 && orderPtn > 0)
{
if(orderPtn == 1)
{
ea_order_stop_price = Ask - STOP_LOSS * Point;
ea_order_good_price = Ask + TP * Point;
}
else if(orderPtn == 2)
{
ea_order_stop_price = Bid + STOP_LOSS * Point;
ea_order_good_price = Bid - TP * Point;
}
//新規注文
OrderKekka = funcOrder_Send(orderPtn - 1,ea_order_stop_price,ea_order_good_price,0,0);
}
return(0);
}
//+------------------------------------------------------------------+
//|【関数】新規注文関数 |
//| |
//|【引数】 ea_order_entry_Type:売買(0:買 1:売) |
//|【引数】 ea_order_stop_price:損切値 ea_order_good_price:利確値 |
//|【引数】 orderComment:オーダーコメント ea_order_MagicNo:マジックNo |
//| |
//|【戻値】True:成功 |
//| |
//|
bool funcOrder_Send(int ea_order_entry_Type, double ea_order_stop_price, double ea_order_good_price,int orderComment,int ea_order_MagicNo)
{
int order_resend_num; // エントリー試行回数
int ea_ticket_res; // チケットNo
int errorcode; // エラーコード
double ea_order_entry_price; // エントリーレート
color order_Color;
bool kekka;
for( order_resend_num = 0; order_resend_num < 10; order_resend_num++ ) { // エントリー試行回数上限:10回
if(MarketInfo(NULL,MODE_SPREAD) < A_SPREAD){
if(ea_order_entry_Type == OP_BUY){
ea_order_entry_price = Ask; // 現在の買値でエントリー
order_Color = clrBlue;
}else if(ea_order_entry_Type == OP_SELL){
ea_order_entry_price = Bid; // 現在の売値でエントリー
order_Color = clrRed;
}
// FXCMでは新規エントリー時にストップ/リミットを設定出来ない。
ea_ticket_res = OrderSend( // 新規エントリー注文
NULL, // 通貨ペア
ea_order_entry_Type, // オーダータイプ[OP_BUY / OP_SELL]
1, // ロット[0.01単位](FXTFは1=10Lot)
ea_order_entry_price, // オーダープライスレート
20, // スリップ上限 (int)[分解能 0.1pips]
ea_order_stop_price, // ストップレート
ea_order_good_price, // リミットレート
orderComment, // オーダーコメント
ea_order_MagicNo, // マジックナンバー(識別用)
0, // オーダーリミット時間
order_Color // オーダーアイコンカラー
);
}
if ( ea_ticket_res == -1) { // オーダーエラー
errorcode = GetLastError(); // エラーコード取得
if( errorcode != ERR_NO_ERROR) { // エラー発生
printf("エラー");
}
Sleep(2000); // 1000msec待ち
RefreshRates(); // レート更新
printf("再エントリー要求回数:%d, 更新エントリーレート:%g",order_resend_num+1 ,ea_order_entry_price);
} else { // 注文約定
Print("新規注文約定。 チケットNo=",ea_ticket_res," レート:",ea_order_entry_price);
Sleep(300); // 300msec待ち(オーダー要求頻度が多過ぎるとエラーになる為)
break;
}
}
return kekka;
}
//+------------------------------------------------------------------+
//|【関数】決済関数
//|
//|【引数】 なし
//|
//|【戻値】True:成功 False:失敗
//|
//|
bool funcOrder_Close()
{
bool kekka,OrderKekka;
int total,order_resend_num;
double ea_order_entry_price; // エントリーレート
color order_Color;
kekka=false;
for(order_resend_num = 0; order_resend_num < 100; order_resend_num++ ) {
if(MarketInfo(NULL,MODE_SPREAD) < A_SPREAD){
total=OrdersTotal();
if(total >0 && OrderSelect(0,SELECT_BY_POS,MODE_TRADES)==true){
if(OrderType() == OP_BUY){
ea_order_entry_price = Bid; // 現在の売値で決済
order_Color = clrLightBlue;
}else if(OrderType() == OP_SELL){
ea_order_entry_price = Ask; // 現在の買値で決済
order_Color = clrLightPink;
}
OrderKekka = OrderClose(OrderTicket(),OrderLots(),ea_order_entry_price,10,order_Color);
if(OrderKekka==false){
Print("決済失敗 エラーNo=",GetLastError()," リトライ回数=",order_resend_num+1);
RefreshRates();
Sleep(1000);
}else{
Print("決済注文約定。 レート=",ea_order_entry_price);
kekka=true;
break;
}
}
}else{
Print("スプレッド拡大中(銭)=",MarketInfo(NULL,MODE_SPREAD) / 10," リトライ回数=",order_resend_num+1);
Sleep(5000); // msec待ち
RefreshRates(); // レート更新
}
}
return kekka;
}
//+------------------------------------------------------------------+
//|【関数】サマータイム確認 |
//| |
//|【引数】 なし |
//| |
//|【戻値】True:サマータイム |
//|【備考】3月第2日曜日~11月第1日曜日までをサマータイムとする |
//| |
bool IsSummerTime(){
switch(Year()){
case 2005: if(StringToTime("2005.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2005.11.6"))return true; break;
case 2006: if(StringToTime("2006.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2006.11.5"))return true; break;
case 2007: if(StringToTime("2007.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2007.11.4"))return true; break;
case 2008: if(StringToTime("2008.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2008.11.2"))return true; break;
case 2009: if(StringToTime("2009.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2009.11.1"))return true; break;
case 2010: if(StringToTime("2010.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2010.11.7"))return true; break;
case 2011: if(StringToTime("2011.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2011.11.6"))return true; break;
case 2012: if(StringToTime("2012.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2012.11.4"))return true; break;
case 2013: if(StringToTime("2013.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2013.11.3"))return true; break;
case 2014: if(StringToTime("2014.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2014.11.2"))return true; break;
case 2015: if(StringToTime("2015.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2015.11.1"))return true; break;
case 2016: if(StringToTime("2016.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2016.11.6"))return true; break;
case 2017: if(StringToTime("2017.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2017.11.5"))return true; break;
case 2018: if(StringToTime("2018.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2018.11.4"))return true; break;
case 2019: if(StringToTime("2019.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2019.11.3"))return true; break;
case 2020: if(StringToTime("2020.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2020.11.1"))return true; break;
case 2021: if(StringToTime("2021.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2021.11.7"))return true; break;
case 2022: if(StringToTime("2022.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2022.11.6"))return true; break;
case 2023: if(StringToTime("2023.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2023.11.5"))return true; break;
case 2024: if(StringToTime("2024.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2024.11.3"))return true; break;
case 2025: if(StringToTime("2025.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2025.11.2"))return true; break;
case 2026: if(StringToTime("2026.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2026.11.1"))return true; break;
case 2027: if(StringToTime("2027.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2027.11.7"))return true; break;
case 2028: if(StringToTime("2028.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2028.11.5"))return true; break;
case 2029: if(StringToTime("2029.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2029.11.4"))return true; break;
case 2030: if(StringToTime("2030.3.10")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2030.11.3"))return true; break;
case 2031: if(StringToTime("2031.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2031.11.2"))return true; break;
case 2032: if(StringToTime("2032.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2032.11.7"))return true; break;
case 2033: if(StringToTime("2033.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2033.11.6"))return true; break;
case 2034: if(StringToTime("2034.3.12")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2034.11.5"))return true; break;
case 2035: if(StringToTime("2035.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2035.11.4"))return true; break;
case 2036: if(StringToTime("2036.3.9") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2036.11.2"))return true; break;
case 2037: if(StringToTime("2037.3.8") <=TimeCurrent()&&TimeCurrent()<=StringToTime("2037.11.1"))return true; break;
case 2038: if(StringToTime("2038.3.14")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2038.11.7"))return true; break;
case 2039: if(StringToTime("2039.3.13")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2039.11.6"))return true; break;
case 2040: if(StringToTime("2040.3.11")<=TimeCurrent()&&TimeCurrent()<=StringToTime("2040.11.4"))return true; break;
}
return false;
}
ブログを書いていて気付いたのですが、無条件に午前7時にするとサマータイム関連で1月や2月は午前7時ちょうどにトレード不可じゃないか、と思いサマータイムチェック入れました。
サマータイム時は午前7時からロングエントリー、それ以外は午前8時からロングエントリーといった感じにしています。
サマータイム関連の処理を入れると若干利益は落ちましたが、それでも良い結果です。
さいごに
以上、『東京時間にドル円ロングトレードしたらどうなるのか?』を確認するためのEAのサンプルソースでした。
結果として、ゴトー日等に関わらず近年はかなり有利にトレード出来る事がわかりました。
いつこの内容が崩れてくるかはわかりませんが、暫くはこのロングが強い時間帯において、相当明確なショートサインが無い限り裁量でショートエントリーで勝負するのは難しいのかなと思いました。
※2021/06/13更新 もう少し詳しく分析してみました
※ MT4・EAが使えるFX会社のおすすめ
※ EAのサンプルソースを一覧表にまとめました
コメント