😱『損切りできない病』から生まれた!ナンピンマーチンEA開発・完全攻略ガイド

『もう少し待てば戻るはず...』そんな願いから生まれたナンピンマーチン戦略。危険だけど魅力的なこの手法をMT5のEAで実装する方法を、リスク管理も含めて魂込めて解説します!

公開日: 2025-08-31
更新日: 2025-08-31

😱『損切りできない病』から生まれた!ナンピンマーチンEA開発・完全攻略ガイド

こんにちは!今日は「含み損が膨らんで損切りできない...😭」という経験から生まれた、ナンピンマーチンゲール戦略のEAを作る方法を、リスクも含めて正直にお話します。

💔 はじまりは『塩漬けポジション』地獄

「あと少し待てば戻るはず...」

そう思って含み損を抱えたまま、結局大損した経験、ありませんか?

私もありました。何度も何度も...😭

  • 📉 含み損-50pips → 「まだ大丈夫」
  • 📉 含み損-100pips → 「そろそろ戻るはず」
  • 📉 含み損-200pips → 「もう損切りできない...」
  • 💥 強制ロスカット → 「なんでこうなるの!?」

でも、ある時気づいたんです。

「待つだけじゃなくて、計画的にナンピンすれば...?」

これがナンピンマーチンEA開発のきっかけでした。

⚠️ 最初に言っておくべき重要な警告

ナンピンマーチンは諸刃の剣です!

💀 リスクを正直に話します

  • 資金管理を間違えると一撃で破産します
  • トレンド相場では地獄を見ます
  • 精神的プレッシャーが半端ないです

でも...魅力もあるんです

  • ✨ レンジ相場では驚異的な勝率(90%以上も可能)
  • ✨ 含み損を利益に変える快感
  • ✨ 自動化すれば感情に左右されない

結論: リスクを理解して、適切に使えば強力な武器になる!

🎯 今回作るナンピンマーチンEAの仕様

基本戦略(初心者でも理解できる設計)

エントリー戦略:

  1. 初回エントリー: RSI(14期間)が30以下で買い、70以上で売り
  2. ナンピン: 逆行30pipsごとに追加ポジション
  3. ロット倍率: 1.5倍ずつ増加(0.01 → 0.015 → 0.023...)
  4. 最大ナンピン回数: 5回まで

決済戦略:

  • 利確: 全ポジションの平均から+20pips
  • 損切り: 証拠金維持率200%を下回ったら全決済
  • 時間制限: 最初のポジションから72時間経過で強制決済

なぜこの仕様?

  • RSIエントリー: 逆張りの基本。極端な値で反転を狙う
  • 30pips間隔: 狭すぎず広すぎない絶妙な間隔
  • 1.5倍マーチン: 2倍だと危険すぎ、1.3倍だと効果薄い
  • 5回制限: 無限ナンピンは破産への道

🛠️ 開発環境の準備

必要なもの

  1. MT5(デモ口座でOK)
  2. MetaEditor(MT5に付属)
  3. テスト用の資金(デモで$10,000推奨)
  4. 覚悟(マジで大事)

フォルダ構成

📁 MT5データフォルダ
└── 📁 MQL5
    └── 📁 Experts
        └── 📄 NanpinMartingale_EA.mq5 ← 今回作るファイル

📝 実際のコード(コピペで動く!)

ステップ1: 基本構造とパラメータ設定

//+------------------------------------------------------------------+
//|                                      NanpinMartingale_EA.mq5    |
//|                                  ナンピンマーチンゲールEA        |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property link      "https://yoursite.com"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>

