初心者でも動かせるMQL4完全EA:ロンドン時間のUSD/JPY押し目順張りとATRリスク管理の実践ガイド

FX

本稿では、ロンドン時間のUSD/JPYに的を絞った「押し目順張り」戦略を、初心者でもそのまま再現できるように解説します。単なる概念紹介ではなく、MQL4の完全EAコードバックテストと最適化の手順日次オペレーションまでを一気通貫で提示します。ボラティリティが立ち上がるロンドン時間に限定し、トレンド方向の押し目だけを狙うことで、無駄なトレードを極力排除します。

戦略の全体像

対象はUSD/JPYの5分足または15分足です。上位トレンド=EMA50とEMA200の上下関係で規定し、短期の押し目=価格とEMA20の関係でエントリータイミングを決めます。モメンタムの確認にRSIを用い、ATRベースのストップ・利確・ポジションサイズで一貫したリスク管理を行います。取引時間はブローカーのサーバー時間でロンドン時間帯に限定し、00/50の切り番(ラウンドナンバー)に近い約定は避ける設計です。

なぜロンドン時間×USD/JPYか

ロンドン時間(日本時間で夕方以降)は、欧州勢のフローで流動性が厚くなり、東京時間のレンジを離れる動きが生まれやすい時間帯です。USD/JPYは実需・政策ニュース・債券金利の影響を強く受け、方向感が出た際の押し目回帰→再加速が比較的明確に観測されます。加えてスプレッドがタイトで、執行コストが読めることも初心者に適しています。

ルール(確定版)

以下はEA実装と完全一致するルールです。裁量の余地はありません。

トレンド判定

EMA50 > EMA200で上昇トレンド、EMA50 < EMA200で下降トレンドとします。トレンド方向以外の新規ポジションは取りません。

押し目・戻りのトリガー

上昇トレンド時は、直近で終値がEMA20を下回った後、再び終値がEMA20を上抜け、かつRSI(14)が55以上でロング。下降トレンド時は逆条件(EMA20再下抜け、RSIが45以下)でショートです。

フィルター

(1)取引時間:サーバー時間で指定の開始時刻~終了時刻のみ新規建て。(2)最大スプレッド:閾値超過時は新規不可。(3)ラウンドナンバー回避:約定価格が「xx.00」「xx.50」に近すぎる場合は見送り。(4)曜日回避:必要に応じて月曜の寄り付き/金曜の引け前を除外。(5)終盤クローズ:終了時刻の一定分前になったら保有ポジションを整理します。

リスク管理

ATR(14)×係数でストップ(SL)と利確(TP)を固定幅で設定します。既定値はSL=ATR×1.2、TP=ATR×1.5です。ロットは口座残高の0.5%リスクを上限に、SL距離から逆算して自動計算します。含み益が+1R到達で建値ストップへ引き上げ、以降はEMA20を追う簡易トレーリングで利益を残しやすくします。

パラメータ設計の考え方

EMA20は短期の押し目・戻りの「均衡点」として機能します。EMA50/200はトレンドの骨格で、方向判定の安定性を優先しました。RSIは閾値を55/45のわずかなバイアスに留め、過剰フィルタリングを回避します。ATR係数はスプレッド・平均波動・時間帯で変動するため、1.0~1.8の範囲で通貨ペアや足種に合わせて再調整してください。最大スプレッドはボラティリティの低い時間帯で厳しめ、高い時間帯で緩めに設定します。

バックテスト手順(MT4)

①MT4の「ファイル > データフォルダ」からMQL4/Experts配下にEAを保存し、再起動します。②ストラテジーテスターで「USDJPY」「M5またはM15」「Every tick(全ティック)」を選択。③スプレッドは「現在値」ではなく固定値を推奨(ロンドン時間の平均スプレッドに合わせる)。④テスト期間は最低でも2~3年、できれば4~5年。⑤次にパラメータの微調整のみを行い、過学習を避けます(例:ATR係数、RSI閾値、セッション時刻)。⑥ウォークフォワード:期間を2分割し、前半で調整・後半で検証、さらに年ごとローテーションで安定度を評価します。

実運用フロー

