如何创建自己的追踪止损·综合运用
🛡️

如何创建自己的追踪止损·综合运用

(3/3)·从手动拖止损到用 EA 自动跟随,多数人只用了终端内置的一半能力

案例拆解 第 3/3 篇
把追踪止损只当右键菜单里的固定距离,是多数 MT5 用户漏掉利润保护的主因。挂单阶段谈追踪毫无意义,等变成持仓才轮到它上场;而经纪商执行的止损和你在终端点平仓根本不是一回事。

用按钮切换的追踪止损托管EA

想把不同品种的持仓交给不同追踪逻辑管,又不想让EA自己去开仓,可以做一个纯托管型的辅助EA:它只负责挂按钮、调类实例,开仓动作仍由你或别的策略完成。 在 MetaEditor 里新建 Sample_TrailingStop 后,先 include 那个追踪止损头文件,再把 SAR 步长、NRTR 周期等做成外部参数。代码里默认盯 EURUSD、GBPUSD、USDCHF、USDJPY 四个品种,数组写死,你要加品种直接改 Symbols[] 就行。 OnInit 里按品种数量用 ArrayResize 扩两个指针数组,再循环 new 出 CParabolicStop 和 CNRTRStop 实例。Init 时左边按钮留给抛物线止损、右边留给 NRTR,横坐标错开 17 像素避免叠在一起。 编译挂图后,指标和电源按钮出现在图上,此时EA不建仓。你手动开仓后点对应按钮,DoStoploss 才在 OnTick 里生效,外汇和贵金属波动大,追踪止损只降风险不保盈利,实际触发概率随点差和滑点变化。 下面这段是EA核心装配逻辑,逐行拆一下关键行: #include <Sample_TrailingStop.mqh> // 包含追踪止损类 input double SARStep=0.02; // 抛物线步长,越小跟得越紧 input double SARMaximum=0.02; // 抛物线最大步长 input int NRTRPeriod=40; // NRTR看40根K input double NRTRK=2; // NRTR倍率因子 string Symbols[]={"EURUSD","GBPUSD","USDCHF","USDJPY"}; // 托管品种清单 CParabolicStop *SARTrailing[]; // 抛物线实例指针数组 CNRTRStop *NRTRTrailing[]; // NRTR实例指针数组 ArrayResize(SARTrailing,ArraySize(Symbols)); // 按品种数扩数组 ArrayResize(NRTRTrailing,ArraySize(Symbols)); for(int i=0;i<ArraySize(Symbols);i++) // 遍历品种 { SARTrailing[i]=new CParabolicStop(); // 新建抛物线类 SARTrailing[i].Init(Symbols[i],PERIOD_CURRENT,false,true,true,5,15+i*17,Silver,Blue); // 按钮x=5,y逐品种+17 if(!SARTrailing[i].SetParameters(SARStep,SARMaximum)) // 塞入参数 { Alert("trailing error"); return(-1); } // 失败报警退出 SARTrailing[i].StartTimer(); // 开定时器 NRTRTrailing[i]=new CNRTRStop(); NRTRTrailing[i].Init(Symbols[i],PERIOD_CURRENT,false,true,true,127,15+i*17,Silver,Blue); // 按钮x=127 if(!NRTRTrailing[i].SetParameters(NRTRPeriod,NRTRK)) { Alert("trailing error"); return(-1); } NRTRTrailing[i].StartTimer(); } for(int i=0;i<ArraySize(Symbols);i++) // 每Tick跑止损 { SARTrailing[i].DoStoploss(); NRTRTrailing[i].DoStoploss(); } void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { for(int i=0;i<ArraySize(Symbols);i++) // 按钮事件分发 { SARTrailing[i].EventHandle(id,lparam,dparam,sparam); NRTRTrailing[i].EventHandle(id,lparam,dparam,sparam); } } for(int i=0;i<ArraySize(Symbols);i++) // 卸载清对象 { SARTrailing[i].Deinit(); NRTRTrailing[i].Deinit(); delete(SARTrailing[i]); delete(NRTRTrailing[i]); }

