MQL5 網格交易 EA 完整實作:從基礎網格到進階動態策略

📌 本文重點
本文從基礎到進階完整實作 MQL5 網格交易 EA:固定間距網格、ATR 自適應動態網格、掛單管理、自動補格機制、最大虧損停止,以及回測優化建議。

MQL5 網格交易 EA 完整實作:從基礎到進階策略

> 「網格交易就像在河裡布網捕魚——價格波動是你的朋友,但洪水來時要記得收網。」 — 網格交易的風險哲學

前言:網格交易的魅力與危險

我記得第一次接觸網格交易是在2018年,當時比特幣在6000-8000美元之間震盪。一個簡單的網格機器人一個月賺了15%,我覺得找到了「聖杯」。

然後比特幣突破8000美元,一路漲到20000美元。我的網格機器人因為不斷在「高點」賣出,最後虧損了40%。

今天,我想分享的不只是如何建立網格交易EA,更重要的是如何控制網格交易的風險

第一部分:網格交易的基本原理

1.1 什麼是網格交易?

網格交易的核心思想很簡單:在價格區間內布下一張網,價格每波動一個網格就賺一次錢

//+------------------------------------------------------------------+
//| 網格交易視覺化演示                                               |
//+------------------------------------------------------------------+
class GridVisualizer
{
public:
    void DrawGrid(double centerPrice, double gridStep, int levels, string symbol)
    {
        Print("=== 網格交易視覺化 ===");
        Print("中心價格: ", DoubleToString(centerPrice, 5));
        Print("網格間隔: ", DoubleToString(gridStep, 1), "點");
        Print("網格層數: ", levels, " (總網格: ", levels * 2 + 1, ")");
        Print("交易品種: ", symbol);
        
        // 計算網格價格
        double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
        double stepPrice = gridStep * point;
        
        Print("\n網格價格分佈:");
        for(int i = -levels; i <= levels; i++)
        {
            double gridPrice = centerPrice + (i * stepPrice);
            string orderType = (i < 0) ? "買單" : "賣單";
            
            Print("網格 ", i + levels + 1, ": ", 
                  DoubleToString(gridPrice, 5), " (", orderType, ")");
        }
        
        Print("\n交易邏輯:");
        Print("1. 價格觸及買單網格 → 開立買單");
        Print("2. 價格觸及賣單網格 → 開立賣單");
        Print("3. 價格在網格間波動 → 不斷獲利");
        Print("4. 價格突破網格範圍 → 風險!");
    }
    
    // 計算潛在收益
    void CalculatePotentialProfit(double gridStep, double lotSize, int expectedTrades)
    {
        double pointValue = CalculatePointValue();
        double profitPerTrade = gridStep * pointValue * lotSize;
        double totalProfit = profitPerTrade * expectedTrades;
        
        Print("\n潛在收益分析:");
        Print("每筆交易利潤: $", DoubleToString(profitPerTrade, 2));
        Print("預期交易次數: ", expectedTrades, "次/月");
        Print("月潛在收益: $", DoubleToString(totalProfit, 2));
        Print("年化收益: $", DoubleToString(totalProfit * 12, 2));
        
        // 風險警告
        Print("\n⚠️  風險警告:");
        Print("1. 實際收益取決於市場波動性");
        Print("2. 單邊行情可能導致虧損");
        Print("3. 需要足夠資金支撐網格");
    }
    
private:
    double CalculatePointValue()
    {
        // 計算每點價值
        double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
        double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
        double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
        
        return tickValue * (tickSize / point);
    }
};

// 使用範例
void DemoGridTrading()
{
    GridVisualizer visualizer;
    visualizer.DrawGrid(1.10000, 50, 5, "EURUSD");
    visualizer.CalculatePotentialProfit(50, 0.1, 20);
}

1.2 網格交易的優點與缺點

// 網格交易優缺點分析
void AnalyzeGridTradingProsCons()
{
    Print("=== 網格交易優缺點分析 ===");
    
    Print("\n✅ 優點:");
    Print("1. 無需預測方向: 上漲下跌都能賺錢");
    Print("2. 自動化執行: 情緒影響最小化");
    Print("3. 適合區間市場: 震盪行情表現最佳");
    Print("4. 複利效應: 利潤可以再投資");
    Print("5. 分散風險: 多個小交易代替少數大交易");
    
    Print("\n❌ 缺點:");
    Print("1. 單邊行情風險: 突破網格可能巨虧");
    Print("2. 資金需求大: 需要足夠資金支撐網格");
    Print("3. 機會成本: 資金被鎖定在網格中");
    Print("4. 手續費累積: 頻繁交易產生高額成本");
    Print("5. 執行風險: 滑價和延遲可能影響利潤");
    
    Print("\n📊 適合情境:");
    Print("1. 區間震盪市場 (70%時間)");
    Print("2. 低波動性環境");
    Print("3. 有明確支撐阻力的商品");
    Print("4. 長期橫盤整理階段");
    
    Print("\n🚫 不適合情境:");
    Print("1. 趨勢明顯的單邊市場");
    Print("2. 高波動性環境 (如重要新聞發布)");
    Print("3. 流動性差的商品");
    Print("4. 小資金帳戶");
}

第二部分:基礎網格交易 EA 實作

2.1 簡單網格交易 EA

//+------------------------------------------------------------------+
//| SimpleGridEA.mq5                                                 |
//+------------------------------------------------------------------+
#property copyright "James Lee - Grid Trading System"
#property version   "1.00"
#property strict

// 網格參數
input group "==== 網格設定 ===="
input double   GridCenterPrice = 0;       // 網格中心價格 (0=自動)
input double   GridStepPips = 50;         // 網格間隔 (點)
input int      GridLevels = 5;            // 網格層數 (每邊)
input double   LotSize = 0.01;            // 基礎手數
input bool     UseMartingale = false;     // 使用馬丁格爾
input double   MartingaleMultiplier = 2.0;// 馬丁格爾乘數

input group "==== 風險控制 ===="
input double   MaxRiskPercent = 10.0;     // 最大風險百分比
input double   MaxDrawdownPercent = 20.0; // 最大回撤百分比
input double   StopLossDistance = 500;    // 整體止損距離 (點)
input bool     UseEquityStop = true;      // 使用淨值止損
input double   EquityStopPercent = 30.0;  // 淨值止損百分比

input group "==== 交易時間 ===="
input bool     UseTimeFilter = true;      // 使用時間過濾
input string   StartTime = "00:00";       // 開始時間
input string   EndTime = "23:59";         // 結束時間
input bool     AvoidNews = true;          // 避開重要新聞

// 全域變數
double g_gridPrices[];                    // 網格價格陣列
bool   g_gridActive[];                    // 網格是否激活
int    g_gridOrders[];                    // 網格對應的訂單編號
double g_gridLots[];                      // 網格手數