VPSで24時間稼働を基本とし、ロンドン時間前にMT4のログを確認します。日次では(1)スプレッド・板の荒れ具合、(2)重要指標の時間、(3)前日からの未決済ポジション管理、(4)終盤の自動クローズの作動確認を行います。週次では(1)約定履歴のR分布、(2)勝ち負けの連続性、(3)手仕舞いの妥当性、(4)サーバー時間の夏時間切替をチェックします。

初心者が躓きやすいポイント

①ロット過大(リスク%を守る)。②スプレッドの見落とし(最大スプレッドを数値で管理)。③時間帯の誤認(サーバー時間で設定)。④バックテストの「現在スプレッド」使用(固定値にする)。⑤切り番の手前で約定し捕まる(フィルター厳格化)。

MQL4完全EAコード(コピペで可)

以下を「Experts」フォルダに LondonPullbackEA.mq4 として保存してください。

//+------------------------------------------------------------------+
//|                                                LondonPullbackEA  |
//|                                    Simple London Session Pullback|
//+------------------------------------------------------------------+
#property strict

input int    MagicNumber        = 24090401;
input double RiskPercent        = 0.5;      // 口座残高に対するリスク%
input bool   UseFixedLots       = false;
input double FixedLots          = 0.10;

input int    EMA_Fast           = 20;
input int    EMA_Mid            = 50;
input int    EMA_Slow           = 200;
input int    RSI_Period         = 14;
input double RSI_Long_Thresh    = 55.0;
input double RSI_Short_Thresh   = 45.0;
input int    ATR_Period         = 14;
input double ATR_SL_Mult        = 1.2;
input double ATR_TP_Mult        = 1.5;

input int    SessionStartHour   = 8;        // ブローカー時間
input int    SessionEndHour     = 18;       // 例)8-18がロンドン中心帯
input int    CloseBeforeEndMin  = 10;
input bool   AvoidMonday        = true;
input bool   AvoidFriday        = true;
input double MaxSpreadPoints    = 30;       // ポイント(例:3.0pips相当)
input double RoundFilterPips    = 5.0;      // 00/50からの回避幅(pips)

datetime     lastAction=0;

// ユーティリティ
double PipPoints() { return (Digits==3 || Digits==5) ? 0.01 : 0.0001; }
double PointsPerPip() { return PipPoints()/Point; }
double GetSpreadPoints(){ return (MarketInfo(Symbol(), MODE_ASK) - MarketInfo(Symbol(), MODE_BID)) / Point; }

bool IsTradingHour(){
   int h = TimeHour(TimeCurrent());
   if(SessionStartHour <= SessionEndHour) return (h >= SessionStartHour && h < SessionEndHour);
   // 24h跨ぎ
   return (h >= SessionStartHour || h < SessionEndHour);
}

bool IsDayAllowed(){
   int dow = TimeDayOfWeek(TimeCurrent());
   if(AvoidMonday && dow==1)  return false;
   if(AvoidFriday && dow==5)  return false;
   return true;
}

bool NearRoundNumber(double price){
   // USDJPY向け:xx.00 / xx.50 から一定pips以内なら回避
   double pips_per_point = PointsPerPip();
   double price_pips = price / PipPoints(); // pip単位へ
   double mod50 = MathMod(MathRound(price_pips), 50); // 50pips刻み
   if(mod50 <= RoundFilterPips) return true;
   if(50 - mod50 <= RoundFilterPips) return true;
   return false;
}

bool SpreadOK(){ return GetSpreadPoints() <= MaxSpreadPoints; }

bool FlatTimeCloseSoon(){
   datetime now = TimeCurrent();
   int h = TimeHour(now);
   int m = TimeMinute(now);
   // 終了時刻のCloseBeforeEndMin分前以降は新規禁止、保有は手仕舞い
   int end = SessionEndHour;
   int minutes_to_end = ((end - h + 24) % 24) * 60 - m;
   if(SessionStartHour <= SessionEndHour){
      minutes_to_end = (end*60 - (h*60 + m));
   }
   return (minutes_to_end >= 0 && minutes_to_end <= CloseBeforeEndMin);
}