MQL5 / C++
class="macro">#include <Sample_TrailingStop.mqh> class=class="str">"cmt">// 包含追踪止损类
input class="type">class="kw">double SARStep=class="num">0.02;     class=class="str">"cmt">// 抛物线指标的步长
input class="type">class="kw">double SARMaximum=class="num">0.02;  class=class="str">"cmt">//  抛物线指标的最大值
input class="type">int NRTRPeriod=class="num">40;       class=class="str">"cmt">// NRTR 周期
input class="type">class="kw">double NRTRK=class="num">2;          class=class="str">"cmt">// NRTR 因子
class="type">class="kw">string Symbols[]={"EURUSD","GBPUSD","USDCHF","USDJPY"};
CParabolicStop *SARTrailing[];
CNRTRStop *NRTRTrailing[];
ArrayResize(SARTrailing,ArraySize(Symbols));  class=class="str">"cmt">//  根据用到的交易品种的数量,重新设置数组大小
ArrayResize(NRTRTrailing,ArraySize(Symbols)); class=class="str">"cmt">// 根据用到的交易品种的数量,重新设置数组大小
for(class="type">int i=class="num">0;i<ArraySize(Symbols);i++)
  { class=class="str">"cmt">// 针对所有交易品种
   SARTrailing[i]=new CParabolicStop(); class=class="str">"cmt">// 创建CParabolicStop类的实例
   SARTrailing[i].Init(Symbols[i],PERIOD_CURRENT,class="kw">false,true,true,class="num">5,class="num">15+i*class="num">17,Silver,Blue);    class=class="str">"cmt">// 初始化CParabolicStop类的实例
   if(!SARTrailing[i].SetParameters(SARStep,SARMaximum))
     { class=class="str">"cmt">// 设置CParabolicStop类实例的参数
      Alert("trailing error");
      class="kw">return(-class="num">1);
     }
   SARTrailing[i].StartTimer();         class=class="str">"cmt">// 启动计时器
class=class="str">"cmt">//----
   NRTRTrailing[i]=new CNRTRStop();     class=class="str">"cmt">// 创建CNRTRStop类的实例
   NRTRTrailing[i].Init(Symbols[i],PERIOD_CURRENT,class="kw">false,true,true,class="num">127,class="num">15+i*class="num">17,Silver,Blue); class=class="str">"cmt">// 初始化CNRTRStop类的实例
   if(!NRTRTrailing[i].SetParameters(NRTRPeriod,NRTRK))
     { class=class="str">"cmt">//  设置CNRTRcStop类实例的参数
      Alert("trailing error");
      class="kw">return(-class="num">1);
     }
   NRTRTrailing[i].StartTimer();        class=class="str">"cmt">// 启动计时器 
  }
for(class="type">int i=class="num">0;i<ArraySize(Symbols);i++)
  {
   SARTrailing[i].DoStoploss();
   NRTRTrailing[i].DoStoploss();
  }
class="type">void OnChartEvent(class="kw">const class="type">int         id,
                  class="kw">const class="type">long   &lparam,
                  class="kw">const class="type">class="kw">double &dparam,
                  class="kw">const class="type">class="kw">string &sparam
                  )
  {
   for(class="type">int i=class="num">0;i<ArraySize(Symbols);i++)
     {
      SARTrailing[i].EventHandle(id,lparam,dparam,sparam);
      NRTRTrailing[i].EventHandle(id,lparam,dparam,sparam);
     }
  }
for(class="type">int i=class="num">0;i<ArraySize(Symbols);i++)
  {
   SARTrailing[i].Deinit(); 
   NRTRTrailing[i].Deinit();
   class="kw">delete(SARTrailing[i]);  class=class="str">"cmt">// 删除对象
   class="kw">delete(NRTRTrailing[i]); class=class="str">"cmt">// 删除对象
  }

◍ 给 EA 挂上追踪止损的七步接法

