Summary: 免费MT4脚本,自动为持仓单设置移动止损。含完整MQL4源码,可自定义跟踪距离、步长和品种过滤。轻量高效,安装即用。




# 免费MT4移动止损脚本 – 完整MQL4源码(自动跟踪止损)

脚本功能说明



手工管理移动止损既繁琐又容易出错。这个MT4脚本会自动随着价格向有利方向移动而调整止损位。一旦在持仓单上激活,它会持续监控价格,并根据你设置的参数将止损位向上(买单)或向下(卖单)移动。

这是一个脚本而不是EA——你在图表上运行一次,它就会持续工作直到你平仓或移除脚本。

核心功能



| 功能 | 说明 |
| :--- | :--- |
| 自动跟踪止损 | 止损位跟随价格自动移动,无需人工干预 |
| 可调跟踪距离 | 以点数设置止损距离(如当前价格后方30点) |
| 步长锁定 | 设置最小移动步长,避免频繁修改订单 |
| 品种过滤 | 可选择仅作用于当前图表品种或全部品种 |
| 魔术号过滤 | 仅影响指定魔术号的订单(EA友好) |
| 轻量高效 | 极低的CPU占用 |

完整MQL4源码



复制下方完整代码,保存为 `TrailingStop.mq4` 至 `MQL4/Scripts/` 文件夹,然后编译。

```cpp
//+------------------------------------------------------------------+
//| TrailingStop.mq4 |
//| 自主编译 |
//| |
//+------------------------------------------------------------------+
#property copyright "ForexEA博客"
#property link ""
#property version "1.00"
#property strict
#property show_inputs

//--- 输入参数
input double TrailingStopPips = 30; // 移动止损距离(点)
input double TrailingStepPips = 10; // 最小移动步长(点)
input bool ApplyToAllSymbols = false; // 应用到所有品种?
input int MagicFilter = 0; // 魔术号过滤(0=全部)
input bool CloseOnReverse = false; // 触发时平仓?
input int Slippage = 3; // 修改订单滑点

//--- 全局变量
double pip_size;
string symbol_target;

//+------------------------------------------------------------------+
//| 脚本启动函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 获取当前品种的点值
symbol_target = _Symbol;
pip_size = GetPipSize(symbol_target);

if(pip_size == 0)
{
Print("错误:无法确定 ", symbol_target, " 的点值");
return;
}

Print("移动止损脚本已启动,品种:", symbol_target);
Print("跟踪距离:", TrailingStopPips, " 点");
Print("步长:", TrailingStepPips, " 点");

//--- 主循环
while(!IsStopped())
{
TraverseOpenPositions();
Sleep(500); // 每500毫秒检查一次
}
}

//+------------------------------------------------------------------+
//| 获取指定品种的点值 |
//+------------------------------------------------------------------+
double GetPipSize(string symbol)
{
double point_value = MarketInfo(symbol, MODE_POINT);
double digits = MarketInfo(symbol, MODE_DIGITS);

//--- 标准点值计算
if(digits == 3 || digits == 5)
return point_value * 10;
else
return point_value;
}

//+------------------------------------------------------------------+
//| 遍历所有持仓并应用移动止损 |
//+------------------------------------------------------------------+
void TraverseOpenPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
continue;

//--- 按品种过滤
if(!ApplyToAllSymbols && OrderSymbol() != symbol_target)
continue;

//--- 按魔术号过滤
if(MagicFilter != 0 && OrderMagicNumber() != MagicFilter)
continue;

//--- 根据订单类型处理
if(OrderType() == OP_BUY)
ProcessBuyPosition();
else if(OrderType() == OP_SELL)
ProcessSellPosition();
}
}

//+------------------------------------------------------------------+
//| 处理买单移动止损 |
//+------------------------------------------------------------------+
void ProcessBuyPosition()
{
double current_stop = OrderStopLoss();
double current_price = MarketInfo(OrderSymbol(), MODE_BID);
double new_stop = current_price - TrailingStopPips * pip_size;

//--- 四舍五入到正确小数位
int digits = (int)MarketInfo(OrderSymbol(), MODE_DIGITS);
new_stop = NormalizeDouble(new_stop, digits);

//--- 判断是否需要更新止损
bool should_update = false;

if(current_stop == 0)
{
//--- 无止损,设置初始移动止损
should_update = true;
}
else
{
//--- 仅当新止损高于当前止损+步长时才更新
if(new_stop > current_stop + TrailingStepPips * pip_size)
should_update = true;
}

if(should_update && new_stop < current_price)
{
bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), new_stop, OrderTakeProfit(), 0, clrNONE);
if(modified)
{
Print("买单 #", OrderTicket(), " 移动止损已更新 - 新止损:", DoubleToString(new_stop, digits));
}
else
{
Print("修改订单 #", OrderTicket(), " 失败 - 错误码:", GetLastError());
}
}
}

//+------------------------------------------------------------------+
//| 处理卖单移动止损 |
//+------------------------------------------------------------------+
void ProcessSellPosition()
{
double current_stop = OrderStopLoss();
double current_price = MarketInfo(OrderSymbol(), MODE_ASK);
double new_stop = current_price + TrailingStopPips * pip_size;

//--- 四舍五入到正确小数位
int digits = (int)MarketInfo(OrderSymbol(), MODE_DIGITS);
new_stop = NormalizeDouble(new_stop, digits);

//--- 判断是否需要更新止损
bool should_update = false;

if(current_stop == 0)
{
should_update = true;
}
else
{
if(new_stop < current_stop - TrailingStepPips * pip_size)
should_update = true;
}

if(should_update && new_stop > current_price)
{
bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), new_stop, OrderTakeProfit(), 0, clrNONE);
if(modified)
{
Print("卖单 #", OrderTicket(), " 移动止损已更新 - 新止损:", DoubleToString(new_stop, digits));
}
else
{
Print("修改订单 #", OrderTicket(), " 失败 - 错误码:", GetLastError());
}
}
}

//+------------------------------------------------------------------+
//| 脚本退出函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("移动止损脚本已停止。原因代码:", reason);
}
//+------------------------------------------------------------------+
```