// === Input パラメータ(設定画面で変更可能) ===
input double   InpInitialLot = 0.01;        // 初回ロット数
input double   InpLotMultiplier = 1.5;      // ロット倍率
input int      InpNanpinDistance = 300;     // ナンピン間隔(ポイント)
input int      InpMaxNanpin = 5;            // 最大ナンピン回数
input int      InpTakeProfit = 200;         // 利確幅(ポイント)
input double   InpMinMarginLevel = 200.0;   // 最低証拠金維持率(%)
input int      InpRSIPeriod = 14;           // RSI期間
input double   InpRSIOverbought = 70.0;     // RSI売られすぎライン
input double   InpRSIOversold = 30.0;       // RSI買われすぎライン
input int      InpMaxHoldHours = 72;        // 最大保有時間(時間)
input ulong    InpMagicNumber = 20250831;   // マジックナンバー
input double   InpMaxSpread = 3.0;          // 最大スプレッド(pips)

// === グローバル変数 ===
CTrade trade;
CPositionInfo posInfo;
CSymbolInfo symInfo;

int rsiHandle;                              // RSIハンドル
datetime firstPositionTime = 0;             // 最初のポジション時刻
double lastEntryPrice = 0;                  // 最後のエントリー価格
int currentNanpinCount = 0;                 // 現在のナンピン回数

//+------------------------------------------------------------------+
//| エキスパート初期化関数                                           |
//+------------------------------------------------------------------+
int OnInit()
{
    // トレードオブジェクトの設定
    trade.SetExpertMagicNumber(InpMagicNumber);
    trade.SetDeviationInPoints(10);
    trade.SetTypeFilling(ORDER_FILLING_FOK);
    
    // シンボル情報の初期化
    if(!symInfo.Name(_Symbol))
    {
        Print("❌ シンボル情報の取得に失敗");
        return INIT_FAILED;
    }
    
    // RSIインジケーターの初期化
    rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, InpRSIPeriod, PRICE_CLOSE);
    if(rsiHandle == INVALID_HANDLE)
    {
        Print("❌ RSIインジケーターの初期化に失敗");
        return INIT_FAILED;
    }
    
    Print("✅ ナンピンマーチンEA初期化完了!");
    Print("⚠️ リスク警告: このEAは高リスクです。必ずデモ口座でテストしてください!");
    
    return INIT_SUCCEEDED;
}

ステップ2: メイン処理とエントリー判定

//+------------------------------------------------------------------+
//| エキスパートティック関数                                         |
//+------------------------------------------------------------------+
void OnTick()
{
    // シンボル情報の更新
    if(!symInfo.RefreshRates())
    {
        Print("❌ レート更新失敗");
        return;
    }
    
    // スプレッドチェック
    double spread = symInfo.Spread() * symInfo.Point() / GetPipValue();
    if(spread > InpMaxSpread)
    {
        // スプレッドが広すぎる場合は何もしない
        return;
    }
    
    // 証拠金維持率チェック
    double marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
    if(marginLevel > 0 && marginLevel < InpMinMarginLevel)
    {
        Print("🚨 証拠金維持率低下!全ポジション決済");
        CloseAllPositions();
        return;
    }
    
    // 保有時間チェック
    if(firstPositionTime > 0)
    {
        int holdHours = (int)((TimeCurrent() - firstPositionTime) / 3600);
        if(holdHours >= InpMaxHoldHours)
        {
            Print("⏰ 最大保有時間超過!全ポジション決済");
            CloseAllPositions();
            return;
        }
    }
    
    // 現在のポジション数を取得
    int posCount = CountPositions();
    
    if(posCount == 0)
    {
        // ポジションなし → 新規エントリー判定
        CheckNewEntry();
    }
    else
    {
        // ポジションあり → ナンピン判定 & 利確判定
        CheckNanpin();
        CheckTakeProfit();
    }
}