int CountOpenByMagic(int magic){
   int c=0;
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic) c++;
      }
   }
   return c;
}

double GetEMA(int period, int shift){ return iMA(Symbol(), 0, period, 0, MODE_EMA, PRICE_CLOSE, shift); }
double GetRSI(int period, int shift){ return iRSI(Symbol(), 0, period, PRICE_CLOSE, shift); }
double GetATR(int period, int shift){ return iATR(Symbol(), 0, period, shift); }

double CalcLotsByRisk(double sl_pips){
   if(UseFixedLots) return FixedLots;
   if(sl_pips <= 0.0) return 0.0;
   double risk_amount = AccountBalance() * RiskPercent / 100.0;
   double tickval = MarketInfo(Symbol(), MODE_TICKVALUE);
   double pip_value_per_lot = tickval * PointsPerPip();
   if(pip_value_per_lot <= 0) return 0.0;
   double lots = risk_amount / (sl_pips * pip_value_per_lot);
   double minlot = MarketInfo(Symbol(), MODE_MINLOT);
   double lotstep = MarketInfo(Symbol(), MODE_LOTSTEP);
   double maxlot = MarketInfo(Symbol(), MODE_MAXLOT);
   lots = MathFloor(lots/lotstep)*lotstep;
   if(lots < minlot) lots = minlot;
   if(lots > maxlot) lots = maxlot;
   return NormalizeDouble(lots, 2);
}

void TrailAndBE(int ticket, double entry_price, double risk_pips){
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) return;
   double ema20 = GetEMA(EMA_Fast, 0);
   double sl = OrderStopLoss();
   double tp = OrderTakeProfit();
   double price = (OrderType()==OP_BUY) ? Bid : Ask;
   double profit_pips = (OrderType()==OP_BUY) ? (price - entry_price)/PipPoints() : (entry_price - price)/PipPoints();

   // BE化(+1R)
   if(profit_pips >= risk_pips && ((OrderType()==OP_BUY && sl < entry_price) || (OrderType()==OP_SELL && sl > entry_price))){
      double newSL = entry_price;
      if(OrderType()==OP_BUY) OrderModify(ticket, OrderOpenPrice(), newSL, tp, 0);
      else                    OrderModify(ticket, OrderOpenPrice(), newSL, tp, 0);
   }

   // EMA20トレーリング
   double newSLtrail;
   if(OrderType()==OP_BUY){
      newSLtrail = ema20 - 1.5*PipPoints(); // わずかに余裕
      if(newSLtrail > sl) OrderModify(ticket, OrderOpenPrice(), newSLtrail, tp, 0);
   }else if(OrderType()==OP_SELL){
      newSLtrail = ema20 + 1.5*PipPoints();
      if(newSLtrail < sl) OrderModify(ticket, OrderOpenPrice(), newSLtrail, tp, 0);
   }
}

void CloseAllByMagic(int magic){
   for(int i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic){
            if(OrderType()==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), Bid,  slippage:3);
            if(OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask,  slippage:3);
         }
      }
   }
}

int OnInit(){ return(INIT_SUCCEEDED); }
int OnDeinit(){ return(0); }

