東京レンジ逆張り×VWAP回帰で狙うUSD/JPYデイトレEA(完全ガイド+MQL4コード)

FX

本稿では、東京時間のレンジ傾向VWAP(出来高加重平均価格)への回帰を組み合わせたUSD/JPYのデイトレ戦略を解説します。初心者が最短で収益化に近づけるよう、発想の源泉、厳密な売買ルール、検証プロセス、実運用の注意点、そしてMQL4の完全EAまでを一式提示します。裁量要素は極力排除し、誰がやっても同じ結論になる再現性にこだわります。

戦略コンセプト:なぜ東京時間で「逆張り×VWAP回帰」なのか

USD/JPYは東京時間(おおむねブローカー時刻で08:00-12:00のイメージ)において、欧州・NY時間に比べてトレンドの伸びが限定的になりやすい時間帯があります。参加者の構成(実需・ヘッジ・仲値需給など)により、短期的に過度な乖離が収束しやすい局面が生まれます。ここで基準として用いるのが当日内VWAPです。価格がVWAPから一定距離だけ拡散したときに逆張りし、収束で利確するのが本戦略の骨子です。

売買ルール(俯瞰)

  • 銘柄:USD/JPY(主要通貨で板厚・スプレッドが小さいため検証の再現性が高い)
  • 時間軸:M5(5分足)— シグナル頻度とノイズのバランスが良い
  • 取引時間:ブローカー時刻でStartHour–EndHour(初期値08:00–11:30)に限定
  • 基準:当日内の累積VWAP(Tickボリュームを出来高の代理とする)
  • ボラ基準:ATR(14)(M5)

エントリー

  • 現在値がVWAP+K×ATR以上に離れたら売りVWAP−K×ATR以下に離れたら買い(初期K=0.7〜1.2推奨)
  • 一度のシグナルで最大1ポジ(再エントリーは価格が一旦VWAP側へ戻り、再度閾値を超えた場合のみ)

イグジット

  • 利確:固定TP(0.6×ATRなど)または「VWAPタッチ」でクローズ
  • 損切:初期SL(1.2×ATRなど)。含み益が0.5×ATR以上で建値ストップへ繰り上げ
  • 時間切れ:EndHour以降は新規エントリー停止。未決済があれば「VWAPに近い側」あるいは「クローズ時刻」で強制決済(どちらか固定)

期待値の源泉(初心者にも分かる市場構造)

東京時間は「値幅が出にくい一方、瞬間的なオーバーシュートが起こる」日が一定割合で存在します。VWAPはその日の平均的な約定コストの指標なので、短期の乖離はマーケットメーカーや裁定フローにより戻されやすい傾向が観察されます。本戦略は乖離の平均回帰にベットします。ただし、指標発表や要人発言など情報フローが強い日はトレンドが続きやすく、トレード回避が合理的です。

実践プロセス(手順)

  1. ブローカー時刻の確認:自分のMT4のサーバー時刻と日本時間の差を把握(夏時間の有無も)
  2. データ準備:USDJPYのM1/M5履歴を十分にダウンロード(欠損は埋める)
  3. パラメータ初期化:StartHour=8, EndHour=11.5, K=0.9, TP=0.6ATR, SL=1.2ATR
  4. ニュース除外:仲値(09:55JST前後)と重要指標(雇用統計・CPIなど)の直前直後は様子見
  5. 執行最適化:スプレッド上限(例:1.0pips)を超えたら新規停止、VPSで遅延を安定化
  6. 少額で実弾検証:テスターとライブのギャップ(スリッページ・再クオート)を把握
  7. 資金管理:日次損失上限(例:-2R)に達したらそこで終了

バックテスト設計(落とし穴回避)

  • モデル:「全ティック」または「Every tick based on real ticks」を推奨
  • コスト平均スプレッド+手数料+滑りを必ず織り込む(例:滑り0.2pips)
  • ウォークフォワード:2年ごとに最適化→直後1年で前進検証
  • 過剰最適化の抑制:KやTP/SLのレンジを絞りすぎない。グリッドは粗めで十分
  • 指標フィルター:除外ロジック(手動フラグでも可)込みでテスト

推奨パラメータ帯(初期値と調整の指針)

項目 推奨初期値 許容レンジ 考え方
K(VWAP乖離) 0.9 0.7–1.2 小さすぎると過剰エントリー、大きすぎると機会損失
TP 0.6×ATR 0.4–0.8×ATR 平均回帰の「戻りしろ」に合わせる
SL 1.2×ATR 1.0–1.6×ATR トレンド発生時の損失を限定
時間帯 08:00–11:30 07:30–12:00 仲値前後の波乱日は慎重に
最大ポジ 1 1–2 初心者は1に固定

典型パターン/回避すべきパターン

勝ちやすい局面

  • 東京序盤に一方向へ急伸(ニュース無し)→VWAPからの乖離が大きい
  • スプレッドが安定(1.0pips未満)、板が薄すぎない

負けやすい局面

  • 重要指標・要人発言の直前直後(トレンド継続)
  • 欧州勢の早出参加でトレンドが生まれている日

実装:MQL4の完全EA

以下はMT4で動作するシンプルな参考実装です。ブローカー時刻のパラメータ(StartHour/EndHour)は必ず自環境に合わせて調整してください。VWAPは当日内のM5バーのTickボリュームを用いて近似します。

