设为首页 收藏本站 切换语言

今天用deepseek写了个进阶的下单面板EA,感觉太屌了,现在的AI发展的吧,感觉普通程序员的下岗潮要来了。。。 这个EA功能包括: ...

| 发表于 2025-2-23 13:15:23 | 显示全部楼层 |复制链接
今天用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 "未知错误";
    }
}
//+------------------------------------------------------------------+




image.png
image.png
举报

评论 使用道具

精彩评论4

kingsman
DDD
| 发表于 2025-2-23 23:20:31 | 显示全部楼层
我今天也试了一下,还是有所欠缺的。
举报

点赞 评论 使用道具

Licos
D
| 发表于 2025-2-24 00:51:21 来自手机 | 显示全部楼层
我也用deepseek写了控制面板,编写时。老是显示错误。需要多次沟通。关键是提示词和对话逻辑要好
举报

点赞 评论 使用道具

mentu588
DD
 楼主 | 发表于 2025-2-24 08:25:58 | 显示全部楼层
kingsman 发表于 2025-2-23 23:20
我今天也试了一下,还是有所欠缺的。

嗯  需要自己再稍微修改下
举报

点赞 评论 使用道具

mentu588
DD
 楼主 | 发表于 2025-2-24 08:26:38 | 显示全部楼层
Licos 发表于 2025-2-24 00:51
我也用deepseek写了控制面板,编写时。老是显示错误。需要多次沟通。关键是提示词和对话逻辑要好 ...

对的,小错误让它继续修改就行,比人写要快很多
举报

点赞 评论 使用道具

发新帖
EA交易
您需要登录后才可以评论 登录 | 立即注册

简体中文
繁體中文
English(英语)
日本語(日语)
Deutsch(德语)
Русский язык(俄语)
بالعربية(阿拉伯语)
Türkçe(土耳其语)
Português(葡萄牙语)
ภาษาไทย(泰国语)
한어(朝鲜语/韩语)
Français(法语)