初心者向け『ごとうび逆張りEA』—東京仲値9:55の実需フローを味方にするUSD/JPYデイトレ入門

FX

本記事では、東京仲値(9:55)×「五十日(ごとうび)」の需給偏りを利用した、初心者でも実装可能なUSD/JPYのデイトレ戦略を徹底解説します。一般論ではなく、明確な取引ルール検証方法、さらにMQL4の完全自動売買EAまで載せています。証券口座(FX口座)をこれから開く方に向けて、基本のフローも最後にまとめました。難しい理論や専門用語は平易に説明しながら、「毎朝やるべき具体的手順」に落とし込みます。

本記事のテーマと結論

テーマは「東京時間9:55の仲値(なかね)決定に向けて偏りやすい実需フローを観察し、その直後の短時間に発生しやすい反転(リバーサル)を狙う」ことです。特に、5と0の付く営業日(五十日)や月末最終営業日は、実需のドル買い・円売り(またはその逆)が集中しやすく、9:30〜9:55に一方向へ進んだ価格が、10:00前後に一時的に戻る現象が見られることがあります。本記事は、この短時間の戻りを機械的ルールで捉える手法を提示します。

なぜ機能し得るのか(需給メカニズム)

  • 実需フローの集中:輸入企業の支払い、運用機関の為替ヘッジなどが仲値(9:55)に向けて取り引きされることがあります。
  • 注文の一極集中による一方向ドリフト:9:30〜9:55にかけて、価格が一方向に滑りやすい「ドリフト」が起きる日があります。
  • イベント後の反転:仲値通過後は実需フローが一巡し、短時間のポジション解消(利食い・巻き戻し)で反転が起きやすくなります。
  • 五十日・月末の強化:支払い・受け取りが集中しやすい日取りでは、この傾向が強まりやすいと考えられます。

重要なのは、常に起きるわけではない点です。従って機械的なルールとリスク管理(損切り・時間指定のクローズ)を徹底し、「平均して期待値がプラスか」という視点で運用します。

戦略の全体像

本戦略は逆張りです。9:55に向けて価格が一方向へ走った場合、通過直後の短時間で逆方向に取りにいく設計です。下記はデフォルトの考え方です。

  1. 対象:USD/JPY(MT4で最も一般的)。
  2. 日付フィルター五十日(5/10/15/20/25日)と月末最終営業日を優先。他の日でも稼働可だが、まずは上記に限定。
  3. 時間帯:9:30〜9:55の値動きを観察し、9:55直後〜10:05でトレード。
  4. 方向:9:30→9:55で上昇幅が規定以上ならショート下落幅が規定以上ならロング
  5. エントリー:9:55:05以降、短期平均(例:1分足の移動平均)割れ/超えなどの微条件を満たした瞬間。
  6. 手仕舞い時間指定クローズ(10:05)、もしくは利確/損切りの価格到達で決済。

具体的な売買ルール(ベーシック版)

  1. 判定足:1分足。
  2. ドリフト計測:9:30の価格と9:55の価格の差(pips)。
    上方向ドリフト=(9:55のBid − 9:30のBid)が+X pips以上
    下方向ドリフト=(9:55のBid − 9:30のBid)が−X pips以下
  3. エントリー方向
    上方向ドリフト時 → 9:55:05以降にショート(戻り取り)。
    下方向ドリフト時 → 9:55:05以降にロング(戻り取り)。
  4. トリガー:直近5本の平均価格(SMA5)に対するクロスで発動(より保守的)。
  5. 損切り/利確
    損切り(SL)=7〜10pips、初期値は9pips
    利確(TP)=8〜12pips、初期値は10pips
    時間指定クローズ=10:05:00に成行決済(どちらか先に当たればそちら優先)。
  6. フィルター
    スプレッドが2.0pips以下、約定拒否が少ない口座。
    重要指標(例:日本のCPI、米雇用統計など)が9:30〜10:10に被る日は停止
    ATR(14)が極端に低い/高い日は停止(例:5分足ATR(14)が1.0〜3.0pipsの範囲を推奨)。
  7. 同日複数回の禁止:1日最大1トレード

