また出たな。AIが書いた「完璧に見えるゴミ」が。

今回の犠牲者は NYTrendScalper_v9。名前だけは立派だが、中身はどこにでもあるFX攻略本をそのままコードに書き写しただけの、救いようのない「教科書信者」のロジックだ。

このAIが何をしようとしたか。推測するまでもない。 「NY時間の強いトレンド相場で、EMAのパーフェクトオーダーを確認し、押し目・戻り目(バリューゾーン)まで待ってから、モメンタムが回復した瞬間にエントリーする」。

……ふん。笑わせるな。 そんなものは、10年前のネット掲示板に転がっていた「必勝法」だ。

破綻の理由:なぜこのロジックは「ゴミ」なのか

バックテストの結果を見てみろ。PF 0.94。 つまり、手数料とスプレッドを考慮せずとも、期待値がマイナスだということだ。

特筆すべきは、最大ドローダウン 0.1% という数値だ。初心者はこれを「低リスクで安全」と勘違いするだろうが、プロから見れば「臆病すぎてチャンスを逃し、たまにエントリーしては微損を繰り返した」だけの、死んでいるコードであることが一目でわかる。

このロジックが現実の相場で通用しない理由は、主に3つだ。

1. インジケーターの「遅行性」の積み上げ

EMA20 > 50 > 200というパーフェクトオーダーを確認し、さらにADXが25を超えるまで待つ。いいか、5分足でここまで条件を揃えたときには、トレンドの美味しい部分はすでに終わっている。 AIは「確実性」を求めてフィルターを重ねたが、結果として「トレンドの終焉」でエントリーする装置を作り上げたわけだ。

2. 「バリューゾーン」という幻想

EMA20から50の間を「反発ポイント」と定義しているが、相場にそんな固定された境界線があると思うな。 大口のトレーダーは、まさにその「教科書通りの反発ポイント」に溜まったストップロスを狩りに来る。このEAが「買い」を入れた瞬間、それは単なる「流動性の提供」となり、ヒゲで刈り取られる運命にある。

3. リスクリワードの不整合

TP 150pipsに対し、SL 45pips。一見、リスクリワード比はいい。だが、5分足のスキャルピングで150pipsを狙うなど、相場のボラティリティを完全に無視した設定だ。トレーリングストップを導入しているが、そもそもエントリーポイントが遅すぎるため、建値に戻されるか、微損で切られるかの繰り返しになる。

結論。インジケーターを組み合わせれば「正解」に辿り着けると思うな。相場は数式ではなく、人間の心理と資金のぶつかり合いだ。


敗北の記録(Pythonコード)

AIが自信満々に書き上げた、絶望のコードがこちらだ。

[SYSTEM WARNING] 本記事のEAは実運用に耐えません

大切な資金を運用するなら、厳しいリアルフォワードテストをクリアしたプロ開発のEAを利用することを強く推奨します。
実際にリアルタイムで利益を出し続けている本物のデータを確認してください。

👉 プロが実稼働で証明済みの本物のEA(Pips_miner_EA)はこちら【超多頻度トレードによる高収益を狙うEA】 | GogoJungle
from strategies.base import BaseStrategy
import pandas_ta as ta
import pandas as pd
import numpy as np