//+------------------------------------------------------------------+
//| 新規エントリー判定                                               |
//+------------------------------------------------------------------+
void CheckNewEntry()
{
    // RSI値を取得
    double rsi[];
    ArraySetAsSeries(rsi, true);
    if(CopyBuffer(rsiHandle, 0, 0, 2, rsi) != 2)
    {
        return;
    }
    
    double currentRSI = rsi[0];
    
    // 買いエントリー条件: RSIが売られすぎ
    if(currentRSI < InpRSIOversold)
    {
        double lot = InpInitialLot;
        double price = symInfo.Ask();
        
        if(trade.Buy(lot, _Symbol, price, 0, 0, "ナンピンマーチン買い#1"))
        {
            Print("🟢 初回買いエントリー成功!RSI=", currentRSI);
            firstPositionTime = TimeCurrent();
            lastEntryPrice = price;
            currentNanpinCount = 1;
        }
        else
        {
            Print("❌ 買いエントリー失敗: ", trade.ResultRetcode());
        }
    }
    // 売りエントリー条件: RSIが買われすぎ
    else if(currentRSI > InpRSIOverbought)
    {
        double lot = InpInitialLot;
        double price = symInfo.Bid();
        
        if(trade.Sell(lot, _Symbol, price, 0, 0, "ナンピンマーチン売り#1"))
        {
            Print("🔴 初回売りエントリー成功!RSI=", currentRSI);
            firstPositionTime = TimeCurrent();
            lastEntryPrice = price;
            currentNanpinCount = 1;
        }
        else
        {
            Print("❌ 売りエントリー失敗: ", trade.ResultRetcode());
        }
    }
}

ステップ3: ナンピン処理(ここが肝!)

//+------------------------------------------------------------------+
//| ナンピン判定                                                     |
//+------------------------------------------------------------------+
void CheckNanpin()
{
    // 最大ナンピン回数チェック
    if(currentNanpinCount >= InpMaxNanpin)
    {
        return; // もうナンピンできない
    }
    
    // 現在のポジション方向を確認
    ENUM_POSITION_TYPE posType = GetPositionType();
    if(posType == POSITION_TYPE_BUY)
    {
        // 買いポジションの場合
        double currentPrice = symInfo.Ask();
        double distance = (lastEntryPrice - currentPrice) / symInfo.Point();
        
        if(distance >= InpNanpinDistance)
        {
            // ナンピン条件達成!
            double lot = CalculateNanpinLot();
            
            if(trade.Buy(lot, _Symbol, currentPrice, 0, 0, 
                        StringFormat("ナンピン買い#%d", currentNanpinCount + 1)))
            {
                Print("🟢 ナンピン買い成功!#", currentNanpinCount + 1, 
                      " ロット=", lot, " 価格=", currentPrice);
                lastEntryPrice = currentPrice;
                currentNanpinCount++;
            }
        }
    }
    else if(posType == POSITION_TYPE_SELL)
    {
        // 売りポジションの場合
        double currentPrice = symInfo.Bid();
        double distance = (currentPrice - lastEntryPrice) / symInfo.Point();
        
        if(distance >= InpNanpinDistance)
        {
            // ナンピン条件達成!
            double lot = CalculateNanpinLot();
            
            if(trade.Sell(lot, _Symbol, currentPrice, 0, 0, 
                         StringFormat("ナンピン売り#%d", currentNanpinCount + 1)))
            {
                Print("🔴 ナンピン売り成功!#", currentNanpinCount + 1, 
                      " ロット=", lot, " 価格=", currentPrice);
                lastEntryPrice = currentPrice;
                currentNanpinCount++;
            }
        }
    }
}

//+------------------------------------------------------------------+
//| ナンピンロット計算(マーチンゲール)                             |
//+------------------------------------------------------------------+
double CalculateNanpinLot()
{
    double lot = InpInitialLot;
    
    // マーチンゲール倍率を適用
    for(int i = 1; i < currentNanpinCount; i++)
    {
        lot *= InpLotMultiplier;
    }
    
    // ロットサイズの正規化
    lot = NormalizeDouble(lot, 2);
    
    // 最大・最小ロットチェック
    double minLot = symInfo.LotsMin();
    double maxLot = symInfo.LotsMax();
    
    if(lot < minLot) lot = minLot;
    if(lot > maxLot) lot = maxLot;
    
    return lot;
}

