# 免费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 | 修改止损时允许的滑点(点) |
移动止损工作原理
举例 – 买单:
价格上涨时:
止损只会向前移动,从不后退,随着价格向有利方向移动锁定利润。
步长参数的作用:
使用场景示例
场景一:保护黄金多单
场景二:仅作用于EA订单
场景三:监控所有持仓
自定义修改示例
改为触发时平仓(而非移动止损)
将修改部分的代码替换为:
```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库的折扣权限。
参考来源:
```