class NYTrendScalper(BaseStrategy):
    """
    NY Trend Scalper v9:
    バリューゾーン・リバウンド戦略。
    EMA20-50のゾーン反発とADX強トレンドを組み合わせ、低DDを維持しつつPFの最大化を追求する。
    """
    def __init__(self):
        # DD 0.2%という余裕を最大限に活用し、リスクリワード比を向上させる。
        # TPを大幅に伸ばし、トレーリングストップでトレンドの終焉まで追随する。
        super().__init__(
            name="NYTrendScalper_v9", 
            default_tp_pips=150.0, 
            default_sl_pips=45.0, 
            enable_trailing_stop=True, 
            trail_start_pips=30.0
        )
        self.base_timeframe = "5m"
        self.vision_timeframes = ["5m", "15m", "1h"]

    def calculate_indicators(self, df):
        # --- 5分足 (Base Timeframe) 指標 ---
        # ADX: トレンド強度の判定 (14)
        adx_df = df.ta.adx(length=14)
        if adx_df is not None:
            df['ADX'] = adx_df.iloc[:, 0]
        
        # ATR: ボラティリティ (14)
        df['ATR'] = df.ta.atr(length=14)
        df['ATR_MA'] = df['ATR'].rolling(window=100).mean()
        
        # MACD: モメンタム (12, 26, 9)
        macd_df = df.ta.macd(fast=12, slow=26, signal=9)
        if macd_df is not None:
            df['MACD_hist'] = macd_df.iloc[:, 2]
        
        # RSI: 強弱判定 (14)
        df['RSI'] = df.ta.rsi(length=14)
        
        # --- Trend Filters (MTF) ---
        # EMA 20: 短期トレンド / EMA 50: 中期トレンド / EMA 200: 長期トレンド
        df['EMA_20'] = df.ta.ema(length=20)
        df['EMA_50'] = df.ta.ema(length=50)
        df['EMA_200'] = df.ta.ema(length=200)

        return df

    def generate_signal(self, df):
        if len(df) < 200:
            return None

        curr = df.iloc[-1]
        prev = df.iloc[-2]
        
        # 必須カラムチェック
        required_cols = ['ADX', 'ATR', 'MACD_hist', 'RSI', 'EMA_20', 'EMA_50', 'EMA_200', 'ATR_MA']
        if not all(col in df.columns for col in required_cols):
            return None

        # 【エントリー時間帯の限定】
        # NY市場のメイントレンド時間帯 (21:00〜01:00 JST)
        current_hour = df.index[-1].hour
        if not (21 <= current_hour <= 23 or 0 <= current_hour <= 1):
            return None

        # 【相場環境フィルター】
        # 1. トレンド強度の厳格化: ADX > 25 (強いトレンドのみを抽出)
        if curr['ADX'] < 25:
            return None
            
        # 2. ボラティリティ: ATRが平均的に安定していること
        if curr['ATR'] < curr['ATR_MA'] * 0.6:
            return None

        # 【MTFトレンド判定: パーフェクトオーダーの確認】
        # 強気環境: 価格 > EMA 20 > EMA 50 > EMA 200
        is_bullish_env = (curr['Close'] > curr['EMA_20']) and (curr['EMA_20'] > curr['EMA_50']) and (curr['EMA_50'] > curr['EMA_200'])
        # 弱気環境: 価格 < EMA 20 < EMA 50 < EMA 200
        is_bearish_env = (curr['Close'] < curr['EMA_20']) and (curr['EMA_20'] < curr['EMA_50']) and (curr['EMA_50'] < curr['EMA_200'])

        # 【エントリートリガー: バリューゾーンからの反発】
        # 買いシグナル:
        if is_bullish_env:
            # 1. バリューゾーン判定: 直近の安値がEMA 20〜EMA 50の間に位置していたか
            in_value_zone = (prev['Low'] <= curr['EMA_20'] * 1.001) and (prev['Low'] >= curr['EMA_50'] * 0.999)
            # 2. プライスアクション: 直近高値を更新する強い陽線
            is_strong_bull = (curr['Close'] > curr['Open']) and (curr['Close'] > prev['High'])
            # 3. モメンタム: RSIが50以上、かつMACDヒストグラムが上昇
            momentum_ok = (curr['RSI'] > 50) and (curr['MACD_hist'] > prev['MACD_hist'])
            
            if in_value_zone and is_strong_bull and momentum_ok:
                return 'BUY'

        # 売りシグナル:
        if is_bearish_env:
            # 1. バリューゾーン判定: 直近の高値がEMA 20〜EMA 50の間に位置していたか
            in_value_zone = (prev['High'] >= curr['EMA_20'] * 0.999) and (prev['High'] <= curr['EMA_50'] * 1.001)
            # 2. プライスアクション: 直近安値を更新する強い陰線
            is_strong_bear = (curr['Close'] < curr['Open']) and (curr['Close'] < prev['Low'])
            # 3. モメンタム: RSIが50以下、かつMACDヒストグラムが下降
            momentum_ok = (curr['RSI'] < 50) and (curr['MACD_hist'] < prev['MACD_hist'])
            
            if in_value_zone and is_strong_bear and momentum_ok:
                return 'SELL'

        return None

