






















9.确保工具栏中的 "自动交易 "按钮已启用(绿色) 10.
//+------------------------------------------------------------------+ //| 一键关闭所有仓位 - 专业交易面板.mq5 | //| 最最最棒的男孩 | //| WeChat:34373430 | //+------------------------------------------------------------------+ #property copyright "最最最棒的男孩" #property link "WeChat:34373430" #property version "1.00" #property description "一键关闭所有仓位 - 专业交易面板" //--- 输入参数(可在MT5界面直接修改,无需改代码) input ENUM_BASE_CORNER PanelCorner = CORNER_LEFT_UPPER; // 面板显示的角落位置(默认左上) input int PanelX = 10; // 面板X轴偏移距离(像素) input int PanelY = 50; // 面板Y轴偏移距离(像素) input color PanelBackgroundColor = clrDarkSlateGray; // 面板背景颜色(深石板灰) input color ButtonColorClose = clrCrimson; // 总平仓按钮颜色(深红色) input color ButtonColorProfit = clrForestGreen; // 平仓盈利单按钮颜色(森林绿) input color ButtonColorLoss = clrOrangeRed; // 平仓亏损单按钮颜色(橙红) input color TextColor = clrWhite; // 面板文字颜色(白色) //--- 全局变量(面板样式配置,统一管理便于修改) string prefix = "OCA_"; // 所有图表对象的前缀(避免和其他EA/指标命名冲突) int panelWidth = 280; // 面板总宽度(像素) int panelHeight = 380; // 面板总高度(像素) int buttonHeight = 35; // 按钮高度(像素) int buttonSpacing = 5; // 按钮之间的间距(像素) //+------------------------------------------------------------------+ //| EA初始化函数(EA加载时执行一次,核心做初始化校验和面板创建) | //+------------------------------------------------------------------+ int OnInit() { // 第一步:删除已存在的同名面板对象(避免重复创建导致界面混乱) DeleteAllObjects(); // 第二步:校验1 - 检查终端是否开启算法交易(MT5全局开关) if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { Alert("ERROR: 终端算法交易已禁用!请在 工具->选项->智能交易 中开启"); Print("ERROR: 终端算法交易已禁用!"); } // 第三步:校验2 - 检查当前EA是否开启自动交易(工具栏AutoTrading按钮) if(!MQLInfoInteger(MQL_TRADE_ALLOWED)) { Alert("ERROR: 自动交易已禁用!请点击工具栏的'自动交易'按钮开启"); Print("ERROR: 当前EA的自动交易权限已禁用!"); } // 第四步:创建可视化面板(按钮、文字、背景) CreatePanel(); // 第五步:初始化持仓信息显示(首次加载时刷新数据) UpdatePositionInfo(); // 打印初始化日志(便于排查问题) Print("=== 一键平仓面板EA初始化完成 ==="); Print("账户号: ", AccountInfoInteger(ACCOUNT_LOGIN)); Print("当前图表品种: ", _Symbol); Print("初始持仓数量: ", PositionsTotal()); return(INIT_SUCCEEDED); // 返回初始化成功 } //+------------------------------------------------------------------+ //| EA卸载函数(EA移除/图表关闭/终端退出时执行) | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // 仅当不是"图表切换"原因时,删除面板对象(避免切换图表误删) if(reason != REASON_CHARTCHANGE) DeleteAllObjects(); } //+------------------------------------------------------------------+ //| 行情Tick函数(每收到一次行情数据执行一次) | //+------------------------------------------------------------------+ void OnTick() { // 实时更新持仓信息(盈亏、数量),保证面板数据和实际持仓一致 UpdatePositionInfo(); } //+------------------------------------------------------------------+ //| 图表事件处理函数(监听鼠标点击、键盘操作等交互事件) | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // 事件类型ID const long &lparam, // 长整型参数(暂未使用) const double &dparam, // 浮点型参数(暂未使用) const string &sparam) // 字符串参数(点击的对象名称) { // 仅处理"对象点击"事件(按钮点击属于此类) if(id == CHARTEVENT_OBJECT_CLICK) { // 1. 点击"平仓所有"按钮 if(sparam == prefix + "BtnCloseAll") { // 重置按钮状态(避免点击后一直高亮) ObjectSetInteger(0, sparam, OBJPROP_STATE, false); // 弹窗确认(显示总盈亏,防止误操作) if(MessageBox("确认平仓所有持仓?\n\n总盈亏: " + DoubleToString(GetTotalProfit(), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓", MB_YESNO | MB_ICONQUESTION) == IDYES) { // 用户点击"是",执行平仓所有 CloseAllPositions(); } } // 2. 点击"平仓所有多单"按钮 else if(sparam == prefix + "BtnCloseBuy") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); if(MessageBox("确认平仓所有多单?\n\n多单盈亏: " + DoubleToString(GetProfitByType(POSITION_TYPE_BUY), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓多单", MB_YESNO | MB_ICONQUESTION) == IDYES) { ClosePositionsByType(POSITION_TYPE_BUY); } } // 3. 点击"平仓所有空单"按钮 else if(sparam == prefix + "BtnCloseSell") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); if(MessageBox("确认平仓所有空单?\n\n空单盈亏: " + DoubleToString(GetProfitByType(POSITION_TYPE_SELL), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓空单", MB_YESNO | MB_ICONQUESTION) == IDYES) { ClosePositionsByType(POSITION_TYPE_SELL); } } // 4. 点击"平仓当前品种所有持仓"按钮 else if(sparam == prefix + "BtnCloseSymbol") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); if(MessageBox("确认平仓" + _Symbol + "的所有持仓?\n\n该品种盈亏: " + DoubleToString(GetProfitBySymbol(_Symbol), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓当前品种", MB_YESNO | MB_ICONQUESTION) == IDYES) { ClosePositionsBySymbol(_Symbol); } } // 5. 点击"平仓所有盈利单"按钮 else if(sparam == prefix + "BtnCloseProfit") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); if(MessageBox("确认平仓所有盈利持仓?\n\n盈利总额: " + DoubleToString(GetProfitablePositionsProfit(), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓盈利单", MB_YESNO | MB_ICONQUESTION) == IDYES) { ClosePositionsByProfit(true); } } // 6. 点击"平仓所有亏损单"按钮 else if(sparam == prefix + "BtnCloseLoss") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); if(MessageBox("确认平仓所有亏损持仓?\n\n亏损总额: " + DoubleToString(GetLosingPositionsProfit(), 2) + " " + AccountInfoString(ACCOUNT_CURRENCY), "确认平仓亏损单", MB_YESNO | MB_ICONQUESTION) == IDYES) { ClosePositionsByProfit(false); } } // 7. 点击"移除面板"按钮 else if(sparam == prefix + "BtnClose") { ObjectSetInteger(0, sparam, OBJPROP_STATE, false); ExpertRemove(); // 卸载当前EA(自动触发OnDeinit删除面板) } // 延迟100ms(避免高频操作导致终端卡顿) Sleep(100); // 平仓后刷新持仓信息 UpdatePositionInfo(); // 强制重绘图表(保证界面实时更新) ChartRedraw(0); } } //+------------------------------------------------------------------+ //| 创建可视化面板(背景、标题、文字、按钮) | //+------------------------------------------------------------------+ void CreatePanel() { // 1. 创建面板背景(矩形) CreateRectangle(prefix + "Background", PanelX, PanelY, panelWidth, panelHeight, PanelBackgroundColor); // 2. 创建面板标题 CreateLabel(prefix + "Title", PanelX + 10, PanelY + 10, "一键平仓面板", TextColor, 11, "Arial Bold"); // 3. 创建持仓信息标签(初始值为0,后续UpdatePositionInfo更新) CreateLabel(prefix + "InfoPositions", PanelX + 10, PanelY + 40, "持仓数量: 0", TextColor, 9, "Arial"); CreateLabel(prefix + "InfoProfit", PanelX + 10, PanelY + 60, "总盈亏: 0.00", TextColor, 9, "Arial"); CreateLabel(prefix + "InfoBuy", PanelX + 10, PanelY + 80, "多单: 0 | 盈亏: 0.00", TextColor, 9, "Arial"); CreateLabel(prefix + "InfoSell", PanelX + 10, PanelY + 100, "空单: 0 | 盈亏: 0.00", TextColor, 9, "Arial"); // 4. 创建分隔线(视觉区分信息区和按钮区) CreateRectangle(prefix + "Separator", PanelX + 10, PanelY + 125, panelWidth - 20, 1, clrGray); // 5. 创建功能按钮(按位置依次排列) int btnY = PanelY + 135; // 第一个按钮的Y轴起始位置 // 5.1 平仓所有按钮 CreateButton(prefix + "BtnCloseAll", PanelX + 10, btnY, panelWidth - 20, buttonHeight, "平仓所有持仓", ButtonColorClose); // 5.2 多单/空单平仓按钮(左右并排) btnY += buttonHeight + buttonSpacing; // 按钮Y轴位置下移(高度+间距) CreateButton(prefix + "BtnCloseBuy", PanelX + 10, btnY, (panelWidth - 25) / 2, buttonHeight, "平仓多单", clrDodgerBlue); CreateButton(prefix + "BtnCloseSell", PanelX + 15 + (panelWidth - 25) / 2, btnY, (panelWidth - 25) / 2, buttonHeight, "平仓空单", clrTomato); // 5.3 平仓当前品种按钮 btnY += buttonHeight + buttonSpacing; CreateButton(prefix + "BtnCloseSymbol", PanelX + 10, btnY, panelWidth - 20, buttonHeight, "平仓" + _Symbol, clrSlateBlue); // 5.4 平仓盈利单按钮 btnY += buttonHeight + buttonSpacing; CreateButton(prefix + "BtnCloseProfit", PanelX + 10, btnY, panelWidth - 20, buttonHeight, "平仓盈利持仓", ButtonColorProfit); // 5.5 平仓亏损单按钮 btnY += buttonHeight + buttonSpacing; CreateButton(prefix + "BtnCloseLoss", PanelX + 10, btnY, panelWidth - 20, buttonHeight, "平仓亏损持仓", ButtonColorLoss); // 5.6 移除面板按钮 btnY += buttonHeight + buttonSpacing + 10; // 额外加10像素间距,视觉更美观 CreateButton(prefix + "BtnClose", PanelX + 10, btnY, panelWidth - 20, 30, "✖ 移除面板", clrDimGray); // 强制重绘图表(确保面板立即显示) ChartRedraw(0); } //+------------------------------------------------------------------+ //| 更新持仓信息(实时计算并刷新面板文字显示) | //+------------------------------------------------------------------+ void UpdatePositionInfo() { // 1. 获取核心持仓数据 int totalPositions = PositionsTotal(); // 总持仓数量 double totalProfit = GetTotalProfit(); // 总盈亏(含手续费/隔夜利息) int buyCount = CountPositionsByType(POSITION_TYPE_BUY); // 多单数量 int sellCount = CountPositionsByType(POSITION_TYPE_SELL); // 空单数量 double buyProfit = GetProfitByType(POSITION_TYPE_BUY); // 多单盈亏 double sellProfit = GetProfitByType(POSITION_TYPE_SELL); // 空单盈亏 string currency = AccountInfoString(ACCOUNT_CURRENCY); // 账户货币(如USD、CNY) // 2. 更新"持仓数量"标签 ObjectSetString(0, prefix + "InfoPositions", OBJPROP_TEXT, "持仓数量: " + IntegerToString(totalPositions)); // 3. 更新"总盈亏"标签(盈亏为正显示绿色,负显示红色) string profitText = "总盈亏: " + DoubleToString(totalProfit, 2) + " " + currency; color profitColor = totalProfit >= 0 ? clrLime : clrRed; ObjectSetString(0, prefix + "InfoProfit", OBJPROP_TEXT, profitText); ObjectSetInteger(0, prefix + "InfoProfit", OBJPROP_COLOR, profitColor); // 4. 更新"多单信息"标签(盈亏颜色区分) ObjectSetString(0, prefix + "InfoBuy", OBJPROP_TEXT, "多单: " + IntegerToString(buyCount) + " | 盈亏: " + DoubleToString(buyProfit, 2) + " " + currency); ObjectSetInteger(0, prefix + "InfoBuy", OBJPROP_COLOR, buyProfit >= 0 ? clrLightGreen : clrLightCoral); // 5. 更新"空单信息"标签(盈亏颜色区分) ObjectSetString(0, prefix + "InfoSell", OBJPROP_TEXT, "空单: " + IntegerToString(sellCount) + " | 盈亏: " + DoubleToString(sellProfit, 2) + " " + currency); ObjectSetInteger(0, prefix + "InfoSell", OBJPROP_COLOR, sellProfit >= 0 ? clrLightGreen : clrLightCoral); } //+------------------------------------------------------------------+ //| 平仓所有持仓 | //+------------------------------------------------------------------+ void CloseAllPositions() { int total = PositionsTotal(); // 获取总持仓数 int closed = 0; // 成功平仓数量 int failed = 0; // 平仓失败数量 Print("开始尝试平仓 ", total, " 个持仓..."); // 遍历持仓(从后往前遍历,避免删除持仓后索引错乱) for(int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); // 获取持仓单号(唯一标识) if(ticket > 0) // 持仓单号有效(>0表示存在) { // 调用底层平仓函数,成功则closed+1,失败则failed+1 if(ClosePosition(ticket)) closed++; else failed++; Sleep(100); // 每平仓一个持仓延迟100ms(避免高频请求被经纪商拒绝) } } // 生成平仓结果提示(弹窗+日志) string message = "已平仓 " + IntegerToString(closed) + " / " + IntegerToString(total) + " 个持仓"; if(failed > 0) message += "(" + IntegerToString(failed) + " 个平仓失败)"; Alert(message); // 弹窗提示用户 Print(message); // 打印日志(便于排查失败原因) } //+------------------------------------------------------------------+ //| 按类型平仓(多单/空单) | //+------------------------------------------------------------------+ void ClosePositionsByType(ENUM_POSITION_TYPE type) { int total = PositionsTotal(); int closed = 0; int failed = 0; // 转换类型为文字(便于日志/提示) string typeName = type == POSITION_TYPE_BUY ? "多单" : "空单"; Print("开始尝试平仓所有", typeName, "..."); // 遍历持仓,仅平仓指定类型 for(int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); // 持仓有效 + 类型匹配 if(ticket > 0 && PositionGetInteger(POSITION_TYPE) == type) { if(ClosePosition(ticket)) closed++; else failed++; Sleep(100); } } string message = "已平仓 " + IntegerToString(closed) + " 个" + typeName; if(failed > 0) message += "(" + IntegerToString(failed) + " 个平仓失败)"; Alert(message); Print(message); } //+------------------------------------------------------------------+ //| 按品种平仓(仅平指定品种的持仓) | //+------------------------------------------------------------------+ void ClosePositionsBySymbol(string symbol) { int total = PositionsTotal(); int closed = 0; int failed = 0; Print("开始尝试平仓", symbol, "的所有持仓..."); // 遍历持仓,仅平仓指定品种 for(int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); // 持仓有效 + 品种匹配 if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == symbol) { if(ClosePosition(ticket)) closed++; else failed++; Sleep(100); } } string message = "已平仓 " + IntegerToString(closed) + " 个" + symbol + "持仓"; if(failed > 0) message += "(" + IntegerToString(failed) + " 个平仓失败)"; Alert(message); Print(message); } //+------------------------------------------------------------------+ //| 按盈亏平仓(仅平盈利单/仅平亏损单) | //+------------------------------------------------------------------+ void ClosePositionsByProfit(bool closeProfitable) { int total = PositionsTotal(); int closed = 0; int failed = 0; // 转换类型为文字 string typeName = closeProfitable ? "盈利单" : "亏损单"; Print("开始尝试平仓所有", typeName, "..."); // 遍历持仓,仅平仓指定盈亏类型 for(int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket > 0) { // 持仓总盈亏 = 平仓盈亏 + 隔夜利息(Swap) double profit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); // 盈利单:profit>0;亏损单:profit<0(等于0的持仓不处理) if((closeProfitable && profit > 0) || (!closeProfitable && profit < 0)) { if(ClosePosition(ticket)) closed++; else failed++; Sleep(100); } } } string message = "已平仓 " + IntegerToString(closed) + " 个" + typeName; if(failed > 0) message += "(" + IntegerToString(failed) + " 个平仓失败)"; Alert(message); Print(message); } //+------------------------------------------------------------------+ //| 底层平仓函数(单持仓平仓核心逻辑,适配不同经纪商成交规则) | //+------------------------------------------------------------------+ bool ClosePosition(ulong ticket) { Print("=== 开始平仓持仓 #", ticket, " ==="); // 第一步:校验持仓是否存在(避免平仓已关闭的持仓) if(!PositionSelectByTicket(ticket)) { Print("ERROR: 持仓单号 ", ticket, " 不存在或已平仓"); return false; } // 第二步:获取持仓详细信息(用于构造平仓请求) string symbol = PositionGetString(POSITION_SYMBOL); // 持仓品种 double volume = PositionGetDouble(POSITION_VOLUME); // 持仓手数 ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // 持仓类型(多/空) ulong magic = PositionGetInteger(POSITION_MAGIC); // 魔术号(EA标识) double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); // 开仓价格 double currentProfit = PositionGetDouble(POSITION_PROFIT); // 当前盈亏 // 打印持仓详情(便于排查问题) Print("持仓详情: 品种=", symbol, " 手数=", volume, " 类型=", EnumToString(posType), " 开仓价=", openPrice, " 当前盈亏=", currentProfit); // 第三步:校验品种是否允许交易(避免平停牌/禁止交易的品种) if(!SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE)) { Print("ERROR: 品种", symbol, "当前禁止交易"); return false; } // 第四步:构造平仓请求(MQL5标准交易请求结构体) MqlTradeRequest request; // 交易请求 MqlTradeResult result; // 交易结果 ZeroMemory(request); // 初始化请求(清空内存) ZeroMemory(result); // 初始化结果 request.action = TRADE_ACTION_DEAL; // 交易动作:直接成交(平仓) request.position = ticket; // 要平仓的持仓单号 request.symbol = symbol; // 品种 request.volume = volume; // 平仓手数(和持仓一致) request.deviation = 50; // 滑点容忍度(50点,适配波动大的品种) request.magic = magic; // 魔术号(和持仓一致) // 获取品种的成交模式(FOK/IOC/RETURN,不同经纪商支持不同) int filling = (int)SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE); // 第五步:设置平仓订单类型(多单平空,空单平多) if(posType == POSITION_TYPE_BUY) { request.type = ORDER_TYPE_SELL; // 多单平仓=卖出 request.price = SymbolInfoDouble(symbol, SYMBOL_BID); // 平仓价格=买价(BID) } else { request.type = ORDER_TYPE_BUY; // 空单平仓=买入 request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); // 平仓价格=卖价(ASK) } Print("平仓订单: 类型=", EnumToString(request.type), " 价格=", request.price); // 第六步:尝试不同成交模式(提高平仓成功率,适配不同经纪商) // 模式1:FOK(全部成交否则取消) if(filling && SYMBOL_FILLING_FOK) { request.type_filling = ORDER_FILLING_FOK; Print("尝试FOK成交模式..."); if(OrderSend(request, result)) { if(result.retcode == TRADE_RETCODE_DONE) { Print("SUCCESS: 持仓", ticket, "通过FOK模式平仓成功"); return true; } } Print("FOK模式失败: 错误码=", result.retcode, " - 原因=", result.comment); } // 模式2:IOC(立即成交可成交部分,剩余取消) if(filling && SYMBOL_FILLING_IOC) { request.type_filling = ORDER_FILLING_IOC; Print("尝试IOC成交模式..."); if(OrderSend(request, result)) { if(result.retcode == TRADE_RETCODE_DONE) { Print("SUCCESS: 持仓", ticket, "通过IOC模式平仓成功"); return true; } } Print("IOC模式失败: 错误码=", result.retcode, " - 原因=", result.comment); } // 模式3:RETURN(默认模式,失败则返回) request.type_filling = ORDER_FILLING_RETURN; Print("尝试RETURN成交模式..."); if(OrderSend(request, result)) { if(result.retcode == TRADE_RETCODE_DONE) { Print("SUCCESS: 持仓", ticket, "通过RETURN模式平仓成功"); return true; } } // 第七步:平仓失败,打印详细错误信息(便于排查) Print("FAILED: 持仓", ticket, "平仓失败"); Print("最终错误: 错误码=", result.retcode, " - 原因=", result.comment); Print("系统错误码: ", GetLastError()); // 错误码解析(快速定位问题) switch(result.retcode) { case TRADE_RETCODE_INVALID: Print("问题诊断: 请求参数无效"); break; case TRADE_RETCODE_INVALID_VOLUME: Print("问题诊断: 平仓手数无效(如超过品种最小/最大手数)"); break; case TRADE_RETCODE_INVALID_PRICE: Print("问题诊断: 平仓价格无效(如超出品种价格范围)"); break; case TRADE_RETCODE_INVALID_STOPS: Print("问题诊断: 止损/止盈无效(此处平仓无止损,可忽略)"); break; case TRADE_RETCODE_TRADE_DISABLED: Print("问题诊断: 终端/品种交易已禁用"); break; case TRADE_RETCODE_MARKET_CLOSED: Print("问题诊断: 品种市场已收盘(如非交易时间)"); break; case TRADE_RETCODE_NO_MONEY: Print("问题诊断: 账户资金不足(如保证金不够)"); break; case TRADE_RETCODE_PRICE_CHANGED: Print("问题诊断: 价格已变化(滑点超出容忍度,需重新请求)"); break; case TRADE_RETCODE_REJECT: Print("问题诊断: 经纪商拒绝请求(需联系经纪商)"); break; case TRADE_RETCODE_ERROR: Print("问题诊断: 通用错误(终端/网络问题)"); break; default: Print("问题诊断: 未知错误码"); } return false; // 平仓失败 } //+------------------------------------------------------------------+ //| 获取所有持仓的总盈亏(含Swap隔夜利息) | //+------------------------------------------------------------------+ double GetTotalProfit() { double profit = 0; // 遍历所有持仓,累加盈亏 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0) profit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); } return profit; } //+------------------------------------------------------------------+ //| 按类型获取盈亏(多单/空单) | //+------------------------------------------------------------------+ double GetProfitByType(ENUM_POSITION_TYPE type) { double profit = 0; // 遍历持仓,仅累加指定类型的盈亏 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0 && PositionGetInteger(POSITION_TYPE) == type) profit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); } return profit; } //+------------------------------------------------------------------+ //| 按品种获取盈亏 | //+------------------------------------------------------------------+ double GetProfitBySymbol(string symbol) { double profit = 0; // 遍历持仓,仅累加指定品种的盈亏 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0 && PositionGetString(POSITION_SYMBOL) == symbol) profit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); } return profit; } //+------------------------------------------------------------------+ //| 按类型统计持仓数量(多单/空单) | //+------------------------------------------------------------------+ int CountPositionsByType(ENUM_POSITION_TYPE type) { int count = 0; // 遍历持仓,仅统计指定类型的数量 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0 && PositionGetInteger(POSITION_TYPE) == type) count++; } return count; } //+------------------------------------------------------------------+ //| 获取所有盈利持仓的总盈利额 | //+------------------------------------------------------------------+ double GetProfitablePositionsProfit() { double profit = 0; // 遍历持仓,仅累加盈利单(profit>0)的盈亏 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0) { double posProfit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); if(posProfit > 0) profit += posProfit; } } return profit; } //+------------------------------------------------------------------+ //| 获取所有亏损持仓的总亏损额 | //+------------------------------------------------------------------+ double GetLosingPositionsProfit() { double profit = 0; // 遍历持仓,仅累加亏损单(profit<0)的盈亏 for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetTicket(i) > 0) { double posProfit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP); if(posProfit < 0) profit += posProfit; } } return profit; } //+------------------------------------------------------------------+ //| 创建按钮(封装重复逻辑,便于批量创建) | //+------------------------------------------------------------------+ void CreateButton(string name, int x, int y, int width, int height, string text, color clr) { // 创建按钮对象(OBJ_BUTTON为MQL5按钮类型) ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0); // 设置按钮锚点(和面板一致) ObjectSetInteger(0, name, OBJPROP_CORNER, PanelCorner); // 设置按钮位置(X/Y偏移) ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); // 设置按钮尺寸(宽/高) ObjectSetInteger(0, name, OBJPROP_XSIZE, width); ObjectSetInteger(0, name, OBJPROP_YSIZE, height); // 设置按钮文字 ObjectSetString(0, name, OBJPROP_TEXT, text); // 设置文字颜色 ObjectSetInteger(0, name, OBJPROP_COLOR, TextColor); // 设置按钮背景色 ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clr); // 设置按钮边框颜色(黑色) ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrBlack); // 设置文字大小 ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9); // 设置文字字体(粗体Arial) ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold"); } //+------------------------------------------------------------------+ //| 创建文字标签(封装重复逻辑) | //+------------------------------------------------------------------+ void CreateLabel(string name, int x, int y, string text, color clr, int size, string font) { // 创建文字标签对象(OBJ_LABEL为MQL5文字类型) ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); // 设置锚点 ObjectSetInteger(0, name, OBJPROP_CORNER, PanelCorner); // 设置位置 ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); // 设置文字内容 ObjectSetString(0, name, OBJPROP_TEXT, text); // 设置文字颜色 ObjectSetInteger(0, name, OBJPROP_COLOR, clr); // 设置文字大小 ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size); // 设置字体 ObjectSetString(0, name, OBJPROP_FONT, font); } //+------------------------------------------------------------------+ //| 创建矩形(用于面板背景/分隔线) | //+------------------------------------------------------------------+ void CreateRectangle(string name, int x, int y, int width, int height, color clr) { // 创建矩形对象(OBJ_RECTANGLE_LABEL为带背景的矩形) ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); // 设置锚点 ObjectSetInteger(0, name, OBJPROP_CORNER, PanelCorner); // 设置位置 ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); // 设置尺寸 ObjectSetInteger(0, name, OBJPROP_XSIZE, width); ObjectSetInteger(0, name, OBJPROP_YSIZE, height); // 设置背景色 ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clr); // 设置边框样式(扁平) ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT); // 设置边框颜色(黑色) ObjectSetInteger(0, name, OBJPROP_COLOR, clrBlack); } //+------------------------------------------------------------------+ //| 删除所有面板对象(避免残留) | //+------------------------------------------------------------------+ void DeleteAllObjects() { // 删除所有以prefix为前缀的对象(精准删除当前EA创建的面板) ObjectsDeleteAll(0, prefix); // 强制重绘图表(立即生效) ChartRedraw(0); } //+------------------------------------------------------------------+ // ===================== 扩展运用方式 ===================== /** * 1. 基础部署使用 * - 步骤1:将代码保存为OneClickCloseAll.mq5,放入MT5的MQL5/Experts目录; * - 步骤2:在MT5中编译代码(F7),确保无报错; * - 步骤3:将EA拖到任意品种图表,在EA设置中调整面板位置/颜色,勾选"允许自动交易"; * - 步骤4:点击面板按钮即可按条件平仓,所有操作有弹窗确认+日志记录。 * * 2. 功能扩展方向(二次开发) * - 扩展1:按魔术号平仓(新增按钮+函数,筛选PositionGetInteger(POSITION_MAGIC) == 指定魔术号); * - 扩展2:按盈亏比例平仓(如平仓盈亏>10%的持仓,修改ClosePositionsByProfit的判断条件); * - 扩展3:批量平仓指定品种(新增输入参数,支持输入多个品种,遍历平仓); * - 扩展4:添加平仓确认密码(防止误操作,在MessageBox后增加密码输入校验); * - 扩展5:自动平仓(如亏损超过X金额自动平仓,在OnTick中添加判断逻辑)。 * * 3. 注意事项 * - 务必开启MT5的"算法交易"和"自动交易"开关,否则无法平仓; * - 滑点参数(deviation=50)可根据品种调整(如外汇默认50,加密货币可设100); * - 平仓失败时查看MT5日志(终端->专家),根据错误码排查问题(如经纪商禁用FOK/IOC模式); * - 建议先在模拟账户测试,确认功能正常后再用于实盘。 */
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。