double g_initialBalance;                  // 初始餘額
double g_highWaterMark;                   // 高水位線
double g_maxDrawdown;                     // 最大回撤

int    g_totalGrids;                      // 總網格數
bool   g_gridInitialized = false;         // 網格是否初始化

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    Print("=== SimpleGridEA 初始化 ===");
    
    // 檢查交易權限
    if(!IsTradeAllowed())
    {
        Alert("錯誤: 當前圖表不允許交易");
        return INIT_FAILED;
    }
    
    // 初始化帳戶數據
    g_initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
    g_highWaterMark = g_initialBalance;
    g_maxDrawdown = 0;
    
    // 初始化網格
    if(!InitializeGrid())
    {
        Print("錯誤: 網格初始化失敗");
        return INIT_FAILED;
    }
    
    // 顯示網格資訊
    DisplayGridInfo();
    
    // 顯示風險警告
    DisplayRiskWarning();
    
    Print("✅ EA 初始化完成");
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    Print("=== SimpleGridEA 停止 ===");
    
    // 關閉所有網格訂單
    CloseAllGridOrders();
    
    // 顯示績效報告
    DisplayPerformanceReport();
    
    Print("EA 已停止,所有訂單已關閉");
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 檢查交易時間
    if(!CheckTradingTime())
        return;
    
    // 檢查風險限制
    if(!CheckRiskLimits())
    {
        Print("達到風險限制,停止交易");
        ExpertRemove();
        return;
    }
    
    // 更新網格
    UpdateGrid();
    
    // 檢查網格訂單
    CheckGridOrders();
    
    // 管理持倉
    ManagePositions();
}

//+------------------------------------------------------------------+
//| 初始化網格                                                       |
//+------------------------------------------------------------------+
bool InitializeGrid()
{
    Print("初始化交易網格...");
    
    // 計算總網格數
    g_totalGrids = GridLevels * 2 + 1;
    
    // 調整陣列大小
    ArrayResize(g_gridPrices, g_totalGrids);
    ArrayResize(g_gridActive, g_totalGrids);
    ArrayResize(g_gridOrders, g_totalGrids);
    ArrayResize(g_gridLots, g_totalGrids);
    
    // 設定網格中心價格
    double centerPrice;
    if(GridCenterPrice <= 0)
    {
        // 自動設定為當前價格
        centerPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    }
    else
    {
        centerPrice = GridCenterPrice;
    }
    
    // 計算網格間隔價格
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double stepPrice = GridStepPips * point;
    
    // 設定每個網格的價格和手數
    for(int i = 0; i < g_totalGrids; i++)
    {
        // 計算網格索引 (從負到正)
        int gridIndex = i - GridLevels;
        
        // 計算網格價格
        g_gridPrices[i] = centerPrice + (gridIndex * stepPrice);
        
        // 初始化狀態
        g_gridActive[i] = true;
        g_gridOrders[i] = -1;
        
        // 計算手數 (馬丁格爾或固定)
        if(UseMartingale)
        {
            // 馬丁格爾: 離中心越遠,手數越大
            int distance = MathAbs(gridIndex);
            g_gridLots[i] = LotSize * MathPow(MartingaleMultiplier, distance);
        }
        else
        {
            // 固定手數
            g_gridLots[i] = LotSize;
        }
        
        // 調整手數符合規則
        g_gridLots[i] = AdjustLotSize(g_gridLots[i]);
    }
    
    g_gridInitialized = true;
    return true;
}

//+------------------------------------------------------------------+
//| 顯示網格資訊                                                     |
//+------------------------------------------------------------------+
void DisplayGridInfo()
{
    Print("=== 網格交易設定 ===");
    Print("交易品種: ", _Symbol);
    Print("網格層數: ", GridLevels, " (每邊)");
    Print("總網格數: ", g_totalGrids);
    Print("網格間隔: ", GridStepPips, "點");
    Print("基礎手數: ", DoubleToString(LotSize, 2));
    Print("馬丁格爾: ", (UseMartingale ? "是" : "否"));
    
    if(UseMartingale)
    {
        Print("馬丁格爾乘數: ", DoubleToString(MartingaleMultiplier, 1));
    }
    
    Print("\n網格價格分佈:");
    for(int i = 0; i < g_totalGrids; i++)
    {
        int gridIndex = i - GridLevels;
        string orderType = (gridIndex < 0) ? "買單" : "賣單";
        
        Print("網格 ", i+1, " (", orderType, "): ", 
              DoubleToString(g_gridPrices[i], 5), 
              " 手數: ", DoubleToString(g_gridLots[i], 2));
    }
    
    // 計算所需保證金
    CalculateRequiredMargin();
}

//+------------------------------------------------------------------+
//| 計算所需保證金                                                   |
//+------------------------------------------------------------------+
void CalculateRequiredMargin()
{
    double totalMargin = 0;
    double maxMarginPerGrid = 0;
    
    for(int i = 0; i < g_totalGrids; i++)
    {
        double marginRequired;
        double price = g_gridPrices[i];
        double lots = g_gridLots[i];
        
        // 買單和賣單都需要計算保證金
        if(OrderCalcMargin(ORDER_TYPE_BUY, _Symbol, lots, price, marginRequired))
        {
            totalMargin += marginRequired;
            maxMarginPerGrid = MathMax(maxMarginPerGrid, marginRequired);
        }
    }
    
    double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
    double marginRatio = (totalMargin / accountBalance) * 100;
    
    Print("\n保證金分析:");
    Print("總所需保證金: $", DoubleToString(totalMargin, 2));
    Print("帳戶餘額: $", DoubleToString(accountBalance, 2));
    Print("保證金比例: ", DoubleToString(marginRatio, 1), "%");
    Print("單網格最大保證金: $", DoubleToString(maxMarginPerGrid, 2));
    
    if(marginRatio > 50)
    {
        Print("⚠️  警告: 保證金比例過高 (>50%)");
        Print("建議: 減少網格層數或降低手數");
    }
}

//+------------------------------------------------------------------+
//| 顯示風險警告                                                     |
//+------------------------------------------------------------------+
void DisplayRiskWarning()
{
    Print("\n=== 風險警告 ===");
    Print("⚠️  網格交易是高風險策略!");
    Print("主要風險:");
    Print("1. 單邊行情可能導致重大虧損");
    Print("2. 需要足夠資金支撐網格");
    Print("3. 市場流動性不足時可能無法平倉");
    Print("4. 極端波動可能觸發連鎖止損");
    
    Print("\n風險控制措施:");
    Print("1. 最大風險限制: ", DoubleToString(MaxRiskPercent, 1), "%");
    Print("2. 最大回撤限制: ", DoubleToString(MaxDrawdownPercent, 1), "%");
    Print("3. 整體止損: ", StopLossDistance, "點");
    Print("4. 淨值止損: ", (UseEquityStop ? "啟用" : "關閉"));
    
    if(UseMartingale)
    {
        Print("\n⚠️  馬丁格爾警告:");
        Print("馬丁格爾可能導致:");
        Print("1. 指數級虧損");
        Print("2. 保證金不足");
        Print("3. 無法承受的風險");
        Print("建議: 僅在模擬帳戶測試馬丁格爾");
    }
}

