//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
input double TradeLot = 0.1; // 固定手數
input int FastMAPeriod = 12;
input int SlowMAPeriod = 26;
input ENUM_MA_METHOD MaMethod = MODE_SMA;
input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;
input int RsiPeriod = 14;
input double RsiBuyLevel = 30.0;
input double RsiSellLevel = 70.0;
input int MacdFast = 12;
input int MacdSlow = 26;
input int MacdSignal = 9;
input double StopLoss = 100; // 點數
input double TakeProfit = 200; // 固定止盈
input double TrailingStop = 80; // 移動停利點數
input int MinTradeGap = 3600; // 最小交易間隔(秒)
input ENUM_TIMEFRAMES TF = PERIOD_H1;
datetime lastTradeTime = 0;
//+------------------------------------------------------------------+
//| 指標計算(修正 MQL5 語法) |
//+------------------------------------------------------------------+
bool IsGoldenCross()
{
double fastPrev[], slowPrev[], fastCurr[], slowCurr[];
ArraySetAsSeries(fastPrev, true);
ArraySetAsSeries(slowPrev, true);
ArraySetAsSeries(fastCurr, true);
ArraySetAsSeries(slowCurr, true);
int fastMaHandle = iMA(_Symbol, TF, FastMAPeriod, 0, MaMethod, MaPrice);
int slowMaHandle = iMA(_Symbol, TF, SlowMAPeriod, 0, MaMethod, MaPrice);
CopyBuffer(fastMaHandle, 0, 1, 1, fastPrev);
CopyBuffer(slowMaHandle, 0, 1, 1, slowPrev);
CopyBuffer(fastMaHandle, 0, 0, 1, fastCurr);
CopyBuffer(slowMaHandle, 0, 0, 1, slowCurr);
return (fastPrev[0] < slowPrev[0] && fastCurr[0] > slowCurr[0]);
}
bool IsDeathCross()
{
double fastPrev[], slowPrev[], fastCurr[], slowCurr[];
ArraySetAsSeries(fastPrev, true);
ArraySetAsSeries(slowPrev, true);
ArraySetAsSeries(fastCurr, true);
ArraySetAsSeries(slowCurr, true);
int fastMaHandle = iMA(_Symbol, TF, FastMAPeriod, 0, MaMethod, MaPrice);
int slowMaHandle = iMA(_Symbol, TF, SlowMAPeriod, 0, MaMethod, MaPrice);
CopyBuffer(fastMaHandle, 0, 1, 1, fastPrev);
CopyBuffer(slowMaHandle, 0, 1, 1, slowPrev);
CopyBuffer(fastMaHandle, 0, 0, 1, fastCurr);
CopyBuffer(slowMaHandle, 0, 0, 1, slowCurr);
return (fastPrev[0] > slowPrev[0] && fastCurr[0] < slowCurr[0]);
}
bool IsMACDGoldenCross()
{
double macdPrev[], signalPrev[];
ArraySetAsSeries(macdPrev, true);
ArraySetAsSeries(signalPrev, true);
int macdHandle = iMACD(_Symbol, TF, MacdFast, MacdSlow, MacdSignal, PRICE_CLOSE);
CopyBuffer(macdHandle, 0, 0, 2, macdPrev);
CopyBuffer(macdHandle, 1, 0, 2, signalPrev);
return (macdPrev[1] < signalPrev[1] && macdPrev[0] > signalPrev[0]);
}
bool IsMACDDeathCross()
{
double macdPrev[], signalPrev[];
ArraySetAsSeries(macdPrev, true);
ArraySetAsSeries(signalPrev, true);
int macdHandle = iMACD(_Symbol, TF, MacdFast, MacdSlow, MacdSignal, PRICE_CLOSE);
CopyBuffer(macdHandle, 0, 0, 2, macdPrev);
CopyBuffer(macdHandle, 1, 0, 2, signalPrev);
return (macdPrev[1] > signalPrev[1] && macdPrev[0] < signalPrev[0]);
}
double GetRSI()
{
double rsi[];
ArraySetAsSeries(rsi, true);
int rsiHandle = iRSI(_Symbol, TF, RsiPeriod, PRICE_CLOSE);
CopyBuffer(rsiHandle, 0, 0, 1, rsi);
return rsi[0];
}
//+------------------------------------------------------------------+
//| 交易邏輯(修正 MQL5 交易函數) |
//+------------------------------------------------------------------+
void OnTick()
{
// 檢查交易間隔
if (TimeCurrent() - lastTradeTime < MinTradeGap)
return;
// 檢查持倉
bool hasBuy = PositionSelect(_Symbol) && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
bool hasSell = PositionSelect(_Symbol) && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL;
double rsi = GetRSI();
double sl = StopLoss * _Point;
double tp = TakeProfit * _Point;
// 進多單條件
if (!hasBuy && IsGoldenCross() && rsi < RsiBuyLevel && IsMACDGoldenCross())
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = TradeLot;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.sl = request.price - sl;
request.tp = request.price + tp;
request.deviation = 10;
request.comment = "Buy Order";
request.magic = 0;
if(!OrderSend(request, result))
Print("Buy Order failed, error code: ", GetLastError());
else
lastTradeTime = TimeCurrent();
}
// 進空單條件
if (!hasSell && IsDeathCross() && rsi > RsiSellLevel && IsMACDDeathCross())
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = TradeLot;
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.sl = request.price + sl;
request.tp = request.price - tp;
request.deviation = 10;
request.comment = "Sell Order";
request.magic = 0;
if(!OrderSend(request, result))
Print("Sell Order failed, error code: ", GetLastError());
else
lastTradeTime = TimeCurrent();
}
// 移動停利與出場邏輯
if (PositionSelect(_Symbol))
{
ulong ticket = PositionGetInteger(POSITION_TICKET);
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
double stopLoss = PositionGetDouble(POSITION_SL);
double profit = PositionGetDouble(POSITION_PROFIT);
// 移動停利(僅向有利方向移動)
if (TrailingStop > 0)
{
double trail = TrailingStop * _Point;
double newSL;
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
newSL = currentPrice - trail;
if (newSL > stopLoss && newSL > PositionGetDouble(POSITION_PRICE_OPEN) - sl)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.sl = newSL;
request.tp = PositionGetDouble(POSITION_TP);
if(!OrderSend(request, result))
Print("Modify SL failed, error code: ", GetLastError());
}
}
else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
newSL = currentPrice + trail;
if (newSL < stopLoss && newSL < PositionGetDouble(POSITION_PRICE_OPEN) + sl)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.sl = newSL;
request.tp = PositionGetDouble(POSITION_TP);
if(!OrderSend(request, result))
Print("Modify SL failed, error code: ", GetLastError());
}
}
}
// 強制平倉條件
bool exitBuy = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
(IsDeathCross() && profit > 0));
bool exitSell = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
(IsGoldenCross() && profit > 0));
if (exitBuy || exitSell)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.type = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
request.price = (request.type == ORDER_TYPE_SELL) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.position = ticket;
request.deviation = 10;
if(!OrderSend(request, result))
Print("Close position failed, error code: ", GetLastError());
}
}
} |