统计EA源码发布!
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

//+------------------------------------------------------------------+//| StatsPanel.mq4 |//| Generated by MetaEditor |//| https://www.mql5.com |//+------------------------------------------------------------------+#property copyright "狼人统计EA"#property link "https://www.example.com"#property version "1.00"#property strict#property description "交易统计面板 - 显示每日/每周/总体统计、胜率、手数、最大浮亏等 (MT4版)"// --- 输入参数 ---input int EA_MagicNumber = 20250306; // 唯一标识(用于保存历史最大浮亏)input int RefreshInterval = 1; // 刷新间隔(秒,0=随tick更新)input int PanelCorner = 0; // 角落(0左上,1右上,2左下,3右下)input int Xoffset = 10; // X偏移input int Yoffset = 20; // Y偏移input int FontSize = 9; // 字体大小input color TextColor = clrBlack; // 文字颜色input color PanelBgColor = C'245,245,245'; // 面板背景色input color TitleColor = clrDarkBlue; // 标题颜色input color ValueColor = clrDarkGreen; // 数值颜色// --- 全局变量 ---string Prefix; // 对象名前缀double gPeakBalance; // 历史最高余额double gMaxDrawdown; // 历史最大浮亏(金额)datetime gLastUpdate; // 上次更新时间(用于tick限流)//+------------------------------------------------------------------+//| 初始化函数 |//+------------------------------------------------------------------+intOnInit(){Prefix = "StatsPanel_" + IntegerToString(EA_MagicNumber) + "_";DeleteAllObjects(); // 清除旧对象// 读取或初始化峰值余额与最大浮亏string gvPeak = Prefix + "PeakBalance";string gvDD = Prefix + "MaxDrawdown";if(GlobalVariableCheck(gvPeak))gPeakBalance = GlobalVariableGet(gvPeak);elsegPeakBalance = AccountBalance();if(GlobalVariableCheck(gvDD))gMaxDrawdown = GlobalVariableGet(gvDD);elsegMaxDrawdown = 0.0;// 创建面板背景和所有标签CreatePanel();// 设置定时器if(RefreshInterval > 0)EventSetTimer(RefreshInterval);gLastUpdate = 0;return(INIT_SUCCEEDED);}//+------------------------------------------------------------------+//| 退出函数 |//+------------------------------------------------------------------+voidOnDeinit(constint reason){if(RefreshInterval > 0)EventKillTimer();DeleteAllObjects();}//+------------------------------------------------------------------+//| Timer 事件 |//+------------------------------------------------------------------+voidOnTimer(){RefreshStats();}//+------------------------------------------------------------------+//| Tick 事件 |//+------------------------------------------------------------------+voidOnTick(){if(RefreshInterval <= 0){// 控制最小更新间隔0.5秒,避免过度消耗CPUif(TimeCurrent() - gLastUpdate >= 0.5){RefreshStats();gLastUpdate = TimeCurrent();}}}//+------------------------------------------------------------------+//| 刷新统计数据并更新面板 |//+------------------------------------------------------------------+voidRefreshStats(){// --- 更新峰值余额与最大浮亏 ---double balance = AccountBalance();double equity = AccountEquity();if(balance > gPeakBalance)gPeakBalance = balance; // 余额创新高double drawdown = (gPeakBalance > equity) ? (gPeakBalance - equity) : 0.0;if(drawdown > gMaxDrawdown)gMaxDrawdown = drawdown; // 更新最大浮亏// 保存到全局变量(持久化)GlobalVariableSet(Prefix + "PeakBalance", gPeakBalance);GlobalVariableSet(Prefix + "MaxDrawdown", gMaxDrawdown);// --- 计算统计 ---datetime now = TimeCurrent();// 当日0点MqlDateTime dt;TimeToStruct(now, dt);dt.hour = 0; dt.min = 0; dt.sec = 0;datetime day_start = StructToTime(dt);// 本周一0点int days_from_monday = (dt.day_of_week == 0) ? 6 : dt.day_of_week - 1; // 周日=0 -> 距周一6天datetime week_start = day_start - days_from_monday * 24 * 60 * 60;// --- 总体统计 (所有历史) ---int totalHist = OrdersHistoryTotal(); // MT4方式获取历史订单总数int totalTrades = 0, winTrades = 0, lossTrades = 0, breakEvenTrades = 0;double totalLots = 0.0, totalProfit = 0.0;double maxWin = 0.0, maxLoss = 0.0;double sumWin = 0.0, sumLoss = 0.0;for(int i = 0; i < totalHist; i++){if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){// 仅统计已平仓的市场单 (排除挂单)if(OrderCloseTime() > 0 && (OrderType() == OP_BUY || OrderType() == OP_SELL)){double profit = OrderProfit();double lots = OrderLots();totalTrades++;totalLots += lots;totalProfit += profit;if(profit > 0.0){winTrades++;sumWin += profit;if(profit > maxWin) maxWin = profit;}else if(profit < 0.0){lossTrades++;sumLoss += profit; // 负值if(profit < maxLoss) maxLoss = profit; // 更负}else{breakEvenTrades++;}}}}// 平均盈亏double avgWin = (winTrades > 0) ? sumWin / winTrades : 0.0;double avgLoss = (lossTrades > 0) ? sumLoss / lossTrades : 0.0;// 胜率double winRate = (winTrades + lossTrades > 0) ? (double)winTrades / (winTrades + lossTrades) * 100.0 : 0.0;// --- 当日统计 ---int dayCount = 0, dayWin = 0, dayLoss = 0;double dayLots = 0.0, dayProfit = 0.0;// 需要遍历所有历史订单,筛选出平仓时间在当日之后的for(int i = 0; i < OrdersHistoryTotal(); i++){if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){if(OrderCloseTime() > 0 && (OrderType() == OP_BUY || OrderType() == OP_SELL)){datetime closeTime = OrderCloseTime();if(closeTime >= day_start && closeTime <= now) // 确保在当日范围内{double p = OrderProfit();dayCount++;dayLots += OrderLots();dayProfit += p;if(p > 0) dayWin++;else if(p < 0) dayLoss++;}}}}double dayWinRate = (dayWin + dayLoss > 0) ? (double)dayWin / (dayWin + dayLoss) * 100.0 : 0.0;// --- 本周统计 ---int weekCount = 0, weekWin = 0, weekLoss = 0;double weekLots = 0.0, weekProfit = 0.0;for(int i = 0; i < OrdersHistoryTotal(); i++){if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){if(OrderCloseTime() > 0 && (OrderType() == OP_BUY || OrderType() == OP_SELL)){datetime closeTime = OrderCloseTime();if(closeTime >= week_start && closeTime <= now){double p = OrderProfit();weekCount++;weekLots += OrderLots();weekProfit += p;if(p > 0) weekWin++;else if(p < 0) weekLoss++;}}}}double weekWinRate = (weekWin + weekLoss > 0) ? (double)weekWin / (weekWin + weekLoss) * 100.0 : 0.0;// --- 当前持仓统计 ---int posCount = 0;double posLots = 0.0, posFloatPL = 0.0;for(int i = 0; i < OrdersTotal(); i++){if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){if(OrderType() == OP_BUY || OrderType() == OP_SELL){posCount++;posLots += OrderLots();posFloatPL += OrderProfit();}}}// --- 更新面板文本 (按行索引更新) ---// 第0行: 标题SetLabelText("Title", "=== 交易统计面板 ===", TitleColor);// 第1-3行: 账户信息SetLabelText("Balance", DoubleToString(balance, 2), ValueColor);SetLabelText("Equity", DoubleToString(equity, 2), ValueColor);SetLabelText("FloatPL", DoubleToString(posFloatPL, 2), (posFloatPL>=0?clrGreen:clrRed));SetLabelText("PosCount", IntegerToString(posCount), ValueColor);SetLabelText("PosLots", DoubleToString(posLots, 2), ValueColor);// 第4行分隔SetLabelText("Sep1", "----------------------", TextColor);// 总体统计SetLabelText("TotalTrades", IntegerToString(totalTrades), ValueColor);SetLabelText("Win", IntegerToString(winTrades), ValueColor);SetLabelText("Loss", IntegerToString(lossTrades), ValueColor);SetLabelText("BE", IntegerToString(breakEvenTrades), ValueColor);SetLabelText("WinRate", DoubleToString(winRate, 2) + "%", ValueColor);SetLabelText("TotalLots", DoubleToString(totalLots, 2), ValueColor);SetLabelText("TotalPL", DoubleToString(totalProfit, 2), (totalProfit>=0?clrGreen:clrRed));SetLabelText("AvgWin", DoubleToString(avgWin, 2), ValueColor);SetLabelText("AvgLoss", DoubleToString(avgLoss, 2), ValueColor);SetLabelText("MaxWin", DoubleToString(maxWin, 2), ValueColor);SetLabelText("MaxLoss", DoubleToString(maxLoss, 2), ValueColor);SetLabelText("MaxDD", DoubleToString(gMaxDrawdown, 2), clrMaroon);// 当日统计SetLabelText("DayTrades", IntegerToString(dayCount), ValueColor);SetLabelText("DayPL", DoubleToString(dayProfit, 2), (dayProfit>=0?clrGreen:clrRed));SetLabelText("DayLots", DoubleToString(dayLots, 2), ValueColor);SetLabelText("DayWinRate",DoubleToString(dayWinRate, 2) + "%", ValueColor);// 本周统计SetLabelText("WeekTrades", IntegerToString(weekCount), ValueColor);SetLabelText("WeekPL", DoubleToString(weekProfit, 2), (weekProfit>=0?clrGreen:clrRed));SetLabelText("WeekLots", DoubleToString(weekLots, 2), ValueColor);SetLabelText("WeekWinRate",DoubleToString(weekWinRate, 2) + "%", ValueColor);}//+------------------------------------------------------------------+//| 创建面板所有静态标签 |//+------------------------------------------------------------------+voidCreatePanel(){int row = 0;int col1_x = Xoffset; // 标签名 Xint col2_x = Xoffset + 120; // 数值 Xint row_h = FontSize + 4;// 辅助创建函数// 参数: 对象名, 文本, 颜色, X, Y, 是否数值(右对齐)#define CREATE_LABEL(name, txt, clr, x, y, isValue) \{ \string objName = Prefix + name; \ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0); \ObjectSetText(objName, txt, FontSize, "Consolas", clr); \ObjectSet(objName, OBJPROP_XDISTANCE, x); \ObjectSet(objName, OBJPROP_YDISTANCE, y); \ObjectSet(objName, OBJPROP_CORNER, PanelCorner); \ObjectSet(objName, OBJPROP_BACK, false); \}// 背景矩形 (覆盖整个面板区域)string bgName = Prefix + "Background";ObjectCreate(0, bgName, OBJ_RECTANGLE_LABEL, 0, 0, 0);ObjectSet(bgName, OBJPROP_XDISTANCE, Xoffset - 5);ObjectSet(bgName, OBJPROP_YDISTANCE, Yoffset - 5);ObjectSet(bgName, OBJPROP_XSIZE, 220);ObjectSet(bgName, OBJPROP_YSIZE, 420); // 根据行数调整ObjectSet(bgName, OBJPROP_CORNER, PanelCorner);ObjectSet(bgName, OBJPROP_BACK, true);ObjectSet(bgName, OBJPROP_BGCOLOR, PanelBgColor);ObjectSet(bgName, OBJPROP_BORDER_TYPE, BORDER_FLAT);ObjectSet(bgName, OBJPROP_WIDTH, 1);// --- 标题行 (0) ---CREATE_LABEL("Title", "=== 交易统计面板 ===", TitleColor, col1_x, Yoffset + row*row_h, false);row++;// 账户信息CREATE_LABEL("LblBalance", "余额:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("Balance", "", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblEquity", "净值:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("Equity", "", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblFloatPL", "浮动盈亏:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("FloatPL", "", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblPosCount", "持仓单数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("PosCount", "", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblPosLots", "持仓手数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("PosLots", "", ValueColor, col2_x, Yoffset + row*row_h, true); row++;// 分隔线CREATE_LABEL("Sep1", "----------------------", TextColor, col1_x, Yoffset + row*row_h, false); row++;// 总体统计标题CREATE_LABEL("LblOverall", "【总体统计】", TitleColor, col1_x, Yoffset + row*row_h, false); row++;CREATE_LABEL("LblTotalTrades","总单数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("TotalTrades","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblWin","盈利:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("Win","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblLoss","亏损:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("Loss","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblBE","平保:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("BE","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblWinRate","胜率:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("WinRate","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblTotalLots","总手数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("TotalLots","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblTotalPL","总盈亏:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("TotalPL","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblAvgWin","平均盈利:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("AvgWin","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblAvgLoss","平均亏损:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("AvgLoss","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblMaxWin","最大盈利:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("MaxWin","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblMaxLoss","最大亏损:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("MaxLoss","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblMaxDD","历史最大浮亏:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("MaxDD","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;// 分隔线CREATE_LABEL("Sep2", "----------------------", TextColor, col1_x, Yoffset + row*row_h, false); row++;// 当日统计CREATE_LABEL("LblToday", "【当日统计】", TitleColor, col1_x, Yoffset + row*row_h, false); row++;CREATE_LABEL("LblDayTrades","单数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("DayTrades","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblDayPL","盈亏:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("DayPL","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblDayLots","手数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("DayLots","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblDayWinRate","胜率:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("DayWinRate","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;// 分隔线CREATE_LABEL("Sep3", "----------------------", TextColor, col1_x, Yoffset + row*row_h, false); row++;// 本周统计CREATE_LABEL("LblWeek", "【本周统计】", TitleColor, col1_x, Yoffset + row*row_h, false); row++;CREATE_LABEL("LblWeekTrades","单数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("WeekTrades","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblWeekPL","盈亏:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("WeekPL","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblWeekLots","手数:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("WeekLots","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;CREATE_LABEL("LblWeekWinRate","胜率:", TextColor, col1_x, Yoffset + row*row_h, false);CREATE_LABEL("WeekWinRate","", ValueColor, col2_x, Yoffset + row*row_h, true); row++;#undef CREATE_LABEL}//+------------------------------------------------------------------+//| 更新指定标签的文本和颜色 |//+------------------------------------------------------------------+voidSetLabelText(string name, string text, color clr){string objName = Prefix + name;if(ObjectFind(0, objName) >= 0){ObjectSetText(objName, text, FontSize, "Consolas", clr);}}//+------------------------------------------------------------------+//| 删除所有以Prefix开头的对象 |//+------------------------------------------------------------------+//+------------------------------------------------------------------+//| 删除所有以Prefix开头的对象 |//+------------------------------------------------------------------+voidDeleteAllObjects(){int total = ObjectsTotal(); // 直接使用无参数版本for(int i = total - 1; i >= 0; i--){string name = ObjectName(0, i);if(StringFind(name, Prefix) == 0)ObjectDelete(0, name);}}//+------------------------------------------------------------------+
夜雨聆风
