MQL5 訂單管理完整指南:掛單、修改止損與部分平倉
📌 本文重點
完整掌握 MQL5 訂單管理:各類掛單下法、修改掛單與持倉、部分平倉技巧,以及訂單與持倉的查詢方法。
完整掌握 MQL5 訂單管理:各類掛單下法、修改掛單與持倉、部分平倉技巧,以及訂單與持倉的查詢方法。
MQL5 的訂單狀態流程
MQL5 的交易流程:掛單(Order) → 觸發後成為 持倉(Position) → 平倉後進入 歷史(History)。
各類掛單下法
#include <Trade\Trade.mqh>
CTrade g_trade;
void PlaceAllOrderTypes()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// 1. 限價買入(低於現價買)
g_trade.BuyLimit(0.1, bid - 20*pt);
// 2. 限價賣出(高於現價賣)
g_trade.SellLimit(0.1, ask + 20*pt);
// 3. 停損買入(高於現價突破買)
g_trade.BuyStop(0.1, ask + 20*pt);
// 4. 停損賣出(低於現價突破賣)
g_trade.SellStop(0.1, bid - 20*pt);
// 5. 停損限價買入(BuyStopLimit)
// 當價格達到 stop 後,在 limit 掛限價買單
double stopPrice = ask + 30*pt;
double limitPrice = ask + 20*pt;
MqlTradeRequest req={}; MqlTradeResult res={};
req.action = TRADE_ACTION_PENDING;
req.symbol = _Symbol;
req.volume = 0.1;
req.type = ORDER_TYPE_BUY_STOP_LIMIT;
req.price = stopPrice;
req.stoplimit = limitPrice;
req.magic = 12345;
OrderSend(req, res);
}
修改掛單
void ModifyPendingOrder(ulong ticket, double newPrice, double newSL = 0, double newTP = 0)
{
if (!OrderSelect(ticket)) { Print("找不到掛單 #", ticket); return; }
MqlTradeRequest req={}; MqlTradeResult res={};
req.action = TRADE_ACTION_MODIFY;
req.order = ticket;
req.price = NormalizeDouble(newPrice, _Digits);
req.sl = NormalizeDouble(newSL, _Digits);
req.tp = NormalizeDouble(newTP, _Digits);
if (!OrderSend(req, res))
Print("修改掛單失敗 #", ticket, " retcode=", res.retcode);
else
Print("掛單修改成功 #", ticket, " 新價格=", newPrice);
}
// 取消掛單
void CancelOrder(ulong ticket)
{
if (g_trade.OrderDelete(ticket))
Print("掛單取消成功 #", ticket);
}
部分平倉
// 平倉持倉的指定手數(部分平倉)
bool PartialClose(ulong ticket, double closeLots)
{
if (!PositionSelectByTicket(ticket)) return false;
int type = (int)PositionGetInteger(POSITION_TYPE);
double volume = PositionGetDouble(POSITION_VOLUME);
string sym = PositionGetString(POSITION_SYMBOL);
// 確保部分平倉手數不超過總手數
closeLots = MathMin(closeLots, volume);
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
if (closeLots < minLot) { Print("平倉手數過小"); return false; }
MqlTradeRequest req={}; MqlTradeResult res={};
req.action = TRADE_ACTION_DEAL;
req.symbol = sym;
req.volume = closeLots;
req.position = ticket;
req.type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
req.price = (req.type == ORDER_TYPE_SELL)
? SymbolInfoDouble(sym, SYMBOL_BID)
: SymbolInfoDouble(sym, SYMBOL_ASK);
req.deviation= 10;
if (OrderSend(req, res))
{
Print("部分平倉成功:", closeLots, " 手(剩餘 ", volume-closeLots, " 手)");
return true;
}
return false;
}
// 實用場景:到達第一目標時平掉一半
void ManagePartialTP()
{
for (int i = PositionsTotal()-1; i >= 0; i--)
{
if (PositionGetSymbol(i) != _Symbol) continue;
ulong ticket = PositionGetInteger(POSITION_TICKET);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double volume = PositionGetDouble(POSITION_VOLUME);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// 當盈利達到 30 點,平倉一半
if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
if (bid >= openPrice + 30*pt && volume >= 0.02)
PartialClose(ticket, NormalizeDouble(volume/2, 2));
}
}
}
本文由 James Lee 撰寫。內容僅供教育目的,不構成投資建議。