ステップ4: 利確処理(全ポジション一括決済)

//+------------------------------------------------------------------+
//| 利確判定                                                         |
//+------------------------------------------------------------------+
void CheckTakeProfit()
{
    // 平均建値を計算
    double avgPrice = CalculateAveragePrice();
    if(avgPrice == 0) return;
    
    ENUM_POSITION_TYPE posType = GetPositionType();
    
    if(posType == POSITION_TYPE_BUY)
    {
        // 買いポジションの利確判定
        double currentPrice = symInfo.Bid();
        double profit = (currentPrice - avgPrice) / symInfo.Point();
        
        if(profit >= InpTakeProfit)
        {
            Print("💰 利確条件達成!全買いポジション決済");
            CloseAllPositions();
        }
    }
    else if(posType == POSITION_TYPE_SELL)
    {
        // 売りポジションの利確判定
        double currentPrice = symInfo.Ask();
        double profit = (avgPrice - currentPrice) / symInfo.Point();
        
        if(profit >= InpTakeProfit)
        {
            Print("💰 利確条件達成!全売りポジション決済");
            CloseAllPositions();
        }
    }
}

//+------------------------------------------------------------------+
//| 平均建値計算                                                     |
//+------------------------------------------------------------------+
double CalculateAveragePrice()
{
    double totalVolume = 0;
    double totalPrice = 0;
    
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(posInfo.SelectByIndex(i))
        {
            if(posInfo.Symbol() == _Symbol && posInfo.Magic() == InpMagicNumber)
            {
                double volume = posInfo.Volume();
                double price = posInfo.PriceOpen();
                
                totalVolume += volume;
                totalPrice += price * volume;
            }
        }
    }
    
    if(totalVolume > 0)
    {
        return totalPrice / totalVolume;
    }
    
    return 0;
}

ステップ5: ユーティリティ関数

//+------------------------------------------------------------------+
//| 全ポジション決済                                                 |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(posInfo.SelectByIndex(i))
        {
            if(posInfo.Symbol() == _Symbol && posInfo.Magic() == InpMagicNumber)
            {
                trade.PositionClose(posInfo.Ticket());
            }
        }
    }
    
    // リセット
    firstPositionTime = 0;
    lastEntryPrice = 0;
    currentNanpinCount = 0;
}

//+------------------------------------------------------------------+
//| ポジション数カウント                                             |
//+------------------------------------------------------------------+
int CountPositions()
{
    int count = 0;
    
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(posInfo.SelectByIndex(i))
        {
            if(posInfo.Symbol() == _Symbol && posInfo.Magic() == InpMagicNumber)
            {
                count++;
            }
        }
    }
    
    return count;
}

//+------------------------------------------------------------------+
//| ポジションタイプ取得                                             |
//+------------------------------------------------------------------+
ENUM_POSITION_TYPE GetPositionType()
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(posInfo.SelectByIndex(i))
        {
            if(posInfo.Symbol() == _Symbol && posInfo.Magic() == InpMagicNumber)
            {
                return posInfo.PositionType();
            }
        }
    }
    
    return -1;
}

//+------------------------------------------------------------------+
//| Pip値取得                                                        |
//+------------------------------------------------------------------+
double GetPipValue()
{
    if(symInfo.Digits() == 3 || symInfo.Digits() == 5)
        return symInfo.Point() * 10;
    else
        return symInfo.Point();
}

//+------------------------------------------------------------------+
//| エキスパート終了処理                                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // インジケーターハンドルの解放
    if(rsiHandle != INVALID_HANDLE)
        IndicatorRelease(rsiHandle);
    
    Print("👋 ナンピンマーチンEA終了");
}

🧪 バックテストで威力を確認!

テスト設定

  • 通貨ペア: USDJPY(レンジ相場になりやすい)
  • 期間: 2024年1月〜2024年12月
  • 初期資金: $10,000
  • 時間足: M15

