XAUJPY合成乖離で稼ぐ:初心者向けクロスアセットEA(MQL4完全コード付き)

FX

結論:ゴールド(XAUUSD)とドル円(USDJPY)から作る「合成XAUJPY=XAUUSD×USDJPY」の乖離(Zスコア)を使えば、裁定的一貫性のズレを低リスクで狙える。この記事では理論→設計→実装→検証→運用までを一気通貫で示し、MQL4の完全EAコードも提供する。

1. 戦略のアイデアと「なぜ儲かるのか」

ゴールドを円建てで評価した価格はおおむね XAUUSD × USDJPY で近似できる(ブローカーにより建値や小数点は異なる)。
市場は常に完全合理的ではないため、短期的にはこの合成値と実需フロー・流動性の歪みが生じる。たとえば、ドル円だけが急伸してもゴールド側の板が薄い時間帯は遅れて反応し、一時的に「円建てゴールドが割高(または割安)」になる。

本戦略は、合成XAUJPYのZスコア(標準化乖離)が一定以上に拡大したとき、方向に応じてXAUUSDを売買する。さらにEMA50/200のトレンドフィルタで「流れに逆らわない」条件を加え、無駄な逆張りを避ける。

2. 数式:Zスコアと判定ロジック

時刻 t の合成値を St = XAUUSDt × USDJPYt とする。直近 N 本の平均と分散を μ, σ とすると、

zt = (St - μ) / σ

売買は次の通り:

  • z ≤ -Zenter かつ 上昇トレンド(EMA50>EMA200 & 終値>EMA50) ⇒ BUY
  • z ≥ Zenter かつ 下降トレンド(EMA50<EMA200 & 終値<EMA50) ⇒ SELL
  • |z| が Zexit 未満に縮小 ⇒ 手仕舞い

ポイントは、トレンド方向と乖離方向を一致させること。上昇トレンドで割安(z<0)だけ買い、下降トレンドで割高(z>0)だけ売る。これでトレンドに逆らう取引を大幅に削減できる。

3. 実装(MQL4 EA)

以下をMT4の「MQL4/Experts」へ保存し、MT4を再起動。XAUUSDのチャート(15分足推奨)にEAを適用する。USDJPYを必ず「気配値表示」に表示して、価格データが取得できる状態にしておく。

//+------------------------------------------------------------------+
//| XAUJPY Synthetic Divergence EA                                  |
//| Author: K's Assistant                                            |
//| Description: Trade XAUUSD using Z-score of (XAUUSD*USDJPY).     |
//+------------------------------------------------------------------+
#property strict

input string  InpSymbolGold   = "XAUUSD";    // ゴールド銘柄名(ブローカー表記に合わせる)
input string  InpSymbolFX     = "USDJPY";    // 為替銘柄名
input ENUM_TIMEFRAMES InpTF   = PERIOD_M15;  // シグナル判定足
input int     InpLookback     = 120;         // Zスコア計算期間(バー数)
input double  InpZEnter       = 1.5;         // エントリー閾値(絶対値)
input double  InpZExit        = 0.2;         // エグジット閾値(絶対値以下で手仕舞い)
input double  InpLots         = 0.10;        // 取引ロット
input double  InpSL_points    = 1500;        // ストップロス(ポイント)
input double  InpTP_points    = 3000;        // テイクプロフィット(ポイント)
input int     InpMaxSpread    = 200;         // 許容スプレッド(ポイント)
input int     InpMagic        = 88051;       // マジックナンバー
input int     InpStartHour    = 7;           // 取引開始(サーバー時間)
input int     InpEndHour      = 23;          // 取引終了(サーバー時間)
input bool    InpOnePosition  = true;        // 同時に1ポジのみ
input bool    InpUseEMAFilter = true;        // EMAトレンドフィルタを使う(順張り)

datetime lastBarTime = 0;

bool IsNewBar(ENUM_TIMEFRAMES tf) {
   datetime t = iTime(InpSymbolGold, tf, 0);
   if(t != lastBarTime) { lastBarTime = t; return true; }
   return false;
}

double GetEMA(string sym, ENUM_TIMEFRAMES tf, int period, int shift) {
   return iMA(sym, tf, period, 0, MODE_EMA, PRICE_CLOSE, shift);
}

double Synthetic(int shift) {
   double gold = iClose(InpSymbolGold, InpTF, shift);
   double fx   = iClose(InpSymbolFX,   InpTF, shift);
   if(gold==0 || fx==0) return 0;
   return gold * fx; // 合成XAUJPY(概算)
}

bool ZScore(double &z, double &mean, double &sd) {
   if(InpLookback < 30) return false;
   int n = InpLookback;
   double sum=0, sum2=0;
   for(int i=1; i<=n; i++) {
      double v = Synthetic(i);
      if(v==0) return false;
      sum += v;
      sum2 += v*v;
   }
   mean = sum / n;
   double var = sum2/n - mean*mean;
   sd = (var>0 ? MathSqrt(var) : 0);
   if(sd==0) return false;
   double latest = Synthetic(1);
   z = (latest - mean) / sd;
   return true;
}

int CountPositions() {
   int cnt=0;
   for(int i=OrdersTotal()-1; i>=0; i--) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol()==InpSymbolGold && OrderMagicNumber()==InpMagic) cnt++;
   }
   return cnt;
}

void CloseAllBySignal() {
   for(int i=OrdersTotal()-1; i>=0; i--) {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderSymbol()!=InpSymbolGold || OrderMagicNumber()!=InpMagic) continue;
      int type = OrderType();
      if(type==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), Bid, 5);
      if(type==OP_SELL) OrderClose(OrderTicket(), OrderLots(), Ask, 5);
   }
}