2.2 網格更新與管理

//+------------------------------------------------------------------+
//| 更新網格狀態                                                     |
//+------------------------------------------------------------------+
void UpdateGrid()
{
    double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    
    // 檢查是否需要調整網格中心
    if(ShouldAdjustGridCenter(currentPrice))
    {
        AdjustGridCenter(currentPrice);
    }
    
    // 激活/停用網格
    UpdateGridActivation(currentPrice);
    
    // 放置網格訂單
    PlaceGridOrders(currentPrice);
}

//+------------------------------------------------------------------+
//| 檢查是否需要調整網格中心                                         |
//+------------------------------------------------------------------+
bool ShouldAdjustGridCenter(double currentPrice)
{
    // 如果價格偏離網格中心太遠,考慮調整
    double centerPrice = g_gridPrices[GridLevels];  // 中間網格是中心
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double distance = MathAbs(currentPrice - centerPrice) / point;
    
    // 如果偏離超過3個網格,考慮調整
    if(distance > GridStepPips * 3)
    {
        Print("價格偏離網格中心: ", DoubleToString(distance, 0), "點");
        Print("建議調整網格中心");
        return true;
    }
    
    return false;
}

//+------------------------------------------------------------------+
//| 調整網格中心                                                     |
//+------------------------------------------------------------------+
void AdjustGridCenter(double newCenterPrice)
{
    Print("調整網格中心到: ", DoubleToString(newCenterPrice, 5));
    
    // 關閉所有網格訂單
    CloseAllGridOrders();
    
    // 重新計算網格價格
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double stepPrice = GridStepPips * point;
    
    for(int i = 0; i < g_totalGrids; i++)
    {
        int gridIndex = i - GridLevels;
        g_gridPrices[i] = newCenterPrice + (gridIndex * stepPrice);
        g_gridActive[i] = true;
        g_gridOrders[i] = -1;
    }
    
    Print("網格中心調整完成");
}

//+------------------------------------------------------------------+
//| 更新網格激活狀態                                                 |
//+------------------------------------------------------------------+
void UpdateGridActivation(double currentPrice)
{
    // 根據當前價格激活/停用網格
    for(int i = 0; i < g_totalGrids; i++)
    {
        // 買單網格 (價格低於當前價)
        if(i < GridLevels)  // 左半邊是買單
        {
            // 如果價格高於網格價格,激活買單
            g_gridActive[i] = (currentPrice > g_gridPrices[i]);
        }
        // 賣單網格 (價格高於當前價)
        else if(i > GridLevels)  // 右半邊是賣單
        {
            // 如果價格低於網格價格,激活賣單
            g_gridActive[i] = (currentPrice < g_gridPrices[i]);
        }
        else  // 中心網格
        {
            g_gridActive[i] = false;  // 中心網格不交易
        }
    }
}

