一键平仓 / 一键保本工具
拖到图表上立刻执行:可选全部平仓、只平盈利单、或把所有单子止损移到成本价
效果示意图 · AI 根据源码绘制
//+------------------------------------------------------------------+
//| PositionManager.mq5 |
//| 一键平仓与保本止损工具 |
//+------------------------------------------------------------------+
#property copyright "量化交易工具"
#property version "1.00"
#property script_show_inputs
#include <Trade\Trade.mqh>
//--- 操作模式枚举
enum ENUM_OPERATION_MODE
{
MODE_CLOSE_ALL = 0, // 平掉所有持仓
MODE_CLOSE_PROFIT = 1, // 只平盈利持仓
MODE_BREAKEVEN = 2 // 移动止损到保本
};
//+------------------------------------------------------------------+
//| 输入参数 |
//+------------------------------------------------------------------+
input ENUM_OPERATION_MODE InpOperationMode = MODE_CLOSE_ALL; // 操作模式
input bool InpCurrentSymbolOnly = true; // 是否只处理当前图表品种
input int InpMagicNumber = 0; // 魔术号过滤(0=不过滤)
input int InpBreakevenExtraPoints = 5; // 保本时额外留几个点利润
//--- 全局变量
CTrade trade;
int g_success_count = 0; // 成功处理的订单数
int g_fail_count = 0; // 失败的订单数
//+------------------------------------------------------------------+
//| 脚本主函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 构建确认消息
string confirm_msg = "";
switch(InpOperationMode)
{
case MODE_CLOSE_ALL:
confirm_msg = "确认要平掉所有持仓吗?";
break;
case MODE_CLOSE_PROFIT:
confirm_msg = "确认要平掉所有盈利的持仓吗?";
break;
case MODE_BREAKEVEN:
confirm_msg = "确认要将所有盈利持仓的止损移到保本价吗?";
break;
}
if(InpCurrentSymbolOnly)
confirm_msg += "\n只处理品种: " + _Symbol;
else
confirm_msg += "\n处理所有品种";
if(InpMagicNumber > 0)
confirm_msg += "\n魔术号过滤: " + IntegerToString(InpMagicNumber);
//--- 弹出确认对话框
int result = MessageBox(confirm_msg, "持仓管理工具", MB_OKCANCEL | MB_ICONQUESTION);
if(result != IDOK)
{
Print("用户取消操作");
return;
}
//--- 初始化交易对象
trade.SetExpertMagicNumber(0);
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_FOK);
trade.SetAsyncMode(false);
//--- 重置计数器
g_success_count = 0;
g_fail_count = 0;
//--- 获取持仓总数
int total_positions = PositionsTotal();
Print("==================== 开始处理持仓 ====================");
Print("当前持仓总数: ", total_positions);
//--- 从后向前遍历(防止索引变化)
for(int i = total_positions - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket <= 0)
continue;
//--- 获取持仓信息
string symbol = PositionGetString(POSITION_SYMBOL);
long magic = PositionGetInteger(POSITION_MAGIC);
double profit = PositionGetDouble(POSITION_PROFIT);
double volume = PositionGetDouble(POSITION_VOLUME);
double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
//--- 品种过滤
if(InpCurrentSymbolOnly && symbol != _Symbol)
continue;
//--- 魔术号过滤
if(InpMagicNumber > 0 && magic != InpMagicNumber)
continue;
//--- 根据模式执行操作
switch(InpOperationMode)
{
case MODE_CLOSE_ALL:
ProcessClosePosition(ticket, symbol, volume, profit);
break;
case MODE_CLOSE_PROFIT:
if(profit > 0)
ProcessClosePosition(ticket, symbol, volume, profit);
break;
case MODE_BREAKEVEN:
if(profit > 0)
ProcessBreakeven(ticket, symbol, pos_type, open_price, sl);
break;
}
}
//--- 汇总结果
Print("==================== 处理完成 ====================");
string summary = "处理完成!\n";
summary += "成功: " + IntegerToString(g_success_count) + " 单\n";
summary += "失败: " + IntegerToString(g_fail_count) + " 单";
Alert(summary);
Print(summary);
}
//+------------------------------------------------------------------+
//| 平仓处理函数 |
//+------------------------------------------------------------------+
void ProcessClosePosition(ulong ticket, string symbol, double volume, double profit)
{
Print("正在平仓 Ticket: ", ticket, " | 品种: ", symbol,
" | 手数: ", DoubleToString(volume, 2),
" | 盈亏: ", DoubleToString(profit, 2));
if(trade.PositionClose(ticket))
{
Print(" ✓ 平仓成功");
g_success_count++;
}
else
{
Print(" ✗ 平仓失败,错误码: ", GetLastError(), " - ", trade.ResultRetcodeDescription());
g_fail_count++;
}
}
//+------------------------------------------------------------------+
//| 保本止损处理函数 |
//+------------------------------------------------------------------+
void ProcessBreakeven(ulong ticket, string symbol, ENUM_POSITION_TYPE pos_type,
double open_price, double current_sl)
{
//--- 计算保本止损价格
double new_sl = 0;
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
if(pos_type == POSITION_TYPE_BUY)
{
// 买单:止损 = 开仓价 + 额外点数
new_sl = NormalizeDouble(open_price + InpBreakevenExtraPoints * point, digits);
// 如果当前止损已经比保本价高,则跳过
if(current_sl >= new_sl)
{
Print("Ticket: ", ticket, " | 当前止损已在保本价或更优,跳过");
return;
}
}
else if(pos_type == POSITION_TYPE_SELL)
{
// 卖单:止损 = 开仓价 - 额外点数
new_sl = NormalizeDouble(open_price - InpBreakevenExtraPoints * point, digits);
// 如果当前止损已经比保本价低(更优),则跳过
if(current_sl > 0 && current_sl <= new_sl)
{
Print("Ticket: ", ticket, " | 当前止损已在保本价或更优,跳过");
return;
}
}
Print("正在修改止损 Ticket: ", ticket, " | 品种: ", symbol,
" | 开仓价: ", DoubleToString(open_price, digits),
" | 原止损: ", DoubleToString(current_sl, digits),
" | 新止损: ", DoubleToString(new_sl, digits));
//--- 修改止损
double tp = PositionGetDouble(POSITION_TP);
if(trade.PositionModify(ticket, new_sl, tp))
{
Print(" ✓ 止损修改成功");
g_success_count++;
}
else
{
Print(" ✗ 止损修改失败,错误码: ", GetLastError(), " - ", trade.ResultRetcodeDescription());
g_fail_count++;
}
}
//+------------------------------------------------------------------+作品说明
思路说明
脚本启动时先弹确认框,用户同意后根据选定的模式执行:平所有仓会遍历所有持仓并平仓;平盈利仓只平当前浮盈大于 0 的;保本止损把盈利仓的止损改到开仓价加上额外点数。可按品种、魔术号过滤。每次操作都打印日志,结束后弹窗汇总成功和失败数量。
使用说明
将代码保存为 PositionManager.mq5,放入 MQL5\Scripts 文件夹,在 MetaEditor 中编译后,从导航器窗口的"脚本"列表拖到任意图表上。
- 安装方法
- 参数调整
- 操作模式:选择要执行的操作(平所有仓 / 平盈利仓 / 保本止损)
- 是否只处理当前图表品种:勾选后只处理当前图表对应的品种,不勾选则处理账户所有品种
- 魔术号过滤:设为 0 表示处理所有 EA 和手工单;填入具体数字则只处理该魔术号的订单
- 保本时额外留几个点利润:保本模式下,止损会设在开仓价加上(买单)或减去(卖单)这个点数,防止因点差被扫
拖到图表后会弹出参数设置窗口 → 调整参数后点"确定" → 弹出二次确认对话框 → 点"确定"开始执行 → 终端"专家"标签页会实时打印每单的处理结果 → 处理完成后弹窗汇总
- 操作流程
- 注意事项
- 脚本执行完即退出,不会常驻
- 平仓和修改止损都可能因网络延迟、流动性不足等原因失败,终端会显示具体错误码
- 保本模式会自动判断当前止损是否已经更优,避免重复操作
- 建议先在模拟账户测试,确认逻辑无误后再用于实盘
AI 解读根据源码逐行分析写成,供参考,以实际运行为准
这是什么
一个 MT5 脚本工具,拖到图表上立即执行批量操作。三种模式可选:平掉所有持仓、只平盈利仓、或把盈利单的止损改到成本价保本。适合需要快速批量管理仓位、避免逐单手动操作的场景。
逻辑原理
脚本启动后先弹确认框,用户同意后从后往前遍历账户所有持仓(倒序遍历防止平仓后索引错位)。根据选定的模式执行:
平所有仓:直接调用平仓函数,不管盈亏全部平掉。
平盈利仓:检查每个持仓的浮盈(POSITION_PROFIT),大于 0 才平。
保本止损:只处理浮盈大于 0 的单子。买单把止损改到开仓价加上额外点数(防止点差扫损),卖单改到开仓价减去额外点数。修改前会检查当前止损是否已经更优,避免重复操作。
每次操作都会打印日志到终端的"专家"标签页,处理完所有持仓后弹窗汇总成功和失败的数量。脚本执行完自动退出,不会常驻。
参数说明
- 操作模式(默认:平掉所有持仓):三选一,决定执行什么操作。平所有仓不管盈亏全关,平盈利仓只关浮盈大于 0 的,保本止损把盈利单的止损移到成本价。
- 是否只处理当前图表品种(默认:true):勾选后只处理当前图表对应的品种(比如在 XAUUSD 图表上只处理黄金单子),不勾选则处理账户所有品种的持仓。
- 魔术号过滤(默认:0):0 表示处理所有 EA 和手工单;填入具体数字(比如 12345)则只处理该魔术号的订单,方便多策略分开管理。
- 保本时额外留几个点利润(默认:5):保本模式专用。买单止损会设在开仓价加这个点数,卖单减这个点数,留一点缓冲防止因点差被立刻扫损。
怎么用
把代码保存为 .mq5 文件,放到 MT5 数据文件夹的 MQL5\Scripts 目录下,在 MetaEditor 里编译。然后从 MT5 主窗口左侧"导航器"的"脚本"列表里,把它拖到任意图表上。
拖上去后会弹出参数设置窗口,调整模式、品种过滤、魔术号,点确定后会再弹一次确认对话框,确认无误再点确定开始执行。终端下方"工具箱"的"专家"标签页会实时显示每单的处理结果,执行完会弹窗汇总。
脚本执行完自动退出,下次需要用再拖一次。
适用场景
适合需要快速批量平仓或统一止损管理的场景:多品种同时持仓、跑多个 EA、或者盘中突发消息需要立刻全平。保本模式适合盈利一段后锁定成本,避免回撤吃掉利润。
可以按品种和魔术号过滤,适合多策略、多品种同时运行的账户。如果只跑单一 EA 或只做一个品种,过滤功能用处不大。
不适合需要精细控制每单平仓时机的场景,脚本是批量操作,执行后无法撤销。
风险提示
不可撤销:脚本执行完就退出了,平仓操作无法撤回,确认前务必看清参数。
网络和流动性:平仓和修改止损都需要服务器确认,如果网络延迟或市场流动性差(比如非农数据、开盘跳空),可能部分订单失败。脚本会在终端打印错误码,但不会自动重试。
保本止损可能立刻触发:如果行情快速回撤,刚设好的保本止损可能马上被扫,尤其是额外点数设得太小、或点差大的品种。默认 5 点适合主流货币对,黄金、原油等波动大或点差大的品种建议加大到 10-20 点。
魔术号 0 的含义:魔术号设为 0 表示不过滤,会处理所有手工单和 EA 单。如果账户里既有手工单又有 EA 单,想只操作其中一类,务必填对魔术号。
常见问题
- 这个脚本可以设置快捷键吗?
- MT5 脚本本身不支持快捷键,但可以在图表上右键 → 脚本列表 → 选中后执行,或者把脚本拖到工具栏收藏夹方便下次快速调用。
- 保本模式会重复修改止损吗?
- 不会。代码里会判断当前止损是否已经在保本价或更优位置,如果是就跳过,避免重复操作。终端会打印"当前止损已在保本价或更优,跳过"。
- 平仓失败怎么办?
- 脚本会在终端打印具体的错误码和描述。常见原因:网络延迟、市场关闭、持仓已被其他操作平掉。脚本执行完会汇总失败数量,可以手动检查剩余持仓或重新执行一次。
- 可以用在黄金以外的品种吗?
- 可以。代码没有品种限制,所有 MT5 支持的品种都能用。保本模式的额外点数参数需要根据品种的波动和点差调整,黄金、原油等建议设大一点。
- MT4 能用吗?
- 不能直接用。这是 MQL5 代码,MT4 用的是 MQL4。逻辑类似但语法不同,需要改写成 MT4 版本。
One-Click Close & Breakeven Script for MT5
MT5 script for instant position management. Drag to chart to execute: close all positions, close only profitable ones, or move stop-loss to breakeven for all winning trades. Supports filtering by symbol and magic number.
Source code is shown above. Compiled EX5 files are available to VIP members.
基于本作的二次创作1
我需要你帮我写一个这样的指标
评论
还没有人评论,来抢个沙发。