void OnTick() {
   if(Symbol()!=InpSymbolGold) return; // チャートはゴールドに貼る
   if(Hour() < InpStartHour || Hour() >= InpEndHour) return;

   if(MarketInfo(InpSymbolGold, MODE_SPREAD) > InpMaxSpread) return;
   if(!IsNewBar(InpTF)) return;

   double z, mean, sd;
   if(!ZScore(z, mean, sd)) return;

   // トレンドフィルタ(順張りで入る)
   bool trendUp = true, trendDn = true;
   if(InpUseEMAFilter) {
      double ema50  = GetEMA(InpSymbolGold, InpTF, 50, 1);
      double ema200 = GetEMA(InpSymbolGold, InpTF, 200, 1);
      double close1 = iClose(InpSymbolGold, InpTF, 1);
      trendUp = (close1>ema50 && ema50>ema200);
      trendDn = (close1<ema50 && ema50<ema200);
   }

   int pos = CountPositions();

   // エグジット:Zが閾値内に戻ったら手仕舞い
   if(pos>0 && MathAbs(z) <= InpZExit) {
      CloseAllBySignal();
      return;
   }

   if(InpOnePosition && pos>0) return;

   // エントリー
   double sl=0, tp=0;
   if(z <= -InpZEnter && trendUp) {
      // Underpriced → BUY
      sl = Bid - InpSL_points * Point;
      tp = Bid + InpTP_points * Point;
      OrderSend(InpSymbolGold, OP_BUY, InpLots, Ask, 5, sl, tp, "BUY z<0", InpMagic, 0, clrNONE);
   } else if(z >= InpZEnter && trendDn) {
      // Overpriced → SELL
      sl = Ask + InpSL_points * Point;
      tp = Ask - InpTP_points * Point;
      OrderSend(InpSymbolGold, OP_SELL, InpLots, Bid, 5, sl, tp, "SELL z>0", InpMagic, 0, clrNONE);
   }
}
//+------------------------------------------------------------------+

4. 推奨初期パラメータ

  • 時間足:M15(スキャルに寄りすぎず、遅すぎない)
  • Lookback(Z期間):120(約2.5営業日相当)
  • Zenter:1.5、Zexit:0.2
  • EMAフィルタ:オン(EMA50/200)
  • 取引時間:サーバー時刻 07:00〜23:00(極端な薄商いを回避)
  • SL/TP:1,500/3,000ポイント(ブローカーの桁に依存。XAUUSDのPointに注意)
  • MaxSpread:200ポイント(約2.0pips相当のブローカー換算例)

ブローカーの桁・ポイント仕様はまちまちなので、デモ口座で必ず値の整合を確認すること。

5. バックテスト手順(MT4)

  1. MT4「ツール」→「ヒストリーセンター」でXAUUSD/USDJPYのデータをM1までダウンロード。
  2. ストラテジーテスターでEAを選び、Every tick based on real ticks(可能なら)でテスト。
  3. 期間は直近2〜3年から開始。スプレッドは固定でなくCurrent推奨。
  4. 最初は既定パラメータで損益曲線・DD・PFを確認。次にZ期間やZ閾値を±20%でロバスト性チェック。
  5. オーバーフィッティング防止のため、期間分割(Walk-Forward)で最適化→前方検証を行う。

合格基準の目安:PF>1.2、最大DD<資金の15%、月次ベースの勝率55%超、パラメータを多少ズラしても性能が崩れないこと。

6. 実運用:資金管理・リスクの現実解

  • 1トレードの許容損失=口座残高の0.5〜1.0%。ロットはここから逆算。
  • 同時ポジション1(EA設定)で連敗の連鎖を抑える。
  • 相場急変(米雇用統計、FOMC、CPI、要人発言)は一時停止。イベントカレンダーを習慣化。
  • 週末はポジションを持ち越さない(週末ギャップ対応)。
  • スリッページとリクオートの多いブローカーは排除。約定品質は最優先のコスト。

7. 勝ちやすい時間帯と流動性

経験的に、東京後場〜ロンドン序盤はUSDJPYのフローが活発になりやすく、合成値の歪みが出やすい一方、NY序盤は金の板が厚く乖離が縮小しやすい。EAの取引時間を調整して自分のブローカーで最適な時間帯を見つける。

8. 失敗パターンと対策

  • スプレッド拡大時の突撃:MaxSpreadで機械的に回避。薄商い(メンテ・祝日)は取引停止。
  • トレンド転換直後の「逆の順張り」:EMAがデッドクロス/ゴールデンクロスした直後はダマシが多い。Z閾値を一段厳しく。
  • 相関崩壊イベント:地政学リスク等で金だけ一方向に走る場合、Zは高止まりする。SLを必ず置く。
  • ヒストリーの欠損:USDJPYのデータ欠落でZが0になるとシグナル不発。気配値表示に常時追加。

9. より上級の拡張案

  1. ヘッジ版(上級):XAUUSDとUSDJPYをデルタ中立比率で同時発注。裁定性は高まるが、実装とコストが複雑。
  2. ボラ調整ロット:ATRでロットを可変化。平均的に損益のブレを均す。
  3. レジーム判定:HMMやクラスタリングで「トレンド/レンジ」状態を推定し、Z閾値を自動切替。
  4. 多時間足合成:M5でエントリー、H1のZでフィルタ、など。

10. 導入チェックリスト

  • ブローカーのXAUUSDのPointと小数桁を把握済み
  • USDJPYを気配値表示へ追加済み
  • デモで1週間連続稼働し、意図通りの売買とログを確認
  • 本番は最小ロットから開始、2週間は監視を強化

「難しいことはしない。勝ちやすい歪みだけを、安全なサイズで、淡々と繰り返す」——これが継続利益の必須条件だ。

コメント

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