找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
首页论坛EAHub 外汇论坛
查看: 18|回复: 0

【AutoSLTP工具EA·带源码】手机下单自动挂止盈止损 AutoSLTP(MT4/MT5通用)

[复制链接]

4万

主题

54

回帖

4万

积分

管理员

积分
45954
发表于 2026-8-27 20:27:00 | 显示全部楼层 |阅读模式
【工具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。

参数

参数默认说明TPOffset10止盈距开仓价(价格距离);0 = 不挂止盈SLOffset10止损距开仓价(价格距离);0 = 不挂止损FilterMagic0只管这个 magic 的单(0 = 手动/手机单);-1 = 全部AllSymbolstruetrue = 管全账户所有品种;false = 只管当前图表品种Overwritefalsefalse = 只在没设时才补;true = 强制按开仓价覆盖RefreshMs500多久扫一次(毫秒)⚠️⚠️ 必读:它必须挂在"一直开机"的电脑或服务器上

这是 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 下、MT5 下 。两个文件和上面代码是同一份。

有问题评论区聊。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|EAHub外汇论坛

GMT+8, 2026-10-9 22:36 , Processed in 0.113996 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表