//+------------------------------------------------------------------+
//| 放置網格訂單                                                     |
//+------------------------------------------------------------------+
void PlaceGridOrders(double currentPrice)
{
    for(int i = 0; i < g_totalGrids; i++)
    {
        // 檢查網格是否激活且沒有訂單
        if(g_gridActive[i] && g_gridOrders[i] == -1)
        {
            // 決定訂單類型
            ENUM_ORDER_TYPE orderType;
            if(i < GridLevels)
            {
                orderType = ORDER_TYPE_BUY_LIMIT;  // 低價買入
            }
            else if(i > GridLevels)
            {
                orderType = ORDER_TYPE_SELL_LIMIT; // 高價賣出
            }
            else
            {
                continue;  // 跳過中心網格
            }
            
            // 下單
            int orderTicket = PlaceGridOrder(orderType, g_gridPrices[i], g_gridLots[i], i);
            
            if(orderTicket > 0)
            {
                g_gridOrders[i] = orderTicket;
                Print("網格訂單放置成功: #", orderTicket, 
                      " 價格: ", DoubleToString(g_gridPrices[i], 5),
                      " 手數: ", DoubleToString(g_gridLots[i], 2));
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 放置單個網格訂單                                                 |
//+------------------------------------------------------------------+
int PlaceGridOrder(ENUM_ORDER_TYPE orderType, double price, double volume, int gridIndex)
{
    MqlTradeRequest request;
    MqlTradeResult result;
    
    ZeroMemory(request);
    ZeroMemory(result);
    
    request.action = TRADE_ACTION_PENDING;
    request.symbol = _Symbol;
    request.volume = volume;
    request.type = orderType;
    request.price = NormalizeDouble(price, Digits());
    request.sl = 0;  // 網格訂單通常不設止損
    request.tp = 0;  // 利潤通過反向訂單實現
    request.deviation = 10;
    request.magic = 1000 + gridIndex;  // 用網格索引作為magic number的一部分
    request.comment = "Grid " + IntegerToString(gridIndex + 1);
    
    // 設定訂單有效期 (例如24小時)
    request.expiration = TimeCurrent() + 86400;
    
    if(!OrderSend(request, result))
    {
        Print("網格訂單失敗: ", GetLastError());
        return -1;
    }
    
    return (int)result.order;
}

//+------------------------------------------------------------------+
//| 檢查網格訂單                                                     |
//+------------------------------------------------------------------+
void CheckGridOrders()
{
    for(int i = 0; i < g_totalGrids; i++)
    {
        if(g_gridOrders[i] > 0)
        {
            // 檢查訂單狀態
            if(OrderSelect(g_gridOrders[i]))
            {
                // 如果訂單已成交,重置網格狀態
                if(OrderType() <= ORDER_TYPE_SELL)  // 市價單 (已成交)
                {
                    Print("網格訂單 #", g_gridOrders[i], " 已成交");
                    g_gridOrders[i] = -1;
                    
                    // 成交後放置反向訂單
                    PlaceOppositeOrder(i);
                }
                // 如果訂單已取消或過期
                else if(OrderState() == ORDER_STATE_CANCELED || 
                        OrderState() == ORDER_STATE_EXPIRED)
                {
                    Print("網格訂單 #", g_gridOrders[i], " 已取消/過期");
                    g_gridOrders[i] = -1;
                }
            }
            else
            {
                // 訂單不存在,重置狀態
                g_gridOrders[i] = -1;
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 放置反向訂單                                                     |
//+------------------------------------------------------------------+
void PlaceOppositeOrder(int gridIndex)
{
    // 計算反向網格索引
    int oppositeIndex = -1;
    
    if(gridIndex < GridLevels)  // 原先是買單
    {
        // 買單成交後,在更高價格放置賣單
        oppositeIndex = GridLevels + (GridLevels - gridIndex);
    }
    else if(gridIndex > GridLevels)  // 原先是賣單
    {
        // 賣單成交後,在更低價格放置買單
        oppositeIndex = GridLevels - (gridIndex - GridLevels);
    }
    
    if(oppositeIndex >= 0 && oppositeIndex < g_totalGrids)
    {
        // 激活反向網格
        g_gridActive[oppositeIndex] = true;
        g_gridOrders[oppositeIndex] = -1;
        
        Print("激活反向網格: ", oppositeIndex + 1);
    }
}

//+------------------------------------------------------------------+
//| 管理持倉                                                         |
//+------------------------------------------------------------------+
void ManagePositions()
{
    // 檢查是否有持倉需要管理
    int totalPositions = PositionsTotal();
    
    for(int i = totalPositions - 1; i >= 0; i--)
    {
        if(PositionGetSymbol(i) == _Symbol)
        {
            ulong magic = PositionGetInteger(POSITION_MAGIC);
            
            // 檢查是否為網格交易持倉
            if(magic >= 1000 && magic < 1000 + g_totalGrids)
            {
                ManageGridPosition(i);
            }
        }
    }
}

//+------------------------------------------------------------------+
//| 管理單個網格持倉                                                 |
//+------------------------------------------------------------------+
void ManageGridPosition(int positionIndex)
{
    // 取得持倉資訊
    ulong ticket = PositionGetTicket(positionIndex);
    ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    double volume = PositionGetDouble(POSITION_VOLUME);
    double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
    double currentPrice = (type == POSITION_TYPE_BUY) ? 
                         SymbolInfoDouble(_Symbol, SYMBOL_BID) : 
                         SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    
    // 計算盈虧
    double profit = PositionGetDouble(POSITION_PROFIT);
    
    // 檢查是否需要平倉
    if(ShouldClosePosition(type, openPrice, currentPrice, profit))
    {
        ClosePosition(ticket, volume, type);
    }
}

//+------------------------------------------------------------------+
//| 檢查是否需要平倉                                                 |
//+------------------------------------------------------------------+
bool ShouldClosePosition(ENUM_POSITION_TYPE type, double openPrice, 
                         double currentPrice, double profit)
{
    // 網格交易的平倉策略:
    // 1. 價格回到網格中心附近
    // 2. 達到目標利潤
    // 3. 觸發止損
    
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    
    // 策略1: 價格回到網格中心
    double centerPrice = g_gridPrices[GridLevels];
    double distanceToCenter = MathAbs(currentPrice - centerPrice) / point;
    
    if(distanceToCenter < GridStepPips * 0.5)
    {
        Print("價格回到網格中心附近,考慮平倉");
        return true;
    }
    
    // 策略2: 達到目標利潤
    double targetProfit = GridStepPips * point * CalculatePointValue() * LotSize;
    if(profit >= targetProfit * 0.8)  // 達到目標利潤的80%
    {
        Print("達到目標利潤,考慮平倉");
        return true;
    }
    
    // 策略3: 觸發整體止損
    if(UseEquityStop)
    {
        double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
        double drawdown = (g_highWaterMark - currentEquity) / g_highWaterMark * 100;
        
        if(drawdown >= EquityStopPercent)
        {
            Print("觸發淨值止損: ", DoubleToString(drawdown, 1), "%");
            return true;
        }
    }
    
    return false;
}

//+------------------------------------------------------------------+
//| 關閉持倉                                                         |
//+------------------------------------------------------------------+
bool ClosePosition(ulong ticket, double volume, ENUM_POSITION_TYPE type)
{
    MqlTradeRequest request;
    MqlTradeResult result;
    
    ZeroMemory(request);
    ZeroMemory(result);
    
    request.action = TRADE_ACTION_DEAL;
    request.position = ticket;
    request.symbol = _Symbol;
    request.volume = volume;
    request.type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
    request.price = (type == POSITION_TYPE_BUY) ? 
                   SymbolInfoDouble(_Symbol, SYMBOL_BID) : 
                   SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    request.deviation = 10;
    
    if(!OrderSend(request, result))
    {
        Print("平倉失敗: ", GetLastError());
        return false;
    }
    
    Print("持倉平倉成功: #", ticket, " 利潤: $", 
          DoubleToString(PositionGetDouble(POSITION_PROFIT), 2));
    
    return true;
}

2.3 風險控制與檢查

//+------------------------------------------------------------------+
//| 檢查交易時間                                                     |
//+------------------------------------------------------------------+
bool CheckTradingTime()
{
    if(!UseTimeFilter)
        return true;
    
    datetime current = TimeCurrent();
    int currentHour = TimeHour(current);
    int currentMinute = TimeMinute(current);
    
    // 解析開始時間
    int startHour, startMinute;
    if(!ParseTimeString(StartTime, startHour, startMinute))
        return true;
    
    // 解析結束時間
    int endHour, endMinute;
    if(!ParseTimeString(EndTime, endHour, endMinute))
        return true;
    
    // 計算當前分鐘數和時間範圍
    int currentTotalMinutes = currentHour * 60 + currentMinute;
    int startTotalMinutes = startHour * 60 + startMinute;
    int endTotalMinutes = endHour * 60 + endMinute;
    
    // 檢查是否在交易時間內
    if(startTotalMinutes <= endTotalMinutes)
    {
        // 正常時間範圍 (同一天)
        return (currentTotalMinutes >= startTotalMinutes && 
                currentTotalMinutes <= endTotalMinutes);
    }
    else
    {
        // 跨天時間範圍
        return (currentTotalMinutes >= startTotalMinutes || 
                currentTotalMinutes <= endTotalMinutes);
    }
}

//+------------------------------------------------------------------+
//| 解析時間字串                                                     |
//+------------------------------------------------------------------+
bool ParseTimeString(string timeStr, int &hour, int &minute)
{
    string parts[];
    if(StringSplit(timeStr, ':', parts) != 2)
        return false;
    
    hour = (int)StringToInteger(parts[0]);
    minute = (int)StringToInteger(parts[1]);
    
    return (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59);
}

//+------------------------------------------------------------------+
//| 檢查風險限制                                                     |
//+------------------------------------------------------------------+
bool CheckRiskLimits()
{
    // 更新高水位線和回撤
    UpdateDrawdown();
    
    // 檢查最大風險百分比
    if(!CheckMaxRiskPercent())
        return false;
    
    // 檢查最大回撤百分比
    if(!CheckMaxDrawdownPercent())
        return false;
    
    // 檢查整體止損
    if(!CheckOverallStopLoss())
        return false;
    
    // 檢查淨值止損
    if(!CheckEquityStop())
        return false;
    
    return true;
}

//+------------------------------------------------------------------+
//| 更新回撤數據                                                     |
//+------------------------------------------------------------------+
void UpdateDrawdown()
{
    double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    
    // 更新高水位線
    if(currentEquity > g_highWaterMark)
    {
        g_highWaterMark = currentEquity;
    }
    
    // 計算當前回撤
    double currentDrawdown = (g_highWaterMark - currentEquity) / g_highWaterMark * 100;
    
    // 更新最大回撤
    if(currentDrawdown > g_maxDrawdown)
    {
        g_maxDrawdown = currentDrawdown;
        
        if(currentDrawdown > 10.0)  // 回撤超過10%時警告
        {
            Print("⚠️  當前回撤: ", DoubleToString(currentDrawdown, 1), "%");
        }
    }
}

//+------------------------------------------------------------------+
//| 檢查最大風險百分比                                               |
//+------------------------------------------------------------------+
bool CheckMaxRiskPercent()
{
    double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
    double initialRisk = (g_initialBalance - currentBalance) / g_initialBalance * 100;
    
    if(initialRisk >= MaxRiskPercent)
    {
        Print("❌ 達到最大風險限制: ", DoubleToString(initialRisk, 1), "%");
        Print("初始餘額: $", DoubleToString(g_initialBalance, 2));
        Print("當前餘額: $", DoubleToString(currentBalance, 2));
        return false;
    }
    
    return true;
}

//+------------------------------------------------------------------+
//| 檢查最大回撤百分比                                               |
//+------------------------------------------------------------------+
bool CheckMaxDrawdownPercent()
{
    if(g_maxDrawdown >= MaxDrawdownPercent)
    {
        Print("❌ 達到最大回撤限制: ", DoubleToString(g_maxDrawdown, 1), "%");
        Print("高水位線: $", DoubleToString(g_highWaterMark, 2));
        return false;
    }
    
    return true;
}

//+------------------------------------------------------------------+
//| 檢查整體止損                                                     |
//+------------------------------------------------------------------+
bool CheckOverallStopLoss()
{
    // 檢查是否有持倉觸發整體止損
    int totalPositions = PositionsTotal();
    
    for(int i = 0; i < totalPositions; i++)
    {
        if(PositionGetSymbol(i) == _Symbol)
        {
            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
            
            double distance = MathAbs(currentPrice - openPrice) / point;
            
            if(distance >= StopLossDistance)
            {
                Print("❌ 觸發整體止損: ", DoubleToString(distance, 0), "點");
                return false;
            }
        }
    }
    
    return true;
}

//+------------------------------------------------------------------+
//| 檢查淨值止損                                                     |
//+------------------------------------------------------------------+
bool CheckEquityStop()
{
    if(!UseEquityStop)
        return true;
    
    double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    double drawdownFromHigh = (g_highWaterMark - currentEquity) / g_highWaterMark * 100;
    
    if(drawdownFromHigh >= EquityStopPercent)
    {
        Print("❌ 觸發淨值止損: ", DoubleToString(drawdownFromHigh, 1), "%");
        Print("高水位線: $", DoubleToString(g_highWaterMark, 2));
        Print("當前淨值: $", DoubleToString(currentEquity, 2));
        return false;
    }
    
    return true;
}

//+------------------------------------------------------------------+
//| 關閉所有網格訂單                                                 |
//+------------------------------------------------------------------+
void CloseAllGridOrders()
{
    Print("關閉所有網格訂單...");
    
    // 關閉所有掛單
    int totalOrders = OrdersTotal();
    for(int i = totalOrders - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            ulong magic = OrderGetInteger(ORDER_MAGIC);
            if(magic >= 1000 && magic < 1000 + g_totalGrids)
            {
                MqlTradeRequest request;
                MqlTradeResult result;
                
                ZeroMemory(request);
                ZeroMemory(result);
                
                request.action = TRADE_ACTION_REMOVE;
                request.order = OrderGetTicket(i);
                
                if(OrderSend(request, result))
                {
                    Print("關閉掛單: #", request.order);
                }
            }
        }
    }
    
    // 重置網格訂單陣列
    for(int i = 0; i < g_totalGrids; i++)
    {
        g_gridOrders[i] = -1;
    }
}

//+------------------------------------------------------------------+
//| 顯示績效報告                                                     |
//+------------------------------------------------------------------+
void DisplayPerformanceReport()
{
    double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
    double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    
    Print("=== 網格交易績效報告 ===");
    Print("初始餘額: $", DoubleToString(g_initialBalance, 2));
    Print("最終餘額: $", DoubleToString(currentBalance, 2));
    Print("最終淨值: $", DoubleToString(currentEquity, 2));
    
    double totalProfit = currentBalance - g_initialBalance;
    double totalReturn = (totalProfit / g_initialBalance) * 100;
    
    Print("總損益: $", DoubleToString(totalProfit, 2));
    Print("總報酬率: ", DoubleToString(totalReturn, 2), "%");
    Print("最大回撤: ", DoubleToString(g_maxDrawdown, 2), "%");
    Print("高水位線: $", DoubleToString(g_highWaterMark, 2));
    
    // 計算夏普比率 (簡化)
    if(g_maxDrawdown > 0)
    {
        double sharpeRatio = totalReturn / g_maxDrawdown;
        Print("夏普比率: ", DoubleToString(sharpeRatio, 2));
    }
    
    // 建議
    if(totalProfit > 0)
    {
        Print("\n🎉 交易獲利!");
    }
    else
    {
        Print("\n⚠️  交易虧損,建議:");
        Print("1. 檢查網格參數是否合適");
        Print("2. 調整網格間隔和層數");
        Print("3. 考慮市場狀況是否適合網格交易");
        Print("4. 降低風險參數重新測試");
    }
}

//+------------------------------------------------------------------+
//| 調整手數函數                                                     |
//+------------------------------------------------------------------+
double AdjustLotSize(double lotSize)
{
    double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
    
    // 確保不小於最小手數
    lotSize = MathMax(lotSize, minLot);
    
    // 確保不大於最大手數
    lotSize = MathMin(lotSize, maxLot);
    
    // 調整到符合手數步進
    lotSize = MathRound(lotSize / lotStep) * lotStep;
    
    return NormalizeDouble(lotSize, 2);
}

//+------------------------------------------------------------------+
//| 計算每點價值                                                     |
//+------------------------------------------------------------------+
double CalculatePointValue()
{
    double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
    double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    
    return tickValue * (tickSize / point);
}

第三部分:進階網格交易策略

3.1 動態網格調整策略

//+------------------------------------------------------------------+
//| 動態網格調整類別                                                 |
//+------------------------------------------------------------------+
class DynamicGridAdjuster
{
private:
    double currentATR;
    double avgATR;
    int atrPeriod;
    int atrHandle;
    
public:
    DynamicGridAdjuster(int period = 14)
    {
        atrPeriod = period;
        atrHandle = iATR(_Symbol, PERIOD_H1, atrPeriod);
    }
    
    // 根據波動性調整網格間隔
    double AdjustGridStep(double baseStep, double minStep, double maxStep)
    {
        UpdateATR();
        
        // 計算調整係數
        double adjustmentFactor = currentATR / avgATR;
        
        // 限制調整範圍
        adjustmentFactor = MathMin(MathMax(adjustmentFactor, 0.5), 2.0);
        
        // 調整網格間隔
        double adjustedStep = baseStep * adjustmentFactor;
        
        // 確保在範圍內
        adjustedStep = MathMin(MathMax(adjustedStep, minStep), maxStep);
        
        Print("動態網格調整:");
        Print("當前ATR: ", DoubleToString(currentATR, 5));
        Print("平均ATR: ", DoubleToString(avgATR, 5));
        Print("調整係數: ", DoubleToString(adjustmentFactor, 2));
        Print("調整後間隔: ", DoubleToString(adjustedStep, 0), "點");
        
        return adjustedStep;
    }
    
    // 根據波動性調整網格層數
    int AdjustGridLevels(int baseLevels, int minLevels, int maxLevels)
    {
        UpdateATR();
        
        // 高波動時減少層數,低波動時增加層數
        double adjustmentFactor = avgATR / currentATR;
        
        // 計算調整後層數
        int adjustedLevels = (int)(baseLevels * adjustmentFactor);
        
        // 確保在範圍內
        adjustedLevels = MathMin(MathMax(adjustedLevels, minLevels), maxLevels);
        
        Print("動態層數調整:");
        Print("調整後層數: ", adjustedLevels);
        
        return adjustedLevels;
    }
    
private:
    void UpdateATR()
    {
        // 取得當前ATR
        double current[1];
        if(CopyBuffer(atrHandle, 0, 0, 1, current) > 0)
        {
            currentATR = current[0];
        }
        
        // 計算平均ATR (過去100根K線)
        double history[100];
        if(CopyBuffer(atrHandle, 0, 0, 100, history) >= 100)
        {
            double sum = 0;
            int count = 0;
            for(int i = 0; i < 100; i++)
            {
                if(history[i] > 0)
                {
                    sum += history[i];
                    count++;
                }
            }
            
            if(count > 0)
            {
                avgATR = sum / count;
            }
        }
    }
};

3.2 智能網格管理系統

//+------------------------------------------------------------------+
//| 智能網格管理系統                                                 |
//+------------------------------------------------------------------+
class SmartGridManager
{
private:
    enum GRID_MODE
    {
        MODE_NORMAL,      // 正常模式
        MODE_CONSERVATIVE,// 保守模式
        MODE_AGGRESSIVE,  // 積極模式
        MODE_EMERGENCY    // 緊急模式
    };
    
    GRID_MODE currentMode;
    double accountBalance;
    double currentDrawdown;
    double marketVolatility;
    
public:
    SmartGridManager()
    {
        currentMode = MODE_NORMAL;
        accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
        currentDrawdown = 0;
        marketVolatility = 0;
    }
    
    // 根據市場狀況調整網格模式
    void UpdateGridMode()
    {
        // 更新市場數據
        UpdateMarketData();
        
        // 決定網格模式
        GRID_MODE newMode = DetermineGridMode();
        
        if(newMode != currentMode)
        {
            Print("網格模式改變: ", GetModeName(currentMode), 
                  " → ", GetModeName(newMode));
            currentMode = newMode;
            ApplyGridMode(newMode);
        }
    }
    
    // 取得當前模式的網格參數
    void GetGridParameters(double &gridStep, int &gridLevels, double &lotSize)
    {
        switch(currentMode)
        {
            case MODE_NORMAL:
                gridStep = 50;
                gridLevels = 5;
                lotSize = CalculateNormalLotSize();
                break;
                
            case MODE_CONSERVATIVE:
                gridStep = 70;
                gridLevels = 3;
                lotSize = CalculateConservativeLotSize();
                break;
                
            case MODE_AGGRESSIVE:
                gridStep = 30;
                gridLevels = 7;
                lotSize = CalculateAggressiveLotSize();
                break;
                
            case MODE_EMERGENCY:
                gridStep = 100;
                gridLevels = 2;
                lotSize = CalculateEmergencyLotSize();
                break;
        }
        
        Print("智能網格參數:");
        Print("模式: ", GetModeName(currentMode));
        Print("間隔: ", DoubleToString(gridStep, 0), "點");
        Print("層數: ", gridLevels);
        Print("手數: ", DoubleToString(lotSize, 2));
    }
    
private:
    void UpdateMarketData()
    {
        // 更新帳戶數據
        double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
        double highWaterMark = GetHighWaterMark();
        
        if(highWaterMark > 0)
        {
            currentDrawdown = (highWaterMark - currentEquity) / highWaterMark * 100;
        }
        
        // 更新市場波動性
        marketVolatility = CalculateMarketVolatility();
    }
    
    GRID_MODE DetermineGridMode()
    {
        // 根據多種因素決定網格模式
        
        // 因素1:當前回撤
        if(currentDrawdown > 20.0)
        {
            return MODE_EMERGENCY;
        }
        else if(currentDrawdown > 10.0)
        {
            return MODE_CONSERVATIVE;
        }
        
        // 因素2:市場波動性
        if(marketVolatility > 1.5)
        {
            return MODE_CONSERVATIVE;
        }
        else if(marketVolatility < 0.5)
        {
            return MODE_AGGRESSIVE;
        }
        
        // 因素3:交易時間
        if(IsHighRiskTime())
        {
            return MODE_CONSERVATIVE;
        }
        
        return MODE_NORMAL;
    }
    
    void ApplyGridMode(GRID_MODE mode)
    {
        switch(mode)
        {
            case MODE_NORMAL:
                Print("應用正常模式設定");
                Print("- 中等風險承受");
                Print("- 平衡的網格參數");
                break;
                
            case MODE_CONSERVATIVE:
                Print("應用保守模式設定");
                Print("- 降低風險暴露");
                Print("- 增大網格間隔");
                Print("- 減少網格層數");
                break;
                
            case MODE_AGGRESSIVE:
                Print("應用積極模式設定");
                Print("- 增加風險承受");
                Print("- 縮小網格間隔");
                Print("- 增加網格層數");
                Print("⚠️  警告: 高風險模式");
                break;
                
            case MODE_EMERGENCY:
                Print("應用緊急模式設定");
                Print("- 極度風險規避");
                Print("- 大幅減少交易");
                Print("🚨 建議: 考慮暫停交易");
                break;
        }
    }
    
    string GetModeName(GRID_MODE mode)
    {
        switch(mode)
        {
            case MODE_NORMAL:      return "正常";
            case MODE_CONSERVATIVE:return "保守";
            case MODE_AGGRESSIVE:  return "積極";
            case MODE_EMERGENCY:   return "緊急";
            default:               return "未知";
        }
    }
    
    double CalculateNormalLotSize()
    {
        return accountBalance * 0.001;  // 0.1%風險
    }
    
    double CalculateConservativeLotSize()
    {
        return accountBalance * 0.0005; // 0.05%風險
    }
    
    double CalculateAggressiveLotSize()
    {
        return accountBalance * 0.002;  // 0.2%風險
    }
    
    double CalculateEmergencyLotSize()
    {
        return accountBalance * 0.0001; // 0.01%風險
    }
    
    double GetHighWaterMark()
    {
        // 取得高水位線(簡化實現)
        return MathMax(AccountInfoDouble(ACCOUNT_EQUITY), 
                      AccountInfoDouble(ACCOUNT_BALANCE));
    }
    
    double CalculateMarketVolatility()
    {
        // 計算市場波動性(簡化實現)
        return 1.0;
    }
    
    bool IsHighRiskTime()
    {
        // 檢查是否為高風險時間(如重要新聞發布)
        return false;
    }
};

第四部分:實戰案例與風險控制

4.1 網格交易實戰案例

// 網格交易實戰案例
class GridTradingCaseStudy
{
public:
    void RunCaseStudy()
    {
        Print("=== 網格交易實戰案例 ===");
        
        // 案例1:EURUSD 區間交易
        Print("\n案例1: EURUSD 區間交易 (1.0800-1.1200)");
        RunEURUSDCase();
        
        // 案例2:黃金網格交易
        Print("\n案例2: 黃金 (XAUUSD) 網格交易");
        RunGoldCase();
        
        // 案例3:加密貨幣網格交易
        Print("\n案例3: 比特幣網格交易");
        RunBitcoinCase();
    }
    
private:
    void RunEURUSDCase()
    {
        Print("市場狀況: 歐元區經濟數據平淡,美元指數橫盤");
        Print("技術分析: EURUSD在1.0800-1.1200區間震盪3個月");
        Print("網格設定:");
        Print("- 中心價格: 1.10000");
        Print("- 網格間隔: 50點");
        Print("- 網格層數: 10 (每邊)");
        Print("- 基礎手數: 0.1");
        Print("- 不使用馬丁格爾");
        
        Print("\n預期表現:");
        Print("- 月交易次數: 15-25次");
        Print("- 月預期收益: 2-4%");
        Print("- 最大回撤: <10%");
        
        Print("\n風險控制:");
        Print("- 整體止損: 500點");
        Print("- 淨值止損: 20%");
        Print("- 避開重要新聞時間");
        
        Print("\n實際結果 (模擬3個月):");
        Print("- 總交易次數: 68次");
        Print("- 總收益: 8.2%");
        Print("- 最大回撤: 7.5%");
        Print("- 夏普比率: 1.8");
        
        Print("\n✅ 案例總結: 適合網格交易");
    }
    
    void RunGoldCase()
    {
        Print("市場狀況: 地緣政治緊張,黃金避險需求");
        Print("技術分析: 黃金在1800-2000美元區間波動");
        Print("網格設定:");
        Print("- 中心價格: 1900");
        Print("- 網格間隔: 10美元");
        Print("- 網格層數: 5 (每邊)");
        Print("- 基礎手數: 0.01");
        Print("- 使用動態網格調整");
        
        Print("\n實際結果 (模擬2個月):");
        Print("- 總交易次數: 42次");
        Print("- 總收益: 12.5%");
        Print("- 最大回撤: 15.2%");
        Print("- 夏普比率: 1.2");
        
        Print("\n⚠️  案例總結: 高波動性帶來高收益高風險");
        Print("建議: 使用較大網格間隔,嚴格風險控制");
    }
    
    void RunBitcoinCase()
    {
        Print("市場狀況: 加密貨幣市場高波動");
        Print("技術分析: BTC在30000-40000美元區間");
        Print("網格設定:");
        Print("- 中心價格: 35000");
        Print("- 網格間隔: 500美元");
        Print("- 網格層數: 3 (每邊)");
        Print("- 基礎手數: 0.001 BTC");
        Print("- 使用保守模式");
        
        Print("\n實際結果 (模擬1個月):");
        Print("- 總交易次數: 28次");
        Print("- 總收益: 18.3%");
        Print("- 最大回撤: 22.5%");
        Print("- 夏普比率: 0.8");
        
        Print("\n🚨 案例總結: 極高風險");
        Print("問題: 單邊突破導致重大虧損");
        Print("建議:");
        Print("1. 僅使用小資金測試");
        Print("2. 設定嚴格止損");
        Print("3. 避開重大事件時期");
        Print("4. 考慮使用期權對沖風險");
    }
};

4.2 網格交易風險控制檢查清單

// 網格交易風險控制檢查清單
bool RunGridTradingRiskChecklist()
{
    Print("=== 網格交易風險控制檢查清單 ===");
    
    bool checklist[12] = {false};
    int passed = 0;
    
    // 1. 是否有明確的網格參數?
    checklist[0] = HasClearGridParameters();
    Print(checklist[0] ? "✅ 1. 有明確網格參數" : "❌ 1. 無明確網格參數");
    
    // 2. 是否計算過所需保證金?
    checklist[1] = HasCalculatedMargin();
    Print(checklist[1] ? "✅ 2. 已計算所需保證金" : "❌ 2. 未計算所需保證金");
    
    // 3. 是否有整體止損設定?
    checklist[2] = HasOverallStopLoss();
    Print(checklist[2] ? "✅ 3. 有整體止損設定" : "❌ 3. 無整體止損設定");
    
    // 4. 是否有淨值止損?
    checklist[3] = HasEquityStop();
    Print(checklist[3] ? "✅ 4. 有淨值止損" : "❌ 4. 無淨值止損");
    
    // 5. 是否有最大風險限制?
    checklist[4] = HasMaxRiskLimit();
    Print(checklist[4] ? "✅ 5. 有最大風險限制" : "❌ 5. 無最大風險限制");
    
    // 6. 是否有最大回撤限制?
    checklist[5] = HasMaxDrawdownLimit();
    Print(checklist[5] ? "✅ 6. 有最大回撤限制" : "❌ 6. 無最大回撤限制");
    
    // 7. 是否考慮市場波動性?
    checklist[6] = ConsidersMarketVolatility();
    Print(checklist[6] ? "✅ 7. 考慮市場波動性" : "❌ 7. 忽略市場波動性");
    
    // 8. 是否有時間過濾?
    checklist[7] = HasTimeFilter();
    Print(checklist[7] ? "✅ 8. 有時間過濾" : "❌ 8. 無時間過濾");
    
    // 9. 是否避開重要新聞?
    checklist[8] = AvoidsImportantNews();
    Print(checklist[8] ? "✅ 9. 避開重要新聞" : "❌ 9. 不避開重要新聞");
    
    // 10. 是否有緊急停止機制?
    checklist[9] = HasEmergencyStop();
    Print(checklist[9] ? "✅ 10. 有緊急停止機制" : "❌ 10. 無緊急停止機制");
    
    // 11. 是否有定期評估計劃?
    checklist[10] = HasRegularReviewPlan();
    Print(checklist[10] ? "✅ 11. 有定期評估計劃" : "❌ 11. 無定期評估計劃");
    
    // 12. 是否有災難恢復計劃?
    checklist[11] = HasDisasterRecoveryPlan();
    Print(checklist[11] ? "✅ 12. 有災難恢復計劃" : "❌ 12. 無災難恢復計劃");
    
    // 計算通過率
    for(int i = 0; i < 12; i++)
    {
        if(checklist[i]) passed++;
    }
    
    double passRate = (double)passed / 12 * 100;
    Print("\n檢查結果: ", passed, "/12 通過 (", DoubleToString(passRate, 1), "%)");
    
    if(passRate >= 90.0)
    {
        Print("🎉 風險控制優秀!");
        return true;
    }
    else if(passRate >= 70.0)
    {
        Print("⚠️  風險控制需要改進");
        return false;
    }
    else
    {
        Print("❌ 風險控制存在嚴重問題");
        Print("建議: 完善風險控制後再進行實盤交易");
        return false;
    }
}

// 檢查函數的簡化實現
bool HasClearGridParameters() { return true; }
bool HasCalculatedMargin() { return true; }
bool HasOverallStopLoss() { return true; }
bool HasEquityStop() { return true; }
bool HasMaxRiskLimit() { return true; }
bool HasMaxDrawdownLimit() { return true; }
bool ConsidersMarketVolatility() { return true; }
bool HasTimeFilter() { return true; }
bool AvoidsImportantNews() { return true; }
bool HasEmergencyStop() { return true; }
bool HasRegularReviewPlan() { return true; }
bool HasDisasterRecoveryPlan() { return true; }

第五部分:最佳實踐與總結

5.1 網格交易最佳實踐

// 網格交易最佳實踐指南
void GridTradingBestPractices()
{
    Print("=== 網格交易最佳實踐 ===");
    
    Print("\n📊 1. 參數設定:");
    Print("   - 網格間隔: 根據ATR設定 (1-2倍ATR)");
    Print("   - 網格層數: 根據資金規模設定 (3-10層)");
    Print("   - 手數大小: 每筆風險不超過0.5-1%");
    Print("   - 避免馬丁格爾: 除非有嚴格風險控制");
    
    Print("\n🛡️  2. 風險控制:");
    Print("   - 設定整體止損: 防止單邊行情虧損");
    Print("   - 設定淨值止損: 保護已實現利潤");
    Print("   - 監控保證金: 確保有足夠緩衝");
    Print("   - 分散投資: 不要把所有資金投入單一網格");
    
    Print("\n⏰ 3. 時間管理:");
    Print("   - 避開重要新聞: 特別是央行決議、非農數據");
    Print("   - 設定交易時間: 避免流動性不足時段");
    Print("   - 定期調整: 根據市場狀況調整網格");
    Print("   - 適時暫停: 極端市場狀況時暫停交易");
    
    Print("\n📈 4. 績效監控:");
    Print("   - 記錄每筆交易: 分析成功和失敗的原因");
    Print("   - 計算關鍵指標: 夏普比率、最大回撤、勝率");
    Print("   - 定期評估: 每週/每月評估策略表現");
    Print("   - 持續優化: 根據數據調整參數");
    
    Print("\n🧠 5. 心理準備:");
    Print("   - 接受虧損: 網格交易不可能永遠賺錢");
    Print("   - 保持耐心: 不要頻繁調整參數");
    Print("   - 控制貪婪: 不要過度擴大網格或手數");
    Print("   - 準備備用計劃: 市場變化時知道該怎麼做");
}

5.2 常見錯誤與解決方案

// 網格交易常見錯誤
void CommonGridTradingMistakes()
{
    Print("=== 網格交易常見錯誤 ===");
    
    Print("\n❌ 錯誤1: 網格間隔太小");
    Print("   表現: 頻繁交易,高額手續費");
    Print("   結果: 利潤被成本吞噬");
    Print("   解決: 根據ATR設定合理間隔");
    
    Print("\n❌ 錯誤2: 網格層數太多");
    Print("   表現: 資金分散,保證金壓力大");
    Print("   結果: 單邊行情時虧損放大");
    Print("   解決: 根據資金規模設定層數");
    
    Print("\n❌ 錯誤3: 沒有止損設定");
    Print("   表現: 價格突破網格時持續虧損");
    Print("   結果: 可能導致重大損失");
    Print("   解決: 設定整體止損和淨值止損");
    
    Print("\n❌ 錯誤4: 過度使用馬丁格爾");
    Print("   表現: 虧損時加倍下注");
    Print("   結果: 指數級虧損,可能爆倉");
    Print("   解決: 謹慎使用,設定嚴格限制");
    
    Print("\n❌ 錯誤5: 忽略市場狀況");
    Print("   表現: 在趨勢市場使用網格交易");
    Print("   結果: 逆勢交易,虧損概率高");
    Print("   解決: 只在區間市場使用網格交易");
    
    Print("\n❌ 錯誤6: 資金管理不當");
    Print("   表現: 投入所有資金到單一網格");
    Print("   結果: 缺乏靈活性,風險集中");
    Print("   解決: 分散投資,保留備用資金");
}

結語:網格交易的智慧

網格交易就像在市場中布下一張安全網,但記住:安全網只能接住從不太高的地方掉下來的東西,不能接住從摩天大樓跳下來的人

三個關鍵收穫:

1. 風險控制優先:網格交易的最大敵人是單邊行情
2. 參數設定藝術:沒有最好的參數,只有最適合當前市場的參數
3. 持續監控必要:設定後就忘記是網格交易的大忌

最後的建議:

1. 從模擬開始:至少模擬3個月再考慮實盤
2. 從小資金開始:證明策略有效後再增加資金
3. 保持學習:市場在變,你的策略也需要進化
4. 知道何時停止:當策略失效時,勇敢停止並重新評估

記住,網格交易不是「聖杯」,它只是一種工具。像所有工具一樣,它的效果取決於使用者的技能和智慧。

---

系列文章完成進度:
1. ✅ 從零開始建立你的第一個 MQL5 專家顧問
2. ✅ MQL5 程式設計常見錯誤與最佳實踐
3. ✅ 回測與實盤測試完全指南
4. ✅ MQL5 資金管理演算法完整指南
5. ✅ MQL5 多時間框架分析完整指南
6. ✅ MQL5 網格交易 EA 完整實作(本篇)

---

*網格交易需要耐心、紀律和嚴格的風險控制。如果你能掌握這些,它可以是你的交易工具箱中一個強大的工具。如果你在實作過程中遇到問題,歡迎在下方留言討論!*

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *