【工具EA·带源码】手机下单自动挂止盈止损 AutoSLTP(MT4/MT5 通用)
手机下单最常见的坑:急着进场,忘了或来不及挂止盈止损,结果行情一反手,一张没挂保护的单能吃掉你一大块利润。这个小 EA 就干一件事:你手机/手动下的单,它自动按你设好的距离,替你把止盈止损补上。
一套源码 MT4、MT5 都能用,纯 ASCII,附件直接下。
⚠️ 先说清楚:这是 EA,得有一台一直开机的电脑或 VPS 挂着它才管用,电脑关了它就停。 只用手机、或电脑会关机的,先往下看"必读"那节再决定要不要用。 它做什么
挂到图表上后,它盯着这个账户的持仓——包括你用手机 App 下的单(只要是同一个账户就能看到):
- 你 4569 进多,设了 TP 偏移 10、SL 偏移 10 → 它自动给这单挂上 止盈 4579、止损 4559;
- 偏移你自己设(按价格距离,黄金 10 = $10 = 1000 点);哪个设成 0 就是不挂那一项(只想要止损、不要止盈,把 TP 设 0 即可);
- 按开仓价算,不是现价——你 4569 进的,TP 就是 4569±偏移,和当前价无关。
⭐三个让它"不添乱"的设计
- 只在"你没设"时才补,已经设好的绝不动。 你手动挂了止损没挂止盈,它只补止盈,你的止损原样保留;两个都挂好了,它完全不碰这单。(想让它强制覆盖,把 Overwrite 改 true,默认不覆盖。)
- 只管你手动/手机下的单(FilterMagic=0),不碰其它 EA 开的单,和你别的策略互不干扰。(注:手动/手机单的 magic 通常是 0;如果你某个 EA 也用 magic=0,那它的单也会被一起管,这种情况把 FilterMagic 改成别的值避开。)
- 默认管全账户所有品种(AllSymbols=true),你手机下黄金、下外汇都一起照顾;只想管一个品种就设 false。
参数
| 参数 | 默认 | 说明 | | TPOffset | 10 | 止盈距开仓价(价格距离);0 = 不挂止盈 | | SLOffset | 10 | 止损距开仓价(价格距离);0 = 不挂止损 | | FilterMagic | 0 | 只管这个 magic 的单(0 = 手动/手机单);-1 = 全部 | | AllSymbols | true | true = 管全账户所有品种;false = 只管当前图表品种 | | Overwrite | false | false = 只在没设时才补;true = 强制按开仓价覆盖 | | RefreshMs | 500 | 多久扫一次(毫秒) |
⚠️⚠️ 必读:它必须挂在"一直开机"的电脑或服务器上
这是 EA,不是手机 App 里的功能。它要靠一个开着 MT4/MT5 的终端在后台运行才生效:
- 推荐用 VPS(服务器):24 小时在线,你人不在、手机在外面下单,它照样第一时间帮你补止盈止损;
- 没有 VPS、只用自己电脑的: 只有「电脑开着 + MT4/MT5 开着 + 允许自动交易」这三条同时满足时它才工作。你一关机、一关 MT4,它立刻停 —— 之后手机下的单不会再被自动挂止损。别以为关了电脑它还在替你盯盘。
一句话:要它真正"永远在帮你兜底",就得有个不关机的地方(VPS)挂着。 只用个人电脑的,记得"电脑关=保护停"。
装法
- 把 AutoSLTP.mq4(MT4)或 AutoSLTP.mq5(MT5)放进 MQL4/Experts(或 MQL5/Experts);
- MetaEditor 里 F7 编译(0 错误);
- 拖到任意一个图表上,勾允许自动交易;顶部"自动交易"按钮要是绿的;
- 之后你手机随便下单,不挂止盈止损,它半秒内自动补上。
一点说明
- 偏移单位是价格(黄金 10 = $10)。若你的品种小数位不同(比如外汇),按该品种的价格来填距离;
- 如果偏移设得太小、离现价比经纪商最小止损距离还近,经纪商会拒绝,EA 会在日志里提示"level too close",这时把偏移设大一点即可;
- MT5 净持仓(netting)账户:同品种加仓会合并成一张单、开仓价变成均价,而本 EA 只在"没设过"时挂一次、不会按新均价重挂——经常加仓的朋友这点自己留意(对冲/MT4 每单独立则无此问题);
- 源码开放,逻辑就几十行,能读能改,欢迎自己按需魔改。
完整源码(复制即用,免扣活跃度)
不想下载扣活跃度的,直接复制下面这份,存成 .mq4(给 MT4)或 .mq5(给 MT5),放进 Experts 编译即可——两个平台同一份代码,靠 #ifdef __MQL5__ 自动分平台:
- //+------------------------------------------------------------------+
- //| AutoSLTP (MT4 + MT5, one source via #ifdef) |
- //| Attach to a chart. When a position appears on this account |
- //| (incl. orders you place by hand from the phone), it auto-sets a |
- //| fixed TP and/or SL at a chosen price distance from the ENTRY. |
- //| BUY entry E: TP = E + TPOffset , SL = E - SLOffset |
- //| SELL entry E: TP = E - TPOffset , SL = E + SLOffset |
- //| Offset unit = PRICE (for gold 10 = $10 = 1000 points). 0 = skip. |
- //| MT5: compile as .mq5. MT4: save the SAME content as .mq4. |
- //+------------------------------------------------------------------+
- #property strict
- #property version "1.00"
-
- #ifdef __MQL5__
- #include <Trade/Trade.mqh>
- CTrade trade;
- #endif
-
- input double TPOffset = 10.0; // TP distance from entry, in price (0 = do NOT set TP)
- input double SLOffset = 10.0; // SL distance from entry, in price (0 = do NOT set SL)
- input int FilterMagic= 0; // only touch this magic (0 = manual/phone orders). -1 = all
- input bool AllSymbols = true; // true = manage every symbol; false = only this chart symbol
- input bool Overwrite = false; // false = only set when SL/TP empty; true = always enforce
- input int RefreshMs = 500; // scan interval (ms)
-
- int OnInit()
- {
- #ifdef __MQL5__
- trade.SetDeviationInPoints(30);
- #endif
- EventSetMillisecondTimer(RefreshMs > 100 ? RefreshMs : 100);
- Scan();
- return(INIT_SUCCEEDED);
- }
- void OnDeinit(const int reason) { EventKillTimer(); Comment(""); }
- void OnTimer() { Scan(); }
-
- double Rnd(string sym, double px)
- {
- #ifdef __MQL5__
- int dg = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
- #else
- int dg = (int)MarketInfo(sym, MODE_DIGITS);
- #endif
- return NormalizeDouble(px, dg);
- }
- double MinStopDist(string sym)
- {
- #ifdef __MQL5__
- long lvl = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
- double pt = SymbolInfoDouble(sym, SYMBOL_POINT);
- return (double)lvl * pt;
- #else
- return MarketInfo(sym, MODE_STOPLEVEL) * MarketInfo(sym, MODE_POINT);
- #endif
- }
- double SymPx(string sym, bool wantBid)
- {
- #ifdef __MQL5__
- return SymbolInfoDouble(sym, wantBid ? SYMBOL_BID : SYMBOL_ASK);
- #else
- return MarketInfo(sym, wantBid ? MODE_BID : MODE_ASK);
- #endif
- }
- bool Plan(string sym, int dir, double entry, double curSL, double curTP,
- double &newSL, double &newTP)
- {
- newSL = curSL; newTP = curTP;
- if(TPOffset > 0.0 && (Overwrite || curTP == 0.0))
- newTP = Rnd(sym, (dir == 0) ? entry + TPOffset : entry - TPOffset);
- if(SLOffset > 0.0 && (Overwrite || curSL == 0.0))
- newSL = Rnd(sym, (dir == 0) ? entry - SLOffset : entry + SLOffset);
- return (MathAbs(newSL - curSL) > _Point || MathAbs(newTP - curTP) > _Point);
- }
- bool FarEnough(string sym, int dir, double lvlPrice)
- {
- if(lvlPrice == 0.0) return true;
- double md = MinStopDist(sym);
- double ref = (dir == 0) ? SymPx(sym, true) : SymPx(sym, false);
- return MathAbs(ref - lvlPrice) >= md;
- }
- void Scan()
- {
- int applied = 0, watched = 0;
- #ifdef __MQL5__
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong tk = PositionGetTicket(i);
- if(tk == 0 || !PositionSelectByTicket(tk)) continue;
- string sym = PositionGetString(POSITION_SYMBOL);
- if(!AllSymbols && sym != _Symbol) continue;
- if(FilterMagic >= 0 && PositionGetInteger(POSITION_MAGIC) != FilterMagic) continue;
- long ty = PositionGetInteger(POSITION_TYPE);
- if(ty != POSITION_TYPE_BUY && ty != POSITION_TYPE_SELL) continue;
- int dir = (ty == POSITION_TYPE_BUY) ? 0 : 1;
- double entry = PositionGetDouble(POSITION_PRICE_OPEN);
- double curSL = PositionGetDouble(POSITION_SL), curTP = PositionGetDouble(POSITION_TP);
- watched++;
- double nSL, nTP;
- if(!Plan(sym, dir, entry, curSL, curTP, nSL, nTP)) continue;
- if(!FarEnough(sym, dir, nSL) || !FarEnough(sym, dir, nTP))
- { Print("AutoSLTP: level too close for #", tk, " - skipped"); continue; }
- if(trade.PositionModify(tk, nSL, nTP)) applied++;
- else Print("AutoSLTP: modify fail #", tk, " ret=", trade.ResultRetcode());
- }
- #else
- for(int i = OrdersTotal() - 1; i >= 0; i--)
- {
- if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
- string sym = OrderSymbol();
- if(!AllSymbols && sym != _Symbol) continue;
- if(FilterMagic >= 0 && OrderMagicNumber() != FilterMagic) continue;
- int type = OrderType();
- if(type != OP_BUY && type != OP_SELL) continue;
- int dir = (type == OP_BUY) ? 0 : 1;
- double entry = OrderOpenPrice();
- double curSL = OrderStopLoss(), curTP = OrderTakeProfit();
- watched++;
- double nSL, nTP;
- if(!Plan(sym, dir, entry, curSL, curTP, nSL, nTP)) continue;
- if(!FarEnough(sym, dir, nSL) || !FarEnough(sym, dir, nTP))
- { Print("AutoSLTP: level too close for #", OrderTicket(), " - skipped"); continue; }
- if(OrderModify(OrderTicket(), OrderOpenPrice(), nSL, nTP, 0, clrNONE)) applied++;
- else Print("AutoSLTP: modify fail #", OrderTicket(), " err=", GetLastError());
- }
- #endif
- Comment("AutoSLTP TP+", DoubleToString(TPOffset, 2), " SL-", DoubleToString(SLOffset, 2),
- " magic=", FilterMagic, (AllSymbols ? " allSym" : " thisSym"),
- " watched=", watched, " justSet=", applied);
- }
- //+------------------------------------------------------------------+
复制代码 或者直接下附件(懒得复制的)
拉到本帖末尾下文件(下载扣 5 活跃度,不想扣就复制上面的代码):MT4 下
AutoSLTP.mq4
(5.94 KB, 下载次数: 0)
|