//+------------------------------------------------------------------+
//| Tokyo VWAP Mean Reversion EA (USDJPY, M5)                        |
//| Simplified reference implementation (MQL4)                        |
//+------------------------------------------------------------------+
#property strict
input int    Magic       = 20250905;
input double RiskPerTrade= 0.01;     // 口座残高に対する1トレードのリスク
input double FixedLots   = 0.00;     // 0ならリスクから自動計算
input int    StartHour   = 8;        // ブローカー時刻の東京開始
input double EndHour     = 11.5;     // 同上(小数=分)
input int    AtrPeriod   = 14;
input double K           = 0.9;      // 乖離係数(VWAP±K*ATR)
input double TP_ATR      = 0.6;      // 利確(ATR倍率)
input double SL_ATR      = 1.2;      // 損切(ATR倍率)
input double MaxSpread   = 1.0;      // pips
input bool   UseBreakeven= true;
input double BE_Trigger  = 0.5;      // 利益が0.5*ATRで建値へ
input bool   CloseAtEnd  = true;     // 取引時間終了でクローズ
datetime lastBarTime = 0;

double Pip() { return (Digits==3 || Digits==5) ? 0.001 : 0.01; }
double PointPips(double p){ return p / Pip(); }

double GetATR(int period){
   return iATR(Symbol(), PERIOD_M5, period, 0);
}

// 当日内のVWAP(M5)を近似計算
double GetIntradayVWAP(){
   datetime dayStart = iTime(Symbol(), PERIOD_D1, 0);
   int bars = iBars(Symbol(), PERIOD_M5);
   double pv=0.0, vv=0.0;
   for(int i=0;i=StartHour && hour<=EndHour);
}

bool SpreadOK(){
   double sp = (MarketInfo(Symbol(), MODE_SPREAD))*Point;
   return (PointPips(sp) <= MaxSpread);
}

int CountPositions(){
   int c=0;
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic) c++;
      }
   }
   return c;
}

void ManageOpenPositions(double atr){
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;
      // 建値ストップ
      if(UseBreakeven){
         if(OrderType()==OP_BUY){
            if(Bid - OrderOpenPrice() >= BE_Trigger*atr){
               double newSL = OrderOpenPrice();
               if(OrderStopLoss() < newSL) OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
            }
         }else if(OrderType()==OP_SELL){
            if(OrderOpenPrice() - Ask >= BE_Trigger*atr){
               double newSL = OrderOpenPrice();
               if(OrderStopLoss() > newSL || OrderStopLoss()==0) OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
            }
         }
      }
      // 時間終了でクローズ
      if(CloseAtEnd && !TradingSession()){
         OrderClose(OrderTicket(), OrderLots(), (OrderType()==OP_BUY)?Bid:Ask, 3, clrNONE);
      }
   }
}

double CalcLotsByRisk(double stopPips){
   if(FixedLots>0) return FixedLots;
   double bal = AccountBalance();
   double riskMoney = bal * RiskPerTrade;
   double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
   if(tickValue<=0) tickValue=10; // フォールバック
   double lot = riskMoney / (stopPips * tickValue);
   // ブローカー制約
   double minlot = MarketInfo(Symbol(), MODE_MINLOT);
   double lotstep= MarketInfo(Symbol(), MODE_LOTSTEP);
   double maxlot = MarketInfo(Symbol(), MODE_MAXLOT);
   lot = MathFloor(lot/lotstep)*lotstep;
   lot = MathMax(minlot, MathMin(lot, maxlot));
   return lot;
}

void TryEntry(){
   if(!TradingSession() || !SpreadOK()) return;
   if(CountPositions()>0) return;
   double atr = GetATR(AtrPeriod);
   if(atr<=0) return;
   double vwap = GetIntradayVWAP();
   double bid=Bid, ask=Ask, mid=(bid+ask)/2.0;
   double threshold = K*atr;
   // シグナル
   int type = -1;
   if(mid >= vwap + threshold) type = OP_SELL;
   else if(mid <= vwap - threshold) type = OP_BUY;
   if(type==-1) return;
   // 価格・SL/TP
   double sl=0, tp=0;
   if(type==OP_BUY){
      sl = bid - SL_ATR*atr;
      tp = bid + TP_ATR*atr;
   }else{
      sl = ask + SL_ATR*atr;
      tp = ask - TP_ATR*atr;
   }
   double stopPips = PointPips(MathAbs((type==OP_BUY?bid:ask) - sl));
   double lots = CalcLotsByRisk(stopPips*Pip());
   int slip=3;
   int ticket=-1;
   if(type==OP_BUY){
      ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, slip, sl, tp, "VWAP MR", Magic, 0, clrBlue);
   }else{
      ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, slip, sl, tp, "VWAP MR", Magic, 0, clrRed);
   }
}

int OnInit(){ lastBarTime=0; return(INIT_SUCCEEDED); }
int OnDeinit(){ return(0); }
int OnTick(){
   // 新バーでのみ判断(M5前提)
   datetime bt = iTime(Symbol(), PERIOD_M5, 0);
   if(bt!=lastBarTime){
      lastBarTime = bt;
      TryEntry();
   }
   double atr = GetATR(AtrPeriod);
   if(atr>0) ManageOpenPositions(atr);
   return 0;
}
//+------------------------------------------------------------------+

運用オペレーションと実務チェックリスト

  • サーバー時刻の夏時間切替のたびにStart/EndHourを点検
  • スプレッド監視(上限超過で自動停止するが、定期的に確認)
  • 重要ニュース日は手動で「自動売買OFF」
  • 週次で損益のドリフトをチェック。直近1〜2か月でパフォーマンス劣化があればKや時間帯を微調整
  • VPS稼働監視、MT4ログのエラー点検(OrderSendエラー・再クオート等)

まとめ

本戦略は、東京時間の平均回帰バイアスVWAPという普遍的な基準を掛け合わせ、単純・再現性・実装容易性を満たす設計です。まずは小ロットで運用し、実環境の摩擦(コスト・滑り)を体感しながら、過剰最適化に陥らない範囲で微調整していくことを推奨します。

コメント

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