再次向各位大神求助!!!
以下是我正在嘗試編寫的MACD交易策略EA,內容一樣是通拼西湊起來了,
雖然F7時沒出現錯誤,但是回測總是不開單,想請各位大神幫忙看看有什麼問題,
主要邏輯如下:
[多單進場]
(1)MACD在零線下方時,如果出現3個波峰,連續升高,此時波峰對應的K棒,低點也連續降低
(2)下一根K棒結束時,對應的MACD柱體變短,就進多單
(3)將入場價格減掉當根K棒的ATR數字,作為止損價格
[空單進場]
(1)MACD在零線上方,如果出現3個波峰,連續降低,此時波峰對應的K棒,低點也連續降低
(2)下一根K棒結束時,對應的MACD柱體變短,就進空單
(3)將入場價格加上當根K棒的ATR數字,作為止損價格
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
CTrade trade;
// ===== Input Parameters =====
input double lotSize = 0.1; // 每次下單手數
input int macdFast = 13; // MACD 快線
input int macdSlow = 34; // MACD 慢線
input int macdSignal = 9; // MACD 訊號線
input int atrPeriod = 13; // ATR 週期
input bool UseTrailingStop = true; // 啟用追蹤止損
input double TrailingStart = 30; // 啟動追蹤的獲利(點)
input double TrailingStep = 15; // 追蹤止損距離(點)
// ===== Handles and Buffers =====
int macdHandle, atrHandle;
double macdMain[], macdSignalBuf[], macdHist[];
double atrBuf[];
datetime lastTradeTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
macdHandle = iMACD(_Symbol, PERIOD_M15, macdFast, macdSlow, macdSignal, PRICE_CLOSE);
atrHandle = iATR(_Symbol, PERIOD_M15, atrPeriod);
if(macdHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE)
{
Print("Failed to create indicator handles.");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(Period() != PERIOD_M15) return;
int barsToCheck = 50;
if(CopyBuffer(macdHandle, 0, 0, barsToCheck, macdMain) <= 0) return;
if(CopyBuffer(macdHandle, 1, 0, barsToCheck, macdSignalBuf) <= 0) return;
if(CopyBuffer(macdHandle, 2, 0, barsToCheck, macdHist) <= 0) return;
if(CopyBuffer(atrHandle, 0, 0, 3, atrBuf) <= 0) return;
// 檢查是否已有持倉
if(!PositionSelect(_Symbol))
{
// 多單機會
if(CheckBullishSignal())
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = NormalizeDouble(ask - atrBuf[1], _Digits);
trade.Buy(lotSize, _Symbol, ask, sl, 0, "MACD Buy");
lastTradeTime = TimeCurrent();
}
// 空單機會
if(CheckBearishSignal())
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = NormalizeDouble(bid + atrBuf[1], _Digits);
trade.Sell(lotSize, _Symbol, bid, sl, 0, "MACD Sell");
lastTradeTime = TimeCurrent();
}
}
else
{
// 移動止盈邏輯
CheckTrailingStop();
}
}
//+------------------------------------------------------------------+
//| 多單條件:MACD零線下方 + 柱體升高 + 低點降低 + 柱體轉弱 |
//+------------------------------------------------------------------+
bool CheckBullishSignal()
{
if(macdMain[1] > 0) return false; // MACD 主線應該在零線下方
int found = 0;
double prevPeak = -DBL_MAX;
double prevLow = DBL_MAX;
for(int i = 10; i < 30; i++)
{
if(macdHist[i] > macdHist[i-1] && macdHist[i] > macdHist[i+1])
{
double low = iLow(_Symbol, PERIOD_M15, i);
if(macdHist[i] > prevPeak && low < prevLow)
{
found++;
prevPeak = macdHist[i];
prevLow = low;
}
}
if(found >= 3)
break;
}
// 若符合條件,且柱體正在轉弱(縮短)
if(found >= 3 && macdHist[1] < macdHist[2])
return true;
return false;
}
//+------------------------------------------------------------------+
//| 空單條件:MACD零線上方 + 柱體降低 + 低點降低 + 柱體轉弱 |
//+------------------------------------------------------------------+
bool CheckBearishSignal()
{
if(macdMain[1] < 0) return false; // MACD 主線應該在零線上方
int found = 0;
double prevPeak = DBL_MAX;
double prevLow = DBL_MAX;
for(int i = 10; i < 30; i++)
{
if(macdHist[i] < macdHist[i-1] && macdHist[i] < macdHist[i+1])
{
double low = iLow(_Symbol, PERIOD_M15, i);
if(macdHist[i] < prevPeak && low < prevLow)
{
found++;
prevPeak = macdHist[i];
prevLow = low;
}
}
if(found >= 3)
break;
}
if(found >= 3 && macdHist[1] > macdHist[2])
return true;
return false;
}
//+------------------------------------------------------------------+
//| 追蹤止損功能(多空都適用) |
//+------------------------------------------------------------------+
void CheckTrailingStop()
{
if(!UseTrailingStop) return;
if(!PositionSelect(_Symbol)) return;
double point = _Point;
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
int type = (int)PositionGetInteger(POSITION_TYPE);
double price = (type == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double profitPts = (type == POSITION_TYPE_BUY) ? (price - openPrice) / point
: (openPrice - price) / point;
if(profitPts < TrailingStart) return;
double newSL = (type == POSITION_TYPE_BUY) ? price - TrailingStep * point
: price + TrailingStep * point;
if((type == POSITION_TYPE_BUY && (newSL > sl)) ||
(type == POSITION_TYPE_SELL && (newSL < sl || sl == 0.0)))
{
trade.PositionModify(_Symbol, NormalizeDouble(newSL, _Digits), 0);
}
}
|