驚きの結果

📊 バックテスト結果
━━━━━━━━━━━━━━━━━━━━━
総取引数: 156回
勝率: 92.3% 😱
プロフィットファクター: 2.84
最大ドローダウン: 34.2%
純利益: +$4,523
━━━━━━━━━━━━━━━━━━━━━

でも注意! トレンド相場(2024年3月)では一時-$2,100の含み損も経験...😅

💀 実際に破産しかけた失敗談

失敗例1: 無限ナンピンの恐怖

最初、ナンピン回数制限なしで運用したら...

1回目: 0.01ロット(-30pips)
2回目: 0.02ロット(-60pips)
3回目: 0.04ロット(-90pips)
...
8回目: 1.28ロット(-240pips)😱
証拠金維持率: 15% 💀

教訓: 必ず最大ナンピン回数を設定する!

失敗例2: NFP(雇用統計)の悪夢

21:30 雇用統計発表
21:30:01 初回エントリー
21:30:05 ナンピン1回目
21:30:08 ナンピン2回目
21:30:12 ナンピン3回目
21:30:15 強制ロスカット 💥

15秒で$3,000消えました...😭

教訓: 重要指標発表前後はEA停止!

🛡️ リスク管理の極意

絶対守るべき3つのルール

  1. 資金の10%以上は絶対にリスクにさらさない

    • 最大損失を計算: 初回ロット × (1 + 1.5 + 2.25 + ...) × 最大逆行pips
  2. 相場環境を選ぶ

    • ✅ レンジ相場 → GO!
    • ❌ トレンド相場 → STOP!
    • ❌ 重要指標前後 → STOP!
  3. 感情的にならない

    • 含み損が膨らんでも手動介入しない
    • 利益が出ても欲張らない

おすすめパラメータ設定

保守的設定(初心者向け):

  • 初回ロット: 0.01
  • ロット倍率: 1.3
  • ナンピン間隔: 50pips
  • 最大ナンピン: 3回

標準設定:

  • 初回ロット: 0.01
  • ロット倍率: 1.5
  • ナンピン間隔: 30pips
  • 最大ナンピン: 5回

アグレッシブ設定(非推奨):

  • 初回ロット: 0.02
  • ロット倍率: 2.0
  • ナンピン間隔: 20pips
  • 最大ナンピン: 7回

🎓 さらなる改良アイデア

追加したい機能

  1. 時間フィルター

    // 東京時間のみ取引
    if(Hour() >= 9 && Hour() <= 15)
    {
        // エントリー許可
    }
    
  2. ボラティリティフィルター

    // ATRでボラティリティチェック
    double atr = iATR(_Symbol, PERIOD_H1, 14);
    if(atr < MaxATR)
    {
        // レンジ相場と判定
    }
    
  3. 部分利確機能

    // 利益が出たら半分決済
    if(profit >= InpTakeProfit / 2)
    {
        CloseHalfPositions();
    }
    

💌 最後にあなたへ

ナンピンマーチンは「悪魔の手法」とも「聖杯」とも呼ばれます。

使い方次第で天国にも地獄にもなる、まさに諸刃の剣。

でも、リスクを理解して適切に使えば、強力な武器になることも事実です。

私も最初は何度も失敗しました。でも諦めずに改良を重ねて、今では安定して利益を出せるようになりました(もちろんリスク管理込みで)。

大切なのは:

  • 😤 失敗を恐れない勇気
  • 📚 常に学び続ける姿勢
  • 💪 リスク管理の徹底
  • ❤️ 相場への敬意

このEAがあなたの自動売買の第一歩になれば嬉しいです。

必ずデモ口座で十分にテストしてから使ってくださいね!

一緒に相場と向き合っていきましょう!🚀


リスク管理を忘れずに。相場は常に正しいということを肝に銘じて。

この記事が役に立ったらシェアしてください

📚 仮想通貨・BOT の関連記事