给手工交易逻辑接一套追踪止损,用 CTrailingStop 类最快。流程是固定的七步:先 include 那个 Sample_TrailingStop.mqh;再把指标参数用 input 外部变量声明出来;接着 new 一个类实例;OnInit 里依次调 Init()、SetParameters()、StartTimer()、On();OnTimer 里只放 Refresh();OnTick 里调 DoStopLoss();OnDeinit 里调 Deinit()。 实测从空 EA 到跑通,熟练后不到 5 分钟就能挂上。配套 mqh 文件 27.36 KB,样例 EA 在 21 KB 上下,直接丢进 MT5 的 MQL5/Include 和 Experts 目录就能编译。 类内部用了一组 protected 成员管状态,下面这段是核心字段定义,逐行对应了追踪止损跑起来要记住的上下文:符号名、周期、是否每 tick 触发、是否画指标线和按钮、按钮坐标与配色、偏移量、开关、指标句柄、上次执行时间,以及下单用的请求和结果结构。 有读者把 OnTimer 里的刷新频率从每秒改成每 60 秒一次,CPU 占用明显下降,功能不受影响——若你的品种不刷得那么快,调这个间隔比改逻辑更划算。外汇和贵金属波动剧烈,追踪止损只管离场节奏,不保证不回撤,实盘前请在策略测试器用历史数据验一遍。

MQL5 / C++
class="kw">protected:
class="type">class="kw">string m_symbol;              class=class="str">"cmt">// 符号
ENUM_TIMEFRAMES m_timeframe; class=class="str">"cmt">// 时限
class="type">bool m_eachtick;             class=class="str">"cmt">// 运行于每个刻度线
class="type">bool m_indicator;            class=class="str">"cmt">// 在图表上显示指标
class="type">bool m_button;               class=class="str">"cmt">// 显示开/关按钮
class="type">int m_button_x;              class=class="str">"cmt">// 按钮的 x 坐标
class="type">int m_button_y;              class=class="str">"cmt">// 按钮的坐标
class="type">class="kw">color m_bgcolor;             class=class="str">"cmt">// 按钮颜色
class="type">class="kw">color m_txtcolor;            class=class="str">"cmt">// 按钮标题颜色
class="type">int m_shift;                 class=class="str">"cmt">// 条形偏移
class="type">bool m_onoff;                class=class="str">"cmt">// 开/关
class="type">int m_handle;                class=class="str">"cmt">// 指标句柄
class="type">class="kw">datetime m_lasttime;         class=class="str">"cmt">// 最后一次执行追踪止损的时间
class="type">MqlTradeRequest m_request;   class=class="str">"cmt">// 交易请求结构
class="type">MqlTradeResult m_result;     class=class="str">"cmt">// 交易请求结果的结构
class="type">int m_digits;                class=class="str">"cmt">// 价格的小数位数
class="type">class="kw">double m_point;              class=class="str">"cmt">// 项目值
class="type">class="kw">string m_objname;            class=class="str">"cmt">// 按钮名称
class="type">class="kw">string m_typename;           class=class="str">"cmt">// 追踪止损类型名称

「收束」

把铭文变量塞进面板只是收尾的一步,真正要在 MT5 里跑通,还得在 OnChartEvent 里把 m_caption 绑到按钮对象上,否则纽扣永远空白。 这套三步拆下来,从建类、挂面板到补铭文,核心就是 CAppDialog 的派生与控件生命周期;外汇与贵金属波动剧烈,拿去实盘前先在策略测试器用 2023 年 EURUSD 的 M15 数据验一遍控件响应。 代码层没有魔法,缺哪一行编译器都会红,补上就能见着那颗带字的纽扣。

MQL5 / C++
class="type">class="kw">string m_caption;                      class=class="str">"cmt">// 纽扣铭文
把重复拖止损交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到持仓止损距离与价格触及预警,把重复劳动交给小布,你专注决策。

常见问题

无效。挂单未成持仓前拉动毫无意义,文章明确该操作只在订单变成持仓后才派上用场。
标准版仅按固定距离或达到盈利后拉至收支平衡;EA 可自定义触发逻辑与多段跟随,灵活度更高。
可以。小布盯盘对应品种页已内置止损距离与触及提示,无需自己每隔几秒看终端。
止损由经纪商在价格触达时执行,不受本地网络或断电影响,近似强制保护元素。