void OnTick(){
   if(TimeCurrent()==lastAction) return;
   lastAction = TimeCurrent();

   double ask = Ask, bid = Bid;
   double ema20 = GetEMA(EMA_Fast,0);
   double ema50 = GetEMA(EMA_Mid,0);
   double ema200= GetEMA(EMA_Slow,0);
   double rsi    = GetRSI(RSI_Period,0);
   double atr    = GetATR(ATR_Period,0);
   double sl_pips = (atr * ATR_SL_Mult)/PipPoints();
   double tp_pips = (atr * ATR_TP_Mult)/PipPoints();
   double pippts  = PipPoints();

   // 終盤は全決済
   if(FlatTimeCloseSoon()) CloseAllByMagic(MagicNumber);

   // 新規条件チェック
   if(!IsTradingHour() || !IsDayAllowed() || !SpreadOK()) return;
   if(CountOpenByMagic(MagicNumber)>0) return;

   // ラウンドナンバー回避
   if(NearRoundNumber(ask) || NearRoundNumber(bid)) return;

   // ロング条件
   bool uptrend   = (ema50 > ema200);
   bool dntrend   = (ema50 < ema200);
   double ema20_prev = GetEMA(EMA_Fast,1);
   double close_0 = iClose(Symbol(),0,0);
   double close_1 = iClose(Symbol(),0,1);

   bool longTrig  = (uptrend && close_1 < ema20_prev && close_0 > ema20 && rsi >= RSI_Long_Thresh);
   bool shortTrig = (dntrend && close_1 > ema20_prev && close_0 < ema20 && rsi <= RSI_Short_Thresh);

   int ticket;
   if(longTrig){
      double lots = CalcLotsByRisk(sl_pips);
      double sl = bid - sl_pips * pippts;
      double tp = bid + tp_pips * pippts;
      ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 3, sl, tp, "LSE Pullback Long", MagicNumber, 0, clrBlue);
      if(ticket>0) TrailAndBE(ticket, OrderOpenPrice(), sl_pips);
   }else if(shortTrig){
      double lots = CalcLotsByRisk(sl_pips);
      double sl = ask + sl_pips * pippts;
      double tp = ask - tp_pips * pippts;
      ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, sl, tp, "LSE Pullback Short", MagicNumber, 0, clrRed);
      if(ticket>0) TrailAndBE(ticket, OrderOpenPrice(), sl_pips);
   }

   // 既存ポジのトレーリング
   for(int i=0;i<OrdersTotal();i++){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber){
            double entry = OrderOpenPrice();
            TrailAndBE(OrderTicket(), entry, sl_pips);
         }
      }
   }
}
//+------------------------------------------------------------------+

インストール手順

(1)上記コードを LondonPullbackEA.mq4 として保存。(2)MT4で「ナビゲーター > Expert Advisors」に表示されたらチャートにドラッグ。(3)パラメータは既定のまま開始し、まずはデモ口座で2週間のフォワード観測を行います。(4)約定ログと損益のR分布を確認し、ATR係数・セッション時刻のみ軽微に調整します。

パラメータのガイドライン

・時間帯:サーバー時間に合わせ、ロンドン前後で8~18時(例)。夏時間はブローカーの案内に合わせて調整します。・足種:M5はエントリー頻度が高く、M15はノイズが少なめ。・RSI閾値:上55/下45から±2程度の微調整が妥当。・ATR係数:スプレッド広がりがちな環境ではTP係数をやや大きく。

口座開設と環境整備(概要)

国内FXはスプレッドが安定し、約定力・入出金の利便性に優れます。海外業者はレバレッジやボーナスが特徴ですが、各種リスク・規制を個別に確認してください。口座開設は、(1)本人確認・マイナンバー提出、(2)審査、(3)取引ツールのダウンロード、(4)入金、(5)デモで動作検証、という標準フローです。EA運用はVPS常時稼働が現実的です。

運用チェックリスト

1)サーバー時間と実際のロンドン時間の整合。2)最大スプレッドの実測更新。3)重要指標(雇用統計・政策金利)前後の挙動。4)00/50付近での約定回避が機能しているか。5)連敗時のドローダウン推移(口座残高に対する%)とロット調整。6)週次でのRマトリクス(勝率×損益比)。

拡張アイデア

①ニュースフィルターの自動化(外部CSV読込)。②ボラ急伸時のブレークアウトモード切替。③Multi-Symbol化(EURUSD/GBPUSDへ展開)。④トレード日記の自動生成(CSV出力)。⑤切り番テーブルを25pipsグリッドに拡張。

限界と期待値の読み方

本戦略はトレンドが明確な日に強く、膠着・逆行日にはドローダウンが発生します。特定年のボラティリティ・政策相場では一時的に優位性が低下します。ドローダウンは「最大想定の2倍」を資金管理の安全域として、長期でのR合計で判断するのが実務的です。

まとめ

ロンドン時間×USD/JPYの押し目順張りは、シンプルなロジックで再現性が高いため、システムトレード入門として適しています。EAコード・検証手順・運用フローを揃えました。まずはデモで動かし、数量管理と時間帯の精度を高めてから少額でフェーズインしてください。

コメント

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