バリエーション(上級者向け)

  • 事前追随→ノーポジ→反転狙い:9:50までにドリフト方向へ小ロットで追随し、9:54でクローズ。その後は逆張りのみ。
  • バンド条件:ボリンジャー±1σ/±2σタッチをトリガー条件に組み替える。
  • 出来高代替:FXは板・出来高が不明確なため、ティック数を出来高代替に。9:50〜9:55にティック数が閾値超えで条件強化。

想定ケーススタディ

以下はイメージしやすいようにした数値例です(実際の値動きとは異なります)。

  1. ケースA(上昇→反転):9:30=151.20、9:55=151.38(+18pips)。9:55:10にSMA5割れでショート、TP=10pips到達(151.28)で利確。
  2. ケースB(下落→反転):9:30=150.80、9:55=150.62(−18pips)。9:55:12にSMA5上抜けでロング、10:05タイムアウト決済で+4pips。
  3. ケースC(ノートレード):9:30↔9:55の差が±8pips未満で条件未達、見送り。

バックテストの進め方(MT4)

  1. データ:USDJPYの1分足ヒストリカルを入手し、プラットフォームに取り込みます。
  2. タイムゾーン:ブローカー時間と日本時間(JST)のズレを固定パラメータで吸収します(例:JSTOffsetHours=+7など)。
  3. 対象日:まずは五十日月末最終営業日のみで検証。次に全営業日に拡大。
  4. 評価指標:勝率、平均損益、プロフィットファクター(PF)、最大ドローダウン(DD)、1トレード期待値。
  5. コスト前後:スプレッドと想定スリッページ(例:0.3〜0.8pips)を加味した成績を必ず確認します。
  6. ロバスト性:X(ドリフト閾値)、TP/SL、クローズ時刻を±20%で振り、成績が大きく崩れないか確認します。
  7. モンテカルロ:エントリー順序やスリッページをランダム化してばらつきを評価します。

MQL4 EA(完全自動売買コード)

以下のEAは、ブローカー時間からJST(日本時間)オフセットを入力してローカルに日本時間を推定し、五十日/最終営業日条件と9:55→10:05の逆張りルールを実装します。MT4のストラテジーテスターで1分足に対して検証してください。

//+------------------------------------------------------------------+
//|  EA Name  : GotobiFixReversalEA.mq4                              |
//|  Purpose  : Tokyo fixing (09:55 JST) reversal on gotobi & EOM     |
//|  Symbol   : USDJPY (5-digit brokers supported)                    |
//|  Timeframe: M1                                                    |
//+------------------------------------------------------------------+
#property strict

extern double Lots                = 0.10;
extern int    DriftPips          = 15;    // X pips threshold between 09:30 and 09:55
extern int    TPpips             = 10;
extern int    SLpips             = 9;
extern int    JSTOffsetHours     = 7;     // BrokerTime + offset = JST (e.g., 7 or 8)
extern bool   OnlyGotobiAndEOM   = true;  // true: trade only on gotobi & EOM
extern int    SMA_Period         = 5;     // trigger using SMA cross
extern int    EntryDelaySeconds  = 5;     // enter at or after 09:55:05
extern int    CloseHourJST       = 10;    // time-based close at 10:05 JST
extern int    CloseMinuteJST     = 5;
extern double MaxSpreadPips      = 2.0;
extern bool   OneTradePerDay     = true;

datetime lastTradeDay = 0;

int    pt; // point-to-pip scaler

int init(){
   pt = (int)MathRound( (MarketInfo(Symbol(), MODE_POINT) == 0.001 || MarketInfo(Symbol(), MODE_DIGITS)==3) ? 10 : 
                        (MarketInfo(Symbol(), MODE_POINT) == 0.00001 || MarketInfo(Symbol(), MODE_DIGITS)==5) ? 10 : 1 );
   return(0);
}

