追蹤止損與保本止損 MQL5 完整實作
📌 本文重點
學習三種追蹤止損(Trailing Stop)方式:固定點數追蹤、ATR 動態追蹤、步進式追蹤,以及保本止損(Break-Even)的完整 MQL5 實作。
學習三種追蹤止損(Trailing Stop)方式:固定點數追蹤、ATR 動態追蹤、步進式追蹤,以及保本止損(Break-Even)的完整 MQL5 實作。
為什麼需要追蹤止損?
固定止損無法鎖住浮動盈利。追蹤止損讓止損跟隨價格移動,在保住已有獲利的同時,讓盈利繼續奔跑。
方法一:固定點數追蹤止損
#include <Trade\Trade.mqh>
CTrade g_trade;
input int InpTrailPoints = 30; // 追蹤點數
input int InpTrailStep = 10; // 步進點數(避免頻繁修改)
void TrailingStop()
{
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
for (int i = PositionsTotal()-1; i >= 0; i--)
{
string sym = PositionGetSymbol(i);
if (sym != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != 12345) continue;
ulong ticket = PositionGetInteger(POSITION_TICKET);
int type = (int)PositionGetInteger(POSITION_TYPE);
double curSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if (type == POSITION_TYPE_BUY)
{
double newSL = NormalizeDouble(bid - InpTrailPoints * pt, _Digits);
// 只在新止損比現有止損高且差距超過步進時才修改
if (newSL > curSL + InpTrailStep * pt)
g_trade.PositionModify(ticket, newSL, tp);
}
else if (type == POSITION_TYPE_SELL)
{
double newSL = NormalizeDouble(ask + InpTrailPoints * pt, _Digits);
if (curSL == 0 || newSL < curSL - InpTrailStep * pt)
g_trade.PositionModify(ticket, newSL, tp);
}
}
}
方法二:保本止損(Break-Even)
input int InpBreakEvenTrigger = 20; // 觸發保本的盈利點數
input int InpBreakEvenOffset = 2; // 保本後止損超過進場價的點數
void MoveToBreakEven()
{
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
for (int i = PositionsTotal()-1; i >= 0; i--)
{
if (PositionGetSymbol(i) != _Symbol) continue;
if (PositionGetInteger(POSITION_MAGIC) != 12345) continue;
ulong ticket = PositionGetInteger(POSITION_TICKET);
int type = (int)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double curSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if (type == POSITION_TYPE_BUY)
{
// 當盈利達到觸發點數,且止損還在進場價以下
double triggerPrice = openPrice + InpBreakEvenTrigger * pt;
double beStop = openPrice + InpBreakEvenOffset * pt;
if (bid >= triggerPrice && curSL < beStop)
{
if (g_trade.PositionModify(ticket, NormalizeDouble(beStop, _Digits), tp))
Print("保本止損設定 #", ticket, " @ ", beStop);
}
}
else if (type == POSITION_TYPE_SELL)
{
double triggerPrice = openPrice - InpBreakEvenTrigger * pt;
double beStop = openPrice - InpBreakEvenOffset * pt;
if (ask <= triggerPrice && (curSL == 0 || curSL > beStop))
{
if (g_trade.PositionModify(ticket, NormalizeDouble(beStop, _Digits), tp))
Print("保本止損設定 #", ticket, " @ ", beStop);
}
}
}
}
// 在 OnTick 中組合使用
void OnTick()
{
MoveToBreakEven(); // 先執行保本
TrailingStop(); // 再執行追蹤
}
方法三:階梯式(Stepped)追蹤止損
// 盈利每增加 N 點,止損跟進 N 點(階梯式)
void SteppedTrailing()
{
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int step = 25; // 每 25 點一個台階
for (int i = PositionsTotal()-1; i >= 0; i--)
{
if (PositionGetSymbol(i) != _Symbol) continue;
ulong ticket = PositionGetInteger(POSITION_TICKET);
int type = (int)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double curSL = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if (type == POSITION_TYPE_BUY)
{
// 計算已走了幾個台階
int steps = (int)((bid - openPrice) / (step * pt));
if (steps <= 0) continue;
double newSL = NormalizeDouble(openPrice + (steps-1) * step * pt, _Digits);
if (newSL > curSL)
g_trade.PositionModify(ticket, newSL, tp);
}
}
}
本文由 James Lee 撰寫。內容僅供教育目的,不構成投資建議。