MT5脚本 / 工具编译通过 · EX5 31KB 11 6
一键平仓 / 一键保本工具
拖到图表上立刻执行:可选全部平仓、只平盈利单、或把所有单子止损移到成本价

PositionManager.mq5211 行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//+------------------------------------------------------------------+
//| 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 和手工单;填入具体数字则只处理该魔术号的订单
- 保本时额外留几个点利润:保本模式下,止损会设在开仓价加上(买单)或减去(卖单)这个点数,防止因点差被扫
拖到图表后会弹出参数设置窗口 → 调整参数后点"确定" → 弹出二次确认对话框 → 点"确定"开始执行 → 终端"专家"标签页会实时打印每单的处理结果 → 处理完成后弹窗汇总
- 操作流程
- 注意事项
- 脚本执行完即退出,不会常驻
- 平仓和修改止损都可能因网络延迟、流动性不足等原因失败,终端会显示具体错误码
- 保本模式会自动判断当前止损是否已经更优,避免重复操作
- 建议先在模拟账户测试,确认逻辑无误后再用于实盘
评论
后可以留言,比如反馈用着怎么样、想加什么功能。
还没有人评论,来抢个沙发。