int deinit(){ return(0); }

int start(){
   if(Bars < 1000) return(0);
   if(IsTradeAllowed()==false) return(0);

   // Spread check
   double spreadPips = (MarketInfo(Symbol(), MODE_SPREAD) / pt);
   if(spreadPips > MaxSpreadPips) return(0);

   // Compute current JST time
   datetime nowBT = TimeCurrent();
   datetime nowJST = nowBT + JSTOffsetHours*3600;
   int y, m, d, hh, mm, ss;
   TimeToStruct(nowJST, y, m, d, hh, mm, ss);

   // One trade per day guard
   if(OneTradePerDay){
      if(TimeDay(lastTradeDay)==d && TimeMonth(lastTradeDay)==m && TimeYear(lastTradeDay)==y) return(0);
   }

   // Filter: only on gotobi & end-of-month business day if set
   if(OnlyGotobiAndEOM){
      if(!IsGotobiOrEOM(y,m,d)) return(0);
   }

   // Trading window: entry on/after 09:55:05 JST; close at 10:05 JST
   bool isEntryWindow = (hh==9 && (mm>=55)) || (hh==10 && mm==0 && ss<=30);
   bool isTimeToForceClose = (hh>CloseHourJST) || (hh==CloseHourJST && mm>=CloseMinuteJST);

   // Calculate drift from 09:30 to 09:55 JST using M1 close
   double drift = 0.0;
   bool   driftReady = GetDriftPips(y,m,d, drift);

   // Manage open position: force-close at 10:05 JST
   ManageOpenPositions(isTimeToForceClose);

   if(!driftReady) return(0);

   // Trigger: SMA cross confirmation
   double sma = iMA(NULL, PERIOD_M1, SMA_Period, 0, MODE_SMA, PRICE_CLOSE, 0);
   double prev = iMA(NULL, PERIOD_M1, SMA_Period, 0, MODE_SMA, PRICE_CLOSE, 1);
   double price = Bid;

   int dir = 0; // 1=long, -1=short
   if(drift >= DriftPips) dir = -1;
   if(drift <= -DriftPips) dir = 1;

   if(dir==0) return(0);

   // SMA cross in direction of reversal
   bool trigger = false;
   if(dir==-1){ // want short
      if(prev <= Close[1] && sma > Close[0]) trigger = true; // simple mean reversion flip
      // Alternate: use price crossing SMA
      if(Close[1] <= prev && Close[0] >= sma) trigger = true;
   }else if(dir==1){ // want long
      if(prev >= Close[1] && sma < Close[0]) trigger = true;
      if(Close[1] >= prev && Close[0] <= sma) trigger = true;
   }

   if(isEntryWindow && trigger){
      if(OneTradePerDay && lastTradeDay!=0){
         if(TimeDay(lastTradeDay)==d && TimeMonth(lastTradeDay)==m && TimeYear(lastTradeDay)==y) return(0);
      }
      OpenReversalTrade(dir);
      lastTradeDay = nowJST;
   }
   return(0);
}

// Compute drift (pips) from 09:30 to 09:55 JST
bool GetDriftPips(int y, int m, int d, double &driftPips){
   datetime t0930 = MakeJST(y,m,d,9,30,0);
   datetime t0955 = MakeJST(y,m,d,9,55,0);

   int i0930 = iBarShift(NULL, PERIOD_M1, t0930, true);
   int i0955 = iBarShift(NULL, PERIOD_M1, t0955, true);
   if(i0930<0 || i0955<0) return(false);

   double p0930 = iClose(NULL, PERIOD_M1, i0930);
   double p0955 = iClose(NULL, PERIOD_M1, i0955);
   double pipDiv = (pt==10) ? 0.001 : 0.01; // for JPY pairs with 3/5 digits
   driftPips = (p0955 - p0930)/pipDiv;
   return(true);
}

