今天用deepseek写了个进阶的下单面板EA,感觉太屌了,现在的AI发展的吧,感觉普通程序员的下岗潮要来了。。。
这个EA功能包括:手数、止盈、止损的输入和快捷按键调节,默认数值可以在参数里面设置。风控比例默认20%,当日亏损达到20%及以上不能用面板开单,并会弹窗报警,提醒自己不要过度做单。源码在下边,需要的老哥复制一下自己研究、修改。
//+------------------------------------------------------------------+
//| TradePanelEA.mq4|
//| Copyright 2024, MetaQuotes Software Corp.|
//| https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "Copyright mentu588"
#property version "20250223-1.10"
#property strict
#property description "高级交易面板EA - 支持风控管理、批量操作和进阶下单"
// 输入参数
input double DefaultLots = 0.01; // 默认手数
input int DefaultSLPoints = 500; // 默认止损点数
input int DefaultTPPoints = 1000; // 默认止盈点数
input double RiskControlPercent = 20.0; // 风控比例(%)
input bool CheckClosedProfit = true; // 检查平仓盈亏
input bool CheckFloatingProfit = true; // 检查持仓浮亏
input string SoundFile = "ok.wav"; // 按钮音效文件
// 全局变量
datetime LastTradeDay; // 最后交易日期
double DailyInitialBalance; // 当日初始资金
double DailyClosedProfit; // 当日平仓盈亏
double CurrentFloating; // 当前持仓浮亏
// 界面布局参数
#define BASE_X 20
#define BASE_Y 10
#define BTN_WIDTH 160
#define BTN_HEIGHT 40
#define ROW_SPACE 60
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
CreateControls();
EventSetTimer(1);
CheckDailyReset();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| EA终止函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
DeleteControls();
}
//+------------------------------------------------------------------+
//| 创建界面控件 |
//+------------------------------------------------------------------+
void CreateControls()
{
// 账户信息
CreateLabel("BalanceLabel", "余额:$"+DoubleToString(AccountBalance(),2), BASE_X, BASE_Y+15, clrWhite);
CreateLabel("EquityLabel", "净值:$"+DoubleToString(AccountEquity(),2), BASE_X+300, BASE_Y+15, clrDodgerBlue);
CreateLabel("FloatPNL", "浮盈:$0.00", BASE_X+600, BASE_Y+15, clrLime);
// 手数调节区
CreateLabel("Normal Lots", "手数:", BASE_X, BASE_Y+60, clrLime);
CreateEdit("LotsEdit", DoubleToString(DefaultLots,2), BASE_X+100, BASE_Y+60, 100, 30, clrBlack);
CreateButton("LotsInc01", "+0.01", BASE_X+210, BASE_Y+60, 100, 30, clrGreen);
CreateButton("LotsInc05", "+0.05", BASE_X+320, BASE_Y+60, 100, 30, clrGreen);
CreateButton("LotsDec01", "-0.01", BASE_X+430, BASE_Y+60, 100, 30, clrRed);
// 市价交易按钮
CreateButton("MarketBuy", "市价做多", BASE_X+540, BASE_Y+60, 140, 55, clrGreen);
CreateButton("MarketSell", "市价做空", BASE_X+540, BASE_Y+135, 140, 55, clrRed);
// 止损点数设置
CreateLabel("SLPointsLabel", "止损:", BASE_X, BASE_Y+110, clrWhite);
CreateEdit("SLPoints", IntegerToString(DefaultSLPoints), BASE_X+100, BASE_Y+110, 100, 30, clrBlack);
CreateButton("SLInc100", "+100", BASE_X+210, BASE_Y+110, 100, 30, clrGray);
CreateButton("SLInc200", "+200", BASE_X+320, BASE_Y+110, 100, 30, clrGray);
CreateButton("SLDec100", "-100", BASE_X+430, BASE_Y+110, 100, 30, clrGray);
// 止盈点数设置
CreateLabel("TPPointsLabel", "止盈:", BASE_X, BASE_Y+160, clrWhite);
CreateEdit("TPPoints", IntegerToString(DefaultTPPoints), BASE_X+100, BASE_Y+160, 100, 30, clrBlack);
CreateButton("TPInc100", "+100", BASE_X+210, BASE_Y+160, 100, 30, clrGray);
CreateButton("TPInc200", "+200", BASE_X+320, BASE_Y+160, 100, 30, clrGray);
CreateButton("TPDec100", "-100", BASE_X+430, BASE_Y+160, 100, 30, clrGray);
// 平仓按钮区
CreateButton("CloseAll", "清仓", BASE_X+690, BASE_Y+60, 100, 130, clrDarkViolet);
}
//+------------------------------------------------------------------+
//| 每日数据重置检查 |
//+------------------------------------------------------------------+
void CheckDailyReset()
{
MqlDateTime today;
TimeCurrent(today);
today.hour = 0;
today.min = 0;
today.sec = 0;
datetime startTime = StructToTime(today);
if(startTime != LastTradeDay)
{
LastTradeDay = startTime;
DailyInitialBalance = AccountBalance();
DailyClosedProfit = 0;
Print("新交易日初始化完成,初始资金:", DailyInitialBalance);
}
}
//+------------------------------------------------------------------+
//| 更新持仓信息 |
//+------------------------------------------------------------------+
void UpdatePositionInfo()
{
ObjectSetString(0, "BalanceLabel", OBJPROP_TEXT, "余额:$" + DoubleToString(AccountBalance(), 2));
ObjectSetString(0, "EquityLabel", OBJPROP_TEXT, "净值:$" + DoubleToString(AccountEquity(), 2));
double totalPNL = 0;
CurrentFloating = 0;
for(int i=0; i<OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && OrderSymbol() == Symbol())
{
double profit = OrderProfit() + OrderSwap() + OrderCommission();
totalPNL += profit;
CurrentFloating += profit;
}
}
color pnlColor = (totalPNL >= 0) ? clrLime : clrRed;
ObjectSetString(0, "FloatPNL", OBJPROP_TEXT, "浮盈:$" + DoubleToString(totalPNL, 2));
ObjectSetInteger(0, "FloatPNL", OBJPROP_COLOR, pnlColor);
}
//+------------------------------------------------------------------+
//| 风控检查 |
//+------------------------------------------------------------------+
bool RiskCheckPassed()
{
if(DailyInitialBalance <= 0) return true;
double totalRisk = 0;
if(CheckClosedProfit)
totalRisk += DailyClosedProfit;
if(CheckFloatingProfit)
totalRisk += CurrentFloating;
double riskRatio = MathAbs(totalRisk) / DailyInitialBalance * 100.0;
if(totalRisk < 0 && riskRatio >= RiskControlPercent)
{
Alert("风控触发!当前亏损比例 ", DoubleToString(riskRatio,1), "%",
"\n允许最大比例 ", DoubleToString(RiskControlPercent,1), "%",
"\n当日初始资金:", DoubleToString(DailyInitialBalance,2),
"\n累计亏损:", DoubleToString(totalRisk,2));
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| 定时器事件 |
//+------------------------------------------------------------------+
void OnTimer()
{
CheckDailyReset();
UpdatePositionInfo();
}
//+------------------------------------------------------------------+
//| 删除界面控件 |
//+------------------------------------------------------------------+
void DeleteControls()
{
ObjectsDeleteAll(0, 0, -1);
}
//+------------------------------------------------------------------+
//| 创建标签控件 |
//+------------------------------------------------------------------+
void CreateLabel(const string name, const string text, int x, int y, color clr)
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
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, 12);
}
//+------------------------------------------------------------------+
//| 创建按钮控件 |
//+------------------------------------------------------------------+
void CreateButton(const string name, const string text, int x, int y, int width, int height, color bgColor)
{
ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
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, clrWhite);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bgColor);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 12);
}
//+------------------------------------------------------------------+
//| 创建输入框控件 |
//+------------------------------------------------------------------+
void CreateEdit(const string name, const string text, int x, int y, int width, int height, color clr)
{
ObjectCreate(0, name, OBJ_EDIT, 0, 0, 0);
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, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 12);
}
//+------------------------------------------------------------------+
//| 图表事件处理 |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
if(id == CHARTEVENT_OBJECT_CLICK)
{
string clicked = sparam;
PlaySound(SoundFile);
// 手数调节
if(clicked == "LotsInc01") AdjustLots(0.01);
else if(clicked == "LotsInc05") AdjustLots(0.05);
else if(clicked == "LotsDec01") AdjustLots(-0.01);
// 市价交易
else if(clicked == "MarketBuy") MarketOrder(OP_BUY);
else if(clicked == "MarketSell") MarketOrder(OP_SELL);
// 止损点数调节
else if(clicked == "SLInc100") AdjustPoints("SLPoints", 100);
else if(clicked == "SLInc200") AdjustPoints("SLPoints", 200);
else if(clicked == "SLDec100") AdjustPoints("SLPoints", -100);
// 止盈点数调节
else if(clicked == "TPInc100") AdjustPoints("TPPoints", 100);
else if(clicked == "TPInc200") AdjustPoints("TPPoints", 200);
else if(clicked == "TPDec100") AdjustPoints("TPPoints", -100);
// 平仓操作
else if(clicked == "CloseAll") CloseAllOrders();
}
}
//+------------------------------------------------------------------+
//| 调整手数 |
//+------------------------------------------------------------------+
void AdjustLots(double delta)
{
double lots = StringToDouble(ObjectGetString(0, "LotsEdit", OBJPROP_TEXT));
lots += delta;
lots = NormalizeDouble(lots, 2);
if(lots < MarketInfo(Symbol(), MODE_MINLOT))
lots = MarketInfo(Symbol(), MODE_MINLOT);
ObjectSetString(0, "LotsEdit", OBJPROP_TEXT, DoubleToString(lots, 2));
}
//+------------------------------------------------------------------+
//| 调整点数 |
//+------------------------------------------------------------------+
void AdjustPoints(string objName, int delta)
{
int points = (int)StringToInteger(ObjectGetString(0, objName, OBJPROP_TEXT));
points += delta;
if(points < 0) points = 0;
ObjectSetString(0, objName, OBJPROP_TEXT, IntegerToString(points));
}
//+------------------------------------------------------------------+
//| 市价下单 |
//+------------------------------------------------------------------+
void MarketOrder(int cmd)
{
if(!RiskCheckPassed())
{
Alert("交易被风控阻止!");
return;
}
double lots = StringToDouble(ObjectGetString(0, "LotsEdit", OBJPROP_TEXT));
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
if(lots < minLot)
{
Alert("手数太小,最小交易手数为:", minLot);
return;
}
int slPoints = (int)StringToInteger(ObjectGetString(0, "SLPoints", OBJPROP_TEXT));
int tpPoints = (int)StringToInteger(ObjectGetString(0, "TPPoints", OBJPROP_TEXT));
double price = (cmd == OP_BUY) ? Ask : Bid;
double slPrice = 0, tpPrice = 0;
double point = MarketInfo(Symbol(), MODE_POINT);
if(slPoints > 0)
{
if(cmd == OP_BUY) slPrice = price - slPoints * point;
else slPrice = price + slPoints * point;
slPrice = NormalizeDouble(slPrice, Digits);
}
if(tpPoints > 0)
{
if(cmd == OP_BUY) tpPrice = price + tpPoints * point;
else tpPrice = price - tpPoints * point;
tpPrice = NormalizeDouble(tpPrice, Digits);
}
int ticket = OrderSend(Symbol(), cmd, lots, price, 3, slPrice, tpPrice, "Adv Order", 0, clrNONE);
if(ticket < 0)
{
int error = GetLastError();
Alert("下单失败,错误代码:", error, " 信息:", GetErrorDescription(error));
}
}
//+------------------------------------------------------------------+
//| 平仓功能函数 |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==Symbol())
{
double profit = OrderProfit() + OrderSwap() + OrderCommission();
DailyClosedProfit += profit;
if(OrderType()==OP_BUY) OrderClose(OrderTicket(),OrderLots(),Bid,3,clrNONE);
if(OrderType()==OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3,clrNONE);
}
}
}
//+------------------------------------------------------------------+
//| 获取错误描述 |
//+------------------------------------------------------------------+
string GetErrorDescription(int errorCode)
{
switch(errorCode)
{
case 0: return "操作成功完成";
case 1: return "没有错误,但结果未知";
case 2: return "通用错误";
case 3: return "无效参数";
case 4: return "服务器忙";
case 5: return "旧版本";
case 6: return "没有连接";
case 7: return "权限不足";
case 8: return "请求过于频繁";
case 9: return "违规操作";
case 64: return "账户被禁用";
case 65: return "无效账户";
case 128: return "交易超时";
case 129: return "无效价格";
case 130: return "无效止损";
case 131: return "无效交易量";
case 132: return "市场已关闭";
case 133: return "交易被禁用";
case 134: return "资金不足";
case 135: return "价格已变化";
case 136: return "没有报价";
case 137: return "经纪商忙";
case 138: return "需要重新报价";
case 139: return "订单被锁定";
case 140: return "仅允许平仓";
case 146: return "交易环境繁忙";
case 147: return "止损/止盈被禁止";
case 148: return "订单数量过多";
case 149: return "对冲被禁止";
case 150: return "禁止FIFO平仓";
default: return "未知错误";
}
}
//+------------------------------------------------------------------+
|