オマケ:反面教師用 MQL5コード

「この程度のロジックで本当に負けるのか?」と、まだ夢を見ている物好きな方へ。MT5でその絶望を体験するためのコードを書いておいた。

//+------------------------------------------------------------------+
//|                                          NYTrendScalper_Fail.mq5 |
//|                                  Copyright 2026, Legendary Trader|
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Legendary Trader"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

// Inputs
input int      InpEMA_Short  = 20;
input int      InpEMA_Medium = 50;
input int      InpEMA_Long   = 200;
input int      InpADX_Period = 14;
input int      InpRSI_Period = 14;
input double   InpTP_Pips    = 1500; // Points
input double   InpSL_Pips    = 450;  // Points

// Handles
int hEMA20, hEMA50, hEMA200, hADX, hRSI, hMACD;

int OnInit() {
    hEMA20  = iMA(_Symbol, _Period, InpEMA_Short, 0, MODE_EMA, PRICE_CLOSE);
    hEMA50  = iMA(_Symbol, _Period, InpEMA_Medium, 0, MODE_EMA, PRICE_CLOSE);
    hEMA200 = iMA(_Symbol, _Period, InpEMA_Long, 0, MODE_EMA, PRICE_CLOSE);
    hADX    = iADX(_Symbol, _Period, InpADX_Period);
    hRSI    = iRSI(_Symbol, _Period, InpRSI_Period, PRICE_CLOSE);
    hMACD   = iMACD(_Symbol, _Period, 12, 26, 9, PRICE_CLOSE);
    return(INIT_SUCCEEDED);
}

void OnTick() {
    MqlDateTime dt;
    TimeCurrent(dt);
    if(!(dt.hour >= 21 || dt.hour <= 1)) return;

    double ema20[], ema50[], ema200[], adx[], rsi[], macd_main[], macd_sig[];
    CopyBuffer(hEMA20, 0, 0, 2, ema20);
    CopyBuffer(hEMA50, 0, 0, 2, ema50);
    CopyBuffer(hEMA200, 0, 0, 2, ema200);
    CopyBuffer(hADX, 0, 0, 2, adx);
    CopyBuffer(hRSI, 0, 0, 2, rsi);
    CopyBuffer(hMACD, 0, 0, 2, macd_main);
    CopyBuffer(hMACD, 1, 0, 2, macd_sig);

    MqlRates rates[];
    CopyRates(_Symbol, _Period, 0, 2, rates);

    bool bullish_env = (rates[1].close > ema20[1]) && (ema20[1] > ema50[1]) && (ema50[1] > ema200[1]);
    bool bearish_env = (rates[1].close < ema20[1]) && (ema20[1] < ema50[1]) && (ema50[1] < ema200[1]);

    if(adx[1] < 25) return;

    if(bullish_env) {
        bool in_zone = (rates[0].low <= ema20[1] * 1.001) && (rates[0].low >= ema50[1] * 0.999);
        bool strong_bull = (rates[1].close > rates[1].open) && (rates[1].close > rates[0].high);
        bool momentum = (rsi[1] > 50) && ((macd_main[1]-macd_sig[1]) > (macd_main[0]-macd_sig[0]));
        if(in_zone && strong_bull && momentum) {
            // Execute BUY
        }
    }
    if(bearish_env) {
        bool in_zone = (rates[0].high >= ema20[1] * 0.999) && (rates[0].high <= ema50[1] * 1.001);
        bool strong_bear = (rates[1].close < rates[1].open) && (rates[1].close < rates[0].low);
        bool momentum = (rsi[1] < 50) && ((macd_main[1]-macd_sig[1]) < (macd_main[0]-macd_sig[0]));
        if(in_zone && strong_bear && momentum) {
            // Execute SELL
        }
    }
}