void OpenReversalTrade(int dir){
   double pipDiv = (pt==10) ? 0.001 : 0.01;
   double sl = SLpips * pipDiv;
   double tp = TPpips * pipDiv;

   if(dir==-1){ // short
      double ask = Ask;
      int ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 20, 
                             NormalizeDouble(ask + sl, Digits), 
                             NormalizeDouble(Bid - tp, Digits),
                             "GotobiFixReversalEA", 0, 0, clrRed);
   }else if(dir==1){ // long
      double bid = Bid;
      int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 20, 
                             NormalizeDouble(bid - sl, Digits), 
                             NormalizeDouble(Ask + tp, Digits),
                             "GotobiFixReversalEA", 0, 0, clrBlue);
   }
}

void ManageOpenPositions(bool forceClose){
   for(int i=OrdersTotal()-1; i>=0; i--){
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol()!=Symbol()) continue;
      if(OrderMagicNumber()!=0 && OrderMagicNumber()!=0){} // keep default

      if(forceClose){
         if(OrderType()==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), Bid, 30, clrYellow);
         if(OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask, 30, clrYellow);
      }
   }
}

// Helpers
bool IsGotobiOrEOM(int y,int m,int d){
   if(d==5 || d==10 || d==15 || d==20 || d==25) return(true);
   // last business day of month (Mon-Fri)
   int lastD = LastBizDay(y,m);
   if(d==lastD) return(true);
   return(false);
}

int LastBizDay(int y,int m){
   int d = DaysInMonth(y,m);
   while(IsWeekend(y,m,d)) d--;
   return(d);
}

bool IsWeekend(int y,int m,int d){
   datetime dt = StrToTime(StringFormat("%04d.%02d.%02d 00:00",y,m,d));
   int wd = TimeDayOfWeek(dt);
   return (wd==0 || wd==6);
}

int DaysInMonth(int y,int m){
   if(m==1||m==3||m==5||m==7||m==8||m==10||m==12) return 31;
   if(m==4||m==6||m==9||m==11) return 30;
   // February
   bool leap = ( (y%4==0 && y%100!=0) || (y%400==0) );
   return leap ? 29 : 28;
}

datetime MakeJST(int y,int m,int d,int hh,int mm,int ss){
   datetime jst = StrToTime(StringFormat("%04d.%02d.%02d %02d:%02d:%02d",y,m,d,hh,mm,ss));
   return jst - JSTOffsetHours*3600 + TimeCurrent(); // align to broker time base
}

void TimeToStruct(datetime t, int &y,int &m,int &d,int &hh,int &mm,int &ss){
   string s = TimeToStr(t, TIME_DATE|TIME_SECONDS);
   // format: YYYY.MM.DD HH:MM:SS
   y = StrToInteger(StringSubstr(s,0,4));
   m = StrToInteger(StringSubstr(s,5,2));
   d = StrToInteger(StringSubstr(s,8,2));
   hh= StrToInteger(StringSubstr(s,11,2));
   mm= StrToInteger(StringSubstr(s,14,2));
   ss= StrToInteger(StringSubstr(s,17,2));
}
//+------------------------------------------------------------------+

パラメータ解説と初期値の目安

DriftPips 15 9:30→9:55の絶対変化量。10〜20の間で調整します。
TPpips / SLpips 10 / 9 時間指定決済と併用。市場状態で微調整。
JSTOffsetHours 7 ブローカー時間→JSTの差分。夏時間で8になる場合あり。
OnlyGotobiAndEOM true まずは有利とされる日付に限定し、慣れたら全営業日に拡張。
MaxSpreadPips 2.0 コスト管理の肝。これ以上は原則停止。
OneTradePerDay true 過剰取引防止。日次1回に制限。

