//+------------------------------------------------------------------+ //| PinbarSignal | //| Copyright 2025, You | //| mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025" #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| 输入参数 | //+------------------------------------------------------------------+ input group "=====信号与运行参数======" input string SymbolsList = "XAUUSD,EURUSD,GBPUSD,BTCUSD,ETHUSD,XRPUSD,DOGEUSD,BNBUSD,SOLUSD,LTCUSD,LINKUSD,AAVEUSD,DOTUSD"; // 多品种,英文逗号分割 input string TimeframesList = "M15,M30,H1,H4"; // 多周期,示例: "H1, M30, H4" input string SymbolSuffix = ""; // 品种后缀 input bool EnableEmail = true; // 启用邮件通知 input string MailSubjectPrefix= "信号提醒"; // 邮件标题前缀 input group "=====Pinbar识别参数=====" input double BodyToRangeMax = 0.3; // 实体占总长度最大比例(越小越像针) input double WickDominanceMin = 0.6; // 主影线占总长度最小比例 input double NoseToTailRatio = 2.0; // 主影线/次影线 最小倍数 input group "=====调试=====" input bool DebugSendTestOnStart = false; // 启用后,EA启动即发送测试邮件 input bool EnableChartArrows = true; // 符合Pinbar时在图表上标记箭头(仅当前图表品种) // 全局/静态变量 datetime lastCheckedTimes[]; // 每个周期的上次处理收线时间(以首个品种为基准) string symbols[]; // 解析后的品种数组 ENUM_TIMEFRAMES timeframes[]; // 解析后的周期数组 //+------------------------------------------------------------------+ //| 工具函数:去除字符串首尾空格 | //+------------------------------------------------------------------+ string Trim(const string text) { string s = text; while(StringLen(s)>0 && (ushort)StringGetCharacter(s,0)<=32) s = StringSubstr(s,1); while(StringLen(s)>0 && (ushort)StringGetCharacter(s,StringLen(s)-1)<=32) s = StringSubstr(s,0,StringLen(s)-1); return s; } //+------------------------------------------------------------------+ //| 解析SymbolsList到数组 | //+------------------------------------------------------------------+ int ParseSymbols() { ArrayFree(symbols); string parts[]; int n = StringSplit(SymbolsList, ',', parts); for(int i=0;i0); } //+------------------------------------------------------------------+ //| 读取指定品种与周期的上一根K线(已收线) | //+------------------------------------------------------------------+ bool GetPrevBar(const string sym, const ENUM_TIMEFRAMES tf, MqlRates &bar) { // 明确请求上一根已收线K(shift=1,count=1),避免数组顺序或未收线K的歧义 MqlRates rates[1]; int copied = CopyRates(sym, tf, 1, 1, rates); if(copied<1) return false; bar = rates[0]; return true; } //+------------------------------------------------------------------+ //| 判定Pinbar(返回:0=否, 1=看涨Pinbar, -1=看跌Pinbar) | //+------------------------------------------------------------------+ int IsPinbar(const MqlRates &b, const int digits) { double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); // 总长度(高低) double range = b.high - b.low; if(range <= 0) return 0; // 实体与影线 double body = MathAbs(b.close - b.open); double upperWick = b.high - MathMax(b.open, b.close); double lowerWick = MathMin(b.open, b.close) - b.low; double bodyRatio = body / range; if(bodyRatio > BodyToRangeMax) return 0; // 判断主影线与方向 if(upperWick > lowerWick) { double dominance = upperWick / range; // 上影占比 double ratio = (lowerWick <= 0 ? 9999.0 : upperWick / lowerWick); if(dominance >= WickDominanceMin && ratio >= NoseToTailRatio) return -1; // 看跌Pinbar(长上影) } else if(lowerWick > upperWick) { double dominance = lowerWick / range; // 下影占比 double ratio = (upperWick <= 0 ? 9999.0 : lowerWick / upperWick); if(dominance >= WickDominanceMin && ratio >= NoseToTailRatio) return 1; // 看涨Pinbar(长下影) } return 0; } //+------------------------------------------------------------------+ //| 将周期枚举转为短标签(M1/H1/D1等) | //+------------------------------------------------------------------+ string TfToLabel(const ENUM_TIMEFRAMES tf) { switch(tf) { case PERIOD_M1: return "M1"; case PERIOD_M2: return "M2"; case PERIOD_M3: return "M3"; case PERIOD_M4: return "M4"; case PERIOD_M5: return "M5"; case PERIOD_M6: return "M6"; case PERIOD_M10: return "M10"; case PERIOD_M12: return "M12"; case PERIOD_M15: return "M15"; case PERIOD_M20: return "M20"; case PERIOD_M30: return "M30"; case PERIOD_H1: return "H1"; case PERIOD_H2: return "H2"; case PERIOD_H3: return "H3"; case PERIOD_H4: return "H4"; case PERIOD_H6: return "H6"; case PERIOD_H8: return "H8"; case PERIOD_H12: return "H12"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN1"; default: return EnumToString(tf); } } //+------------------------------------------------------------------+ //| 在图表上标记Pinbar箭头(仅当前图表与主窗口) | //+------------------------------------------------------------------+ void MarkPinbarOnChart(const string sym, const ENUM_TIMEFRAMES tf, const MqlRates &b, const int dir) { if(!EnableChartArrows) return; if(sym != _Symbol) return; // 仅在当前图表品种上绘制 // 生成唯一对象名:Pinbar__