安装步骤



第1步: 复制上方完整代码
第2步: 打开MT4 → 文件 → 打开数据文件夹 → MQL4 → Scripts
第3步: 新建文件 `TrailingStop.mq4`
第4步: 粘贴代码,按F7编译
第5步: 编译成功后在导航器 → 脚本中找到
第6步: 将脚本拖拽到有持仓单的图表上
第7步: 在弹出的窗口中设置参数,点击确定

参数详解



| 参数 | 默认值 | 说明 |
| :--- | :--- | :--- |
| `TrailingStopPips` | 30 | 止损位于当前价格后方的距离(点) |
| `TrailingStepPips` | 10 | 触发移动止损所需的最小价格变动(点) |
| `ApplyToAllSymbols` | false | true=所有品种,false=仅当前图表品种 |
| `MagicFilter` | 0 | 仅影响此魔术号的订单(0=全部) |
| `CloseOnReverse` | false | 预留扩展功能 |
| `Slippage` | 3 | 修改止损时允许的滑点(点) |

移动止损工作原理



举例 – 买单:
  • 入场价:1.10000

  • TrailingStopPips:30点

  • 初始止损:1.09700(入场价下方30点)


  • 价格上涨时:
  • 价格涨到1.10300 → 新止损:1.10000(保本)

  • 价格涨到1.10600 → 新止损:1.10300(后方30点)

  • 价格涨到1.11000 → 新止损:1.10700


  • 止损只会向前移动,从不后退,随着价格向有利方向移动锁定利润。

    步长参数的作用:
  • TrailingStepPips = 10 表示只有当价格比上次止损位置多移动了至少10点时,脚本才会移动止损

  • 这可以防止频繁修改订单,降低CPU占用


  • 使用场景示例



    场景一:保护黄金多单


  • 在XAUUSD开一个买单

  • 将脚本拖到XAUUSD图表

  • 设置 `TrailingStopPips = 50`(黄金波动大)

  • 设置 `TrailingStepPips = 15`

  • 脚本会在价格后方50点跟踪止损,每15点移动一次


  • 场景二:仅作用于EA订单


  • 你的EA使用魔术号 `12345`

  • 设置 `MagicFilter = 12345`

  • 脚本只会影响EA开的订单,不影响手工单


  • 场景三:监控所有持仓


  • 设置 `ApplyToAllSymbols = true`

  • 脚本在任何图表上运行,管理所有品种的所有持仓


  • 自定义修改示例



    改为触发时平仓(而非移动止损)



    将修改部分的代码替换为:

    ```cpp
    if(should_update)
    {
    bool closed = OrderClose(OrderTicket(), OrderLots(),
    MarketInfo(OrderSymbol(), MODE_BID), Slippage, clrNONE);
    if(closed)
    Print("移动止损触发,订单已平仓");
    }
    ```

    添加移动止损时的声音提醒



    在成功修改订单后添加:

    ```cpp
    PlaySound("alert.wav");
    Alert("订单 #", OrderTicket(), " 移动止损已触发");
    ```

    常见问题



    | 问题 | 解决方法 |
    | :--- | :--- |
    | 脚本没有反应 | 确认当前图表上有持仓单 |
    | 止损不移动 | 检查价格是否已超过TrailingStepPips设定的步长 |
    | 编译报错 | 确认文件扩展名是 `.mq4`,不是 `.txt` |
    | 脚本几秒后就停止 | 脚本默认只执行一次。本脚本含while循环会持续运行——请确认你是作为脚本拖入,而非EA |

    重要提示



    1. 脚本持续运行 – 普通脚本执行一次就会退出。本脚本包含 `while(!IsStopped())` 循环来保持运行。如需停止,右键图表 → 智能交易系统 → 移除,或点击脚本属性中的“停止”按钮。

    2. 风险提示 – 移动止损不能保证盈利。在快速波动的市场中,滑点可能导致成交价劣于预期。

    3. 经纪商限制 – 部分经纪商要求最小止损距离。如果将 `TrailingStopPips` 设置过小,修改可能失败(错误码130 – 无效止损)。

    ---

    想要更多黄金和外汇交易的专业脚本和EA? [订阅我们的资讯] 即可每周获取免费工具,并享受付费EA库的折扣权限。

    参考来源:
  • MQL4官方文档 – OrderModify()函数 (docs.mql4.com)

  • 自主编译测试于MT4 Build 1420+

  • ```