よくある失敗と対策

  • タイムゾーン設定ミス:JSTOffsetHoursを季節で見直します。
  • スプレッド拡大への無警戒:東京午前でも銘柄やブローカーにより拡大します。MaxSpreadPipsを守ります。
  • イベント日無視:重要指標や要人発言が近いと挙動が崩れます。経済カレンダーを確認します。
  • 過剰最適化:狭い期間でパラメータを最適化し過ぎない。ロバスト性テストを必ず実施します。

ブローカー/口座の基本選定

MT4が使えて、USD/JPYのスプレッドが安定して狭く、約定品質が良い口座を選びます。国内外問わず、デモ口座→小額リアルの順で確認しましょう。スキャルピング可否、約定拒否の頻度、約定スピードは実運用前に必ずチェックします。

初心者向け・口座開設の流れ

  1. FX会社の公式サイトから口座開設申込み(本人確認書類・マイナンバー等)。
  2. 審査完了後、ログイン情報が送付されます。
  3. MT4をPCへインストールし、デモ口座でUSD/JPYの操作に慣れます。
  4. 入金後はまず0.01〜0.10ロットで小さく運用し、スプレッドやスリッページを体感します。
  5. バックテストとフォワードテストの両方で、想定通りの挙動を確認してからロットを段階的に増やします。

毎朝のチェックリスト(テンプレ)

  • 今日は五十日/月末最終営業日か?
  • 重要指標・要人発言予定はないか?
  • スプレッドは2.0pips以下か?
  • 9:30→9:55のドリフトが±15pips以上あるか?
  • 10:05の時間指定クローズ設定は有効か?

期待値の考え方(簡易)

期待値EVは、EV=勝率×平均利益−(1−勝率)×平均損失−コストで見積もります。TP/SLを対等(例:10pips/9pips)とし、コスト(スプレッド+スリッページ)を1.0〜1.5pipsと仮定して、勝率が50%を少し超えるだけでもトータルでプラスになり得ます。勝率とリスクリワードの両方を微調整し、PF>1.1〜1.3を最低ライン、DD(最大ドローダウン)は許容範囲に収まるよう管理します。

よくある質問(FAQ)

Q1:五十日以外の日は動かしませんか?
A:最初は限定した方が分かりやすいですが、慣れてきたら全営業日に拡張してもかまいません。過去検証で優位性が残るか必ず確認してください。

Q2:夏時間でJSTとのズレが変わります。
A:JSTOffsetHoursを季節ごとに見直してください。テスターでは複数パターンを比較しましょう。

Q3:損切りが続きます。
A:ドリフト閾値(DriftPips)を引き上げる、またはイベント日をより厳しく除外してください。ロットは常に資金に対して小さく保ちます。

用語ミニ解説

  • 仲値(なかね):銀行が顧客向けに提示する当日の対顧客基準レート。日本時間9:55前後に決定されます。
  • 五十日(ごとうび):5の倍数日(5、10、15、20、25日)を指す商習慣。資金決済が集中しやすいといわれます。
  • PF(プロフィットファクター):総利益÷総損失。1を超えるほど戦略が利益体質である目安。

TradingView(任意)での可視化補助

必要であれば、以下のシンプルなPine Script v5で9:55ラインとドリフト計測を視覚化できます(裁量検証用)。

//@version=5
indicator("Tokyo Fix Drift Helper", overlay=true)
jst = input.session("0900-1500", "Tokyo Cash Session")
fixTime = input.time(defval=timestamp("Asia/Tokyo", year, month, dayofmonth, 9, 55), title="Fixing Time")
i930 = input.time(defval=timestamp("Asia/Tokyo", year, month, dayofmonth, 9, 30), title="Start Drift")
plot(vline(time == fixTime), title="09:55")
plot(vline(time == i930), title="09:30")

まとめ

「東京仲値×五十日リバーサル」は、短時間・明確ルール・低回数という特徴から、初心者でも学びやすい戦略です。機械的な執行とコスト管理、そしてイベント回避を徹底し、必ずバックテストと小ロットのフォワードテストから始めてください。コツは、日次1回・時間指定・コスト厳守の3点です。

コメント

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