移动止盈EA源码分享:可以固定,可以ATR,多元移动止盈!

//+------------------------------------------------------------------+//| TrailingEA.mq4 |//| 移动止盈EA v1.0 |//| Created by Assistant |//+------------------------------------------------------------------+#property copyright "Assistant"#property link ""#property version "1.0"#property description "移动止盈功能EA,支持多种止盈策略"#property strict//+------------------------------------------------------------------+//| 枚举定义 |//+------------------------------------------------------------------+enum ENUM_TRAILING_TYPE{TRAILING_FIXED, // 固定距离TRAILING_ATR_BASED, // 基于ATRTRAILING_CHANDELIER, // 吊灯止损TRAILING_PARABOLIC // 抛物线SAR};//+------------------------------------------------------------------+//| 输入参数 |//+------------------------------------------------------------------+input group "移动止盈设置"input bool EnableTrailingStop = true; // 启用移动止盈input int TrailingStart = 50; // 启动点数(盈利达到此点数后启动)input int TrailingStep = 10; // 移动步长(点数)input group "止盈策略选择"input ENUM_TRAILING_TYPE TrailingType = TRAILING_FIXED; // 移动止盈策略input group "ATR设置(ATR策略使用)"input int ATR_Period = 14; // ATR周期input double ATR_Multiplier = 2.0; // ATR乘数input group "吊灯止损设置"input int ChandelierPeriod = 22; // 计算周期input double ChandelierMultiplier = 3.0; // 吊灯乘数input group "通用设置"input int MagicNumber = 12345; // 魔术码input bool UseSoundAlert = true; // 使用声音提示input color TrailingLineColor = clrBlue; // 移动止盈线颜色//+------------------------------------------------------------------+//| 全局变量 |//+------------------------------------------------------------------+string EAName = "移动止盈EA";datetime LastCheckTime = 0;int TrailingLineID = 0;bool g_EnableTrailingStop; // 用于修改的全局变量//+------------------------------------------------------------------+//| EA初始化函数 |//+------------------------------------------------------------------+intOnInit(){// 初始化EAEAName = "移动止盈EA v1.0";// 初始化全局变量g_EnableTrailingStop = EnableTrailingStop;// 创建界面对象CreateControls();// 设置定时器每5秒检查一次EventSetTimer(5);Print(EAName + " 初始化成功");Comment(EAName + " 已启动\n移动止盈: " + (g_EnableTrailingStop ? "启用" : "禁用"));return(INIT_SUCCEEDED);}//+------------------------------------------------------------------+//| EA去初始化函数 |//+------------------------------------------------------------------+voidOnDeinit(constint reason){// 删除界面对象DeleteControls();// 删除定时器EventKillTimer();// 删除图形对象ObjectDelete(0, "TrailingLine");Print(EAName + " 已停止");Comment("");}//+------------------------------------------------------------------+//| EA订单处理函数 |//+------------------------------------------------------------------+voidOnTick(){// 每5秒检查一次,避免过于频繁if(TimeCurrent() - LastCheckTime < 5) return;LastCheckTime = TimeCurrent();// 如果移动止盈启用,处理所有订单if(g_EnableTrailingStop){ProcessTrailingStop();}// 更新界面显示UpdateDisplay();}//+------------------------------------------------------------------+//| 定时器事件 |//+------------------------------------------------------------------+voidOnTimer(){// 更新界面信息UpdateDisplay();}//+------------------------------------------------------------------+//| 处理移动止盈逻辑 |//+------------------------------------------------------------------+voidProcessTrailingStop(){double newStopLoss;for(int i = OrdersTotal() - 1; i >= 0; i--){if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){// 只处理当前品种和指定魔术码的订单if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber){// 检查是否达到启动条件if(CheckTrailingStart(OrderTicket())){// 根据策略计算新的止损位newStopLoss = CalculateNewStopLoss(OrderTicket());// 验证止损位是否有效if(IsValidStopLoss(OrderTicket(), newStopLoss)){// 修改订单止损位ModifyOrderStopLoss(OrderTicket(), newStopLoss);}}}}}}//+------------------------------------------------------------------+//| 检查是否达到移动止盈启动条件 |//+------------------------------------------------------------------+boolCheckTrailingStart(int ticket){if(!OrderSelect(ticket, SELECT_BY_TICKET)) return false;double currentProfit;double openPrice = OrderOpenPrice();double currentPrice;if(OrderType() == OP_BUY){currentPrice = Bid;currentProfit = (currentPrice - openPrice) / Point;}else if(OrderType() == OP_SELL){currentPrice = Ask;currentProfit = (openPrice - currentPrice) / Point;}else{return false;}// 检查盈利是否达到启动点数if(currentProfit >= TrailingStart){return true;}return false;}//+------------------------------------------------------------------+//| 计算新的止损位 |//+------------------------------------------------------------------+doubleCalculateNewStopLoss(int ticket){if(!OrderSelect(ticket, SELECT_BY_TICKET)) return 0;double newStopLoss = 0;double currentPrice;if(OrderType() == OP_BUY){currentPrice = Bid;switch(TrailingType){case TRAILING_FIXED:newStopLoss = currentPrice - TrailingStep * Point;break;case TRAILING_ATR_BASED:{double atrValue = iATR(Symbol(), 0, ATR_Period, 0);newStopLoss = currentPrice - atrValue * ATR_Multiplier;break;}case TRAILING_CHANDELIER:newStopLoss = CalculateChandelierExit(ticket, true);break;case TRAILING_PARABOLIC:{double sarValue = iSAR(Symbol(), 0, 0.02, 0.2, 0);newStopLoss = MathMax(sarValue, OrderStopLoss());break;}}// 确保新止损不低于当前止损if(newStopLoss > OrderStopLoss() || OrderStopLoss() == 0){return newStopLoss;}}else if(OrderType() == OP_SELL){currentPrice = Ask;switch(TrailingType){case TRAILING_FIXED:newStopLoss = currentPrice + TrailingStep * Point;break;case TRAILING_ATR_BASED:{double atrValue = iATR(Symbol(), 0, ATR_Period, 0);newStopLoss = currentPrice + atrValue * ATR_Multiplier;break;}case TRAILING_CHANDELIER:newStopLoss = CalculateChandelierExit(ticket, false);break;case TRAILING_PARABOLIC:{double sarValue = iSAR(Symbol(), 0, 0.02, 0.2, 0);newStopLoss = MathMin(sarValue, OrderStopLoss());break;}}// 确保新止损不高于当前止损if((newStopLoss < OrderStopLoss() && newStopLoss > 0) || OrderStopLoss() == 0){return newStopLoss;}}return OrderStopLoss();}//+------------------------------------------------------------------+//| 计算吊灯止损退出点 |//+------------------------------------------------------------------+doubleCalculateChandelierExit(int ticket, bool isBuyOrder){if(!OrderSelect(ticket, SELECT_BY_TICKET)) return 0;double highestHigh = High[iHighest(Symbol(), 0, MODE_HIGH, ChandelierPeriod, 0)];double lowestLow = Low[iLowest(Symbol(), 0, MODE_LOW, ChandelierPeriod, 0)];double atrValue = iATR(Symbol(), 0, ChandelierPeriod, 0);if(isBuyOrder){return highestHigh - (atrValue * ChandelierMultiplier);}else{return lowestLow + (atrValue * ChandelierMultiplier);}}//+------------------------------------------------------------------+//| 验证止损位是否有效 |//+------------------------------------------------------------------+boolIsValidStopLoss(int ticket, double newStopLoss){if(!OrderSelect(ticket, SELECT_BY_TICKET)) return false;// 检查止损位与当前价格的距离double minDistance = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;double distance = MathAbs(currentPrice - newStopLoss);if(distance < minDistance){Print("止损距离太小: ", distance, " 最小要求: ", minDistance);return false;}return true;}//+------------------------------------------------------------------+//| 修改订单止损位 |//+------------------------------------------------------------------+boolModifyOrderStopLoss(int ticket, double newStopLoss){if(!OrderSelect(ticket, SELECT_BY_TICKET)) return false;// 如果新止损与当前止损相同,不修改if(MathAbs(newStopLoss - OrderStopLoss()) < Point * 0.5){return false;}bool result = OrderModify(ticket, OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, 0);if(result && UseSoundAlert){Alert("订单 #", ticket, " 止损已修改为: ", DoubleToString(newStopLoss, Digits));}// 在图表上绘制止损线DrawStopLossLine(newStopLoss, OrderType());return result;}//+------------------------------------------------------------------+//| 绘制止损线 |//+------------------------------------------------------------------+voidDrawStopLossLine(double price, int orderType){string lineName = "TrailingStopLine_" + IntegerToString(orderType);// 删除旧线ObjectDelete(0, lineName);// 创建新线ObjectCreate(0, lineName, OBJ_HLINE, 0, 0, price);ObjectSetInteger(0, lineName, OBJPROP_COLOR, TrailingLineColor);ObjectSetInteger(0, lineName, OBJPROP_STYLE, STYLE_DASHDOT);ObjectSetInteger(0, lineName, OBJPROP_WIDTH, 2);ObjectSetInteger(0, lineName, OBJPROP_BACK, true);// 设置标签string labelName = lineName + "_Label";ObjectDelete(0, labelName);ObjectCreate(0, labelName, OBJ_TEXT, 0, Time[10], price);ObjectSetString(0, labelName, OBJPROP_TEXT, "移动止损: " + DoubleToString(price, Digits));ObjectSetInteger(0, labelName, OBJPROP_COLOR, TrailingLineColor);ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 8);}//+------------------------------------------------------------------+//| 创建界面控件 |//+------------------------------------------------------------------+voidCreateControls(){// 创建主面板ObjectCreate(0, "EA_Background", OBJ_RECTANGLE_LABEL, 0, 0, 0);ObjectSetInteger(0, "EA_Background", OBJPROP_XDISTANCE, 10);ObjectSetInteger(0, "EA_Background", OBJPROP_YDISTANCE, 20);ObjectSetInteger(0, "EA_Background", OBJPROP_XSIZE, 200);ObjectSetInteger(0, "EA_Background", OBJPROP_YSIZE, 180);ObjectSetInteger(0, "EA_Background", OBJPROP_BGCOLOR, C'30,30,30');ObjectSetInteger(0, "EA_Background", OBJPROP_BORDER_TYPE, BORDER_FLAT);ObjectSetInteger(0, "EA_Background", OBJPROP_CORNER, CORNER_LEFT_UPPER);// 标题ObjectCreate(0, "EA_Title", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "EA_Title", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "EA_Title", OBJPROP_YDISTANCE, 25);ObjectSetString(0, "EA_Title", OBJPROP_TEXT, "移动止盈EA v1.0");ObjectSetInteger(0, "EA_Title", OBJPROP_COLOR, clrWhite);ObjectSetInteger(0, "EA_Title", OBJPROP_FONTSIZE, 10);// 状态显示ObjectCreate(0, "Status_Label", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "Status_Label", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Status_Label", OBJPROP_YDISTANCE, 50);ObjectSetString(0, "Status_Label", OBJPROP_TEXT, "状态: 运行中");ObjectSetInteger(0, "Status_Label", OBJPROP_COLOR, clrLime);// 订单信息ObjectCreate(0, "Orders_Label", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "Orders_Label", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Orders_Label", OBJPROP_YDISTANCE, 70);ObjectSetString(0, "Orders_Label", OBJPROP_TEXT, "监控订单: 0");// 策略显示ObjectCreate(0, "Strategy_Label", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "Strategy_Label", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Strategy_Label", OBJPROP_YDISTANCE, 90);ObjectSetString(0, "Strategy_Label", OBJPROP_TEXT, "策略: 固定距离");// 盈利信息ObjectCreate(0, "Profit_Label", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "Profit_Label", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Profit_Label", OBJPROP_YDISTANCE, 110);ObjectSetString(0, "Profit_Label", OBJPROP_TEXT, "总盈利: $0.00");// 最后修改时间ObjectCreate(0, "Time_Label", OBJ_LABEL, 0, 0, 0);ObjectSetInteger(0, "Time_Label", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Time_Label", OBJPROP_YDISTANCE, 130);ObjectSetString(0, "Time_Label", OBJPROP_TEXT, "最后检查: --:--:--");// 启用/禁用按钮ObjectCreate(0, "Btn_Enable", OBJ_BUTTON, 0, 0, 0);ObjectSetInteger(0, "Btn_Enable", OBJPROP_XDISTANCE, 15);ObjectSetInteger(0, "Btn_Enable", OBJPROP_YDISTANCE, 160);ObjectSetInteger(0, "Btn_Enable", OBJPROP_XSIZE, 90);ObjectSetInteger(0, "Btn_Enable", OBJPROP_YSIZE, 25);ObjectSetString(0, "Btn_Enable", OBJPROP_TEXT, "禁用EA");ObjectSetInteger(0, "Btn_Enable", OBJPROP_COLOR, clrWhite);ObjectSetInteger(0, "Btn_Enable", OBJPROP_BGCOLOR, clrRed);ObjectSetInteger(0, "Btn_Enable", OBJPROP_CORNER, CORNER_LEFT_UPPER);// 关闭按钮ObjectCreate(0, "Btn_Close", OBJ_BUTTON, 0, 0, 0);ObjectSetInteger(0, "Btn_Close", OBJPROP_XDISTANCE, 115);ObjectSetInteger(0, "Btn_Close", OBJPROP_YDISTANCE, 160);ObjectSetInteger(0, "Btn_Close", OBJPROP_XSIZE, 90);ObjectSetInteger(0, "Btn_Close", OBJPROP_YSIZE, 25);ObjectSetString(0, "Btn_Close", OBJPROP_TEXT, "隐藏界面");ObjectSetInteger(0, "Btn_Close", OBJPROP_COLOR, clrWhite);ObjectSetInteger(0, "Btn_Close", OBJPROP_BGCOLOR, clrGray);ObjectSetInteger(0, "Btn_Close", OBJPROP_CORNER, CORNER_LEFT_UPPER);}//+------------------------------------------------------------------+//| 删除界面控件 |//+------------------------------------------------------------------+voidDeleteControls(){string objects[] = {"EA_Background", "EA_Title", "Status_Label", "Orders_Label","Strategy_Label", "Profit_Label", "Time_Label", "Btn_Enable", "Btn_Close"};for(int i = 0; i < ArraySize(objects); i++){ObjectDelete(0, objects[i]);}}//+------------------------------------------------------------------+//| 更新界面显示 |//+------------------------------------------------------------------+voidUpdateDisplay(){// 计算监控的订单数量int monitoredOrders = 0;double totalProfit = 0;for(int i = OrdersTotal() - 1; i >= 0; i--){if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber){monitoredOrders++;totalProfit += OrderProfit() + OrderSwap() + OrderCommission();}}}// 更新订单数量ObjectSetString(0, "Orders_Label", OBJPROP_TEXT, "监控订单: " + IntegerToString(monitoredOrders));// 更新策略显示string strategyText = "策略: ";switch(TrailingType){case TRAILING_FIXED: strategyText += "固定距离"; break;case TRAILING_ATR_BASED: strategyText += "ATR跟踪"; break;case TRAILING_CHANDELIER: strategyText += "吊灯止损"; break;case TRAILING_PARABOLIC: strategyText += "抛物线SAR"; break;}ObjectSetString(0, "Strategy_Label", OBJPROP_TEXT, strategyText);// 更新盈利信息ObjectSetString(0, "Profit_Label", OBJPROP_TEXT, "总盈利: $" + DoubleToString(totalProfit, 2));// 更新状态string statusText = "状态: " + (g_EnableTrailingStop ? "运行中" : "已停止");ObjectSetString(0, "Status_Label", OBJPROP_TEXT, statusText);ObjectSetInteger(0, "Status_Label", OBJPROP_COLOR, g_EnableTrailingStop ? clrLime : clrRed);// 更新按钮文本ObjectSetString(0, "Btn_Enable", OBJPROP_TEXT, g_EnableTrailingStop ? "禁用EA" : "启用EA");ObjectSetInteger(0, "Btn_Enable", OBJPROP_BGCOLOR, g_EnableTrailingStop ? clrRed : clrLime);// 更新时间ObjectSetString(0, "Time_Label", OBJPROP_TEXT, "最后检查: " + TimeToString(TimeCurrent(), TIME_SECONDS));}//+------------------------------------------------------------------+//| 图表事件处理 |//+------------------------------------------------------------------+voidOnChartEvent(constint id, constlong &lparam, constdouble &dparam, conststring &sparam){// 处理按钮点击事件if(id == CHARTEVENT_OBJECT_CLICK){if(sparam == "Btn_Enable"){g_EnableTrailingStop = !g_EnableTrailingStop;UpdateDisplay();Print("移动止盈 " + (g_EnableTrailingStop ? "启用" : "禁用"));}else if(sparam == "Btn_Close"){// 隐藏界面SetControlsVisible(false);}}}//+------------------------------------------------------------------+//| 设置控件可见性 |//+------------------------------------------------------------------+voidSetControlsVisible(bool visible){string objects[] = {"EA_Background", "EA_Title", "Status_Label", "Orders_Label","Strategy_Label", "Profit_Label", "Time_Label", "Btn_Enable", "Btn_Close"};for(int i = 0; i < ArraySize(objects); i++){ObjectSetInteger(0, objects[i], OBJPROP_TIMEFRAMES, visible ? OBJ_ALL_PERIODS : OBJ_NO_PERIODS);}if(visible){ObjectSetString(0, "Btn_Close", OBJPROP_TEXT, "隐藏界面");}}
夜雨聆风
