//+------------------------------------------------------------------+ //| Urban Flux Research — 研究アーカイブ公開版(無償) | //| https://apex-predator-x.com/ | //| | //| 公開日 : 2026-08-22 | //| 配布区分 : 研究アーカイブ / 検証用ソースコード | //| 対応 : MetaTrader 5 (MQL5) | //| ライセンス : 検証・学習目的での閲覧・改変・実行を許諾します。 | //| 再配布する場合は本ヘッダを削除しないでください。 | //| | //| ── 免責 ────────────────────────────────────────────────────── | //| 本コードは研究記録の公開であり、投資助言ではありません。 | //| 過去の検証結果は将来の利益を一切保証しません。 | //| 実口座での使用により生じたいかなる損失についても、 | //| 当方は責任を負いません。必ずデモ口座で検証してください。 | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| ⚠⚠ 重要警告:本EAは実運用を推奨しません ⚠⚠ | //| | //| 本EAは絶対時刻(TimeGMT)を基準にエントリーします。 | //| しかし当社のその後の検証(TZ-2026-001 / RA-2026-002)により、 | //| 研究に用いた生データはブローカーサーバー時刻であり、 | //| 観測されたエッジの真の位置は | //| 「週次 market reopen の次の1時間」 | //| であることが判明しました。ライブで参照される真UTC01:00は | //| 別の時間帯であり、そこでの期待値は【負】と判定されています | //| (Trial Ledger T-0005)。 | //| | //| さらに、実測コスト控除後に生存する可能性があるのは USDJPY のみ | //| です。GBPJPY は再開直後のスプレッドが広く | //| (p50 3.2pip / p95 6.8pip)、悲観コストで期待値が負になります。 | //| EURJPY も同様に脆弱です。 | //| 本EAの対象ペアは、この「負」と判定されたペアを含みます。 | //| | //| → 本コードは「当時どう実装したか」を示す研究アーカイブです。 | //| 時刻基準を修正した実装例は TokyoMorningEA_v1.04.mq5 を | //| 参照してください(週次reopenアンカー・タイムゾーン非依存)。 | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| GENOME01_MonTue_GMT01_GBPJPY.mq5 | //| GENOME-01 — 月曜+火曜 GMT01:00 GBPJPY キャリー再開 LONG | //| | //| Recommended Symbol: GBPJPY | //| Entry : 月曜または火曜 GMT 01:00〜01:59 LONG (成行) | //| Exit : GMT 02:00 成行クローズ | //| Filter: なし(曜日+時刻のみ) | //| | //| Python IS avg=+6.02pip PF=2.683 Sharpe=3.34 N=369 (103/yr) | //| Python Val avg=+7.85pip PF=3.164 Sharpe=3.91 N=146 (104/yr) | //| Null Model: p=0.000 (2000回中0件がGENOME-01超え) | //| WFA 3/3: PF=8.02/2.99/2.29 ✅ | //| | //| ⚠️ RISK DISCLOSURE: | //| 2020 COVID 期に最悪年 Sharpe=1.32 / MDD=319pip を記録。 | //| COVID 規模の週初キャリー崩壊では同様の成績低下が起こりうる。 | //| GMT01:00 エントリーは事前登録条件のまま(GMT00:30 は未採用)。| //| tpy ≈ 104 (高頻度Track: PF≥1.3/avg≥3pip/Sharpe≥1.5) | //| | //| Gate B 目標: MT5 PF ≥ Python IS PF × 0.6 = 1.61 | //| | //| Components: R086 (MON) + R122 (TUE) | 相関 r=0.015 | //| v1.00: 初版 Gate B 早期テスト用 | //| v1.10: 複利モード追加 (FIXED / AUTO リスク比例ロット) | //+------------------------------------------------------------------+ #property copyright "Urban Flux Research — GENOME-01" #property link "https://apex-predator-x.com/" #property version "1.10" #property description "[RESEARCH ARCHIVE / NOT FOR LIVE] Mon+Tue GMT01 GBPJPY LONG | No filter | v1.10 compounding" #include #include #define MAGIC_NUM 220101 // GENOME-01 固有マジックナンバー #define TIMER_MS 10000 // 10秒ごとチェック #define MAX_RETRY 10 //============================================================ // ロットモード列挙 //============================================================ enum ENUM_LOT_MODE { LOT_FIXED = 0, // 固定ロット (InpLots をそのまま使用) LOT_AUTO = 1, // 複利: 口座残高 × リスク% ÷ (想定損失pip × pip価値) }; //============================================================ // 入力パラメータ //============================================================ input group "=== エントリー ===" input int InpRetryMaxMin = 10; // スプレッド待機上限 (分) input group "=== スプレッド ===" input double InpMaxSpreadPip = 5.0; // 最大スプレッド (pip) input group "=== ロット ===" input ENUM_LOT_MODE InpLotMode = LOT_FIXED; // ロットモード input double InpLots = 0.10; // 固定ロット (LOT_FIXED 時に使用) input double InpRiskPct = 1.0; // リスク % (LOT_AUTO 時: 口座残高の何%) input double InpRiskPips = 20.0; // 想定最大損失 pip (LOT_AUTO のロット算出基準) input double InpMaxLots = 10.0; // 最大ロット上限 (LOT_AUTO 時の安全弁) input group "=== ログ ===" input bool InpPrintLog = true; //============================================================ // グローバル変数 //============================================================ CTrade trade; CPositionInfo posInfo; bool g_entry_done = false; bool g_exit_done = false; bool g_spread_skip = false; datetime g_last_day = 0; int g_exit_retry = 0; //============================================================ // ユーティリティ //============================================================ // [M-Fix 3] digits ベース全シンボル対応 PipSize double PipSize() { int digits = (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS); double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); return (digits == 3 || digits == 5) ? point * 10.0 : point; } double GetSpreadPip() { return (SymbolInfoDouble(Symbol(), SYMBOL_ASK) - SymbolInfoDouble(Symbol(), SYMBOL_BID)) / PipSize(); } // 1pip あたりの口座通貨換算額 (1ロット) double PipValuePerLot() { double tick_val = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); double tick_size = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE); if(tick_size <= 0.0) return 0.0; return tick_val * (PipSize() / tick_size); } // 使用ロット数を決定する (LOT_AUTO 時は複利計算) double CalcLots() { if(InpLotMode == LOT_FIXED) return InpLots; // LOT_AUTO: equity × risk% ÷ (想定損失pip × pip価値/lot) double equity = AccountInfoDouble(ACCOUNT_EQUITY); double pip_val = PipValuePerLot(); if(pip_val <= 0.0) { if(InpPrintLog) Print("GENOME01 CalcLots: pip_val=0、固定ロットにフォールバック"); return InpLots; } double risk_money = equity * InpRiskPct / 100.0; double raw_lots = risk_money / (InpRiskPips * pip_val); // ブローカーのロット制約に丸める double lot_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP); double lot_min = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN); double lot_max = MathMin(SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX), InpMaxLots); double lots = MathFloor(raw_lots / lot_step) * lot_step; lots = MathMax(lots, lot_min); lots = MathMin(lots, lot_max); if(InpPrintLog) PrintFormat("GENOME01 CalcLots(AUTO) | equity=%.2f risk=%.1f%% " "risk_money=%.2f pip_val=%.4f raw=%.3f → lots=%.2f", equity, InpRiskPct, risk_money, pip_val, raw_lots, lots); return lots; } ENUM_ORDER_TYPE_FILLING DetectFilling() { long m = SymbolInfoInteger(Symbol(), SYMBOL_FILLING_MODE); if((m & SYMBOL_FILLING_IOC) != 0) return ORDER_FILLING_IOC; if((m & SYMBOL_FILLING_FOK) != 0) return ORDER_FILLING_FOK; return ORDER_FILLING_RETURN; } void GetGmt(int &h, int &wd) { MqlDateTime dt; TimeToStruct(TimeGMT(), dt); h = dt.hour; wd = dt.day_of_week; } //============================================================ // 日次リセット — ブローカー時刻の日付変化でリセット //============================================================ void DailyReset() { datetime today = (datetime)(TimeCurrent() / 86400 * 86400); if(today == g_last_day) return; g_last_day = today; g_entry_done = false; g_exit_done = false; g_spread_skip = false; g_exit_retry = 0; if(InpPrintLog) PrintFormat("GENOME01 日次リセット | %s", TimeToString(today, TIME_DATE)); } //============================================================ // ポジション管理 //============================================================ bool HasPosition() { for(int i = PositionsTotal() - 1; i >= 0; i--) if(posInfo.SelectByIndex(i)) if(posInfo.Symbol() == Symbol() && posInfo.Magic() == MAGIC_NUM) return true; return false; } bool CloseAllPos() { bool ok = true; for(int i = PositionsTotal() - 1; i >= 0; i--) if(posInfo.SelectByIndex(i)) if(posInfo.Symbol() == Symbol() && posInfo.Magic() == MAGIC_NUM) if(!trade.PositionClose(posInfo.Ticket())) { PrintFormat("GENOME01 ClosePos失敗 ticket=%d err=%d", posInfo.Ticket(), GetLastError()); ok = false; } return ok; } //============================================================ // メイン処理 //============================================================ void ProcessLogic() { DailyReset(); int h, wd; GetGmt(h, wd); // ─── クローズ: GMT02 ─── if(!g_exit_done && h == 2 && HasPosition()) { if(CloseAllPos()) { g_exit_done = true; g_exit_retry = 0; if(InpPrintLog) PrintFormat("GENOME01 EXIT完了 | GMT%02d | %s", h, TimeToString(TimeGMT(), TIME_DATE | TIME_MINUTES)); } else { g_exit_retry++; if(g_exit_retry >= MAX_RETRY) g_exit_done = true; } return; } // ─── エントリー判定 ─── if(g_entry_done || g_spread_skip) return; // 月曜(1) または 火曜(2) の GMT01 if(wd != 1 && wd != 2) return; if(h != 1) return; MqlDateTime mdt; TimeToStruct(TimeGMT(), mdt); if(mdt.min > InpRetryMaxMin) return; // スプレッドチェック(GMT01はロンドン前: 実スプレッド低め) double spread = GetSpreadPip(); if(spread > InpMaxSpreadPip) { if(mdt.min <= InpRetryMaxMin) { if(InpPrintLog) PrintFormat("GENOME01 スプレッド待機 | %.2fpip > %.1fpip | min=%d", spread, InpMaxSpreadPip, mdt.min); return; } if(InpPrintLog) PrintFormat("GENOME01 スプレッドスキップ(上限超) | %.2fpip", spread); g_entry_done = true; g_spread_skip = true; return; } // ロット決定(固定 or 複利) double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double lots = CalcLots(); // [M-Fix 4] 証拠金プリチェック($1残高バリデーター対策) double margin_req = 0.0; if(OrderCalcMargin(ORDER_TYPE_BUY, Symbol(), lots, ask, margin_req) && margin_req > AccountInfoDouble(ACCOUNT_FREEMARGIN)) { g_entry_done = true; if(InpPrintLog) PrintFormat("GENOME01 SKIP(no margin) | Need=%.2f Free=%.2f", margin_req, AccountInfoDouble(ACCOUNT_FREEMARGIN)); return; } // LONG エントリー trade.SetExpertMagicNumber(MAGIC_NUM); trade.SetDeviationInPoints(50); trade.SetTypeFilling(DetectFilling()); string day_tag = (wd == 1) ? "MON(R086)" : "TUE(R122)"; string mode_tag = (InpLotMode == LOT_AUTO) ? "AUTO" : "FIXED"; bool ok = trade.Buy(lots, Symbol(), ask, 0.0, 0.0, StringFormat("GENOME01_%s_GMT01", day_tag)); if(ok) { g_entry_done = true; if(InpPrintLog) PrintFormat("GENOME01 ENTER LONG | %s | %s | GMT%02d | " "Ask=%.3f Lot=%.2f(%s) Spread=%.2fpip", day_tag, TimeToString(TimeGMT(), TIME_DATE | TIME_MINUTES), h, ask, lots, mode_tag, spread); } else PrintFormat("GENOME01 エントリー失敗 | err=%d %s", GetLastError(), trade.ResultComment()); } //============================================================ // 初期化 — [M-Fix 1] どのシンボルでも INIT_SUCCEEDED を返す //============================================================ int OnInit() { // [M-Fix 2] シンボルガードなし。どのシンボルでも起動可能。 // 推奨シンボルはヘッダーとログに明記するのみ。 if(InpLotMode == LOT_FIXED && InpLots <= 0.0) return INIT_PARAMETERS_INCORRECT; if(InpLotMode == LOT_AUTO && (InpRiskPct <= 0.0 || InpRiskPips <= 0.0 || InpMaxLots <= 0.0)) return INIT_PARAMETERS_INCORRECT; trade.SetExpertMagicNumber(MAGIC_NUM); trade.SetDeviationInPoints(50); trade.SetTypeFilling(DetectFilling()); EventSetMillisecondTimer(TIMER_MS); if(InpPrintLog) { if(InpLotMode == LOT_FIXED) PrintFormat("GENOME01 v1.10 初期化 | Symbol=%s | " "Mon+Tue GMT01→02 LONG | MaxSpread=%.1fpip | " "LotMode=FIXED Lots=%.2f | " "Python IS PF=2.683 | GateB目標PF≥1.61", Symbol(), InpMaxSpreadPip, InpLots); else PrintFormat("GENOME01 v1.10 初期化 | Symbol=%s | " "Mon+Tue GMT01→02 LONG | MaxSpread=%.1fpip | " "LotMode=AUTO Risk=%.1f%% / RiskPips=%.1f / MaxLots=%.2f | " "Python IS PF=2.683 | ⚠️ 2020 COVID MDD=319pip", Symbol(), InpMaxSpreadPip, InpRiskPct, InpRiskPips, InpMaxLots); } return INIT_SUCCEEDED; } void OnDeinit(const int reason) { EventKillTimer(); } void OnTick() { ProcessLogic(); } void OnTimer() { ProcessLogic(); }