找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4|回复: 0

[MT5] 高斯滤波趋势 + 多周期趋势面板.mq5

[复制链接]

276

主题

6

回帖

1030

积分

管理员

积分
1030
发表于 昨天 17:58 | 显示全部楼层 |阅读模式
//+------------------------------------------------------------------+
//|                                高斯滤波趋势 + 多周期趋势面板.mq5  |
//|        Gaussian Filter Trend [QuantAlgo] - 汉化增强版             |
//|        移植自 Pine Script v6 "Gaussian Filter Trend [QuantAlgo]"  |
//|        原作版权: (c) QuantAlgo - CC BY-NC-SA 4.0                  |
//+------------------------------------------------------------------+
//| 本版本说明:                                                      |
//|  1. 参数界面、注释与提示文字全面汉化;                            |
//|  2. 新增"多周期趋势面板"(默认位于图表右上角):                  |
//|     · 多头趋势 → 绿色向上箭头                                    |
//|     · 空头趋势 → 红色向下箭头                                    |
//|     · 中性/数据加载中 → 灰色圆点/省略号                          |
//|     · 各周期状态在该周期 K 线走完(收盘)后自动刷新;             |
//|     · 面板周期列表可在参数中自定义(如 "M5,M15,H1,D1");          |
//|     · 首次加载即自动读取全部周期数据,无需手动切换图表周期。       |
//+------------------------------------------------------------------+
#property copyright "QuantAlgo (ported) | 汉化 & 多周期面板增强"
#property link      ""
#property version   "1.10"
#property description "高斯滤波趋势指标(汉化版)"
#property description "新增:图表右上角多周期趋势面板,多头绿色↑ / 空头红色↓,各周期K线走完自动刷新"
#property indicator_chart_window
#property indicator_buffers 17
#property indicator_plots   7

#property indicator_type1  DRAW_COLOR_LINE
#property indicator_type2  DRAW_COLOR_ARROW
#property indicator_type3  DRAW_COLOR_ARROW
#property indicator_type4  DRAW_COLOR_ARROW
#property indicator_type5  DRAW_COLOR_ARROW
#property indicator_type6  DRAW_COLOR_CANDLES
#property indicator_type7  DRAW_FILLING

//--- 绘图1:趋势线(多头 / 空头 / 中性)
#property indicator_color1  clrLime,clrRed,clrGray
#property indicator_width1  4
//--- 绘图2..5:星空散点(多头 / 空头 / 中性)- 绘制时向背景色做透明混合
#property indicator_color2  clrLime,clrRed,clrGray
#property indicator_width2  2
#property indicator_color3  clrLime,clrRed,clrGray
#property indicator_width3  2
#property indicator_color4  clrLime,clrRed,clrGray
#property indicator_width4  1
#property indicator_color5  clrLime,clrRed,clrGray
#property indicator_width5  1
//--- 绘图6:K线着色覆盖(多头 / 空头 / 中性隐藏)
#property indicator_color6  clrLime,clrRed,clrNONE
//--- 绘图7:背景填充(多头 / 空头)
#property indicator_color7  clrLime,clrRed

//              ╔════════════════════════════════╗
//              ║           用户设置              ║
//              ╚════════════════════════════════╝

enum ENUM_PRESET
  {
   Default,        // 默认
   Fast_Response,  // 快速响应
   Smooth_Trend    // 平滑趋势
  };

enum ENUM_COLOR_PRESET
  {
   Color_Custom,  // 自定义颜色
   Color_Classic, // 经典红绿
   Color_Aqua,    // 水色系
   Color_Cosmic,  // 宇宙色系
   Color_Cyber,   // 赛博色系
   Color_Neon     // 霓虹色系
  };

enum ENUM_SRC_PRICE
  {
   Src_Close,  // 收盘价 Close
   Src_HL2,    // 高低均价 HL2
   Src_HLC3    // 典型价 HLC3
  };

input group "════════ 高斯滤波 ════════"
input ENUM_PRESET     PresetConfiguration = Default;                  // 预设配置
input ENUM_SRC_PRICE  PriceSource         = Src_Close;                // 价格源
input int             GaussianLength      = 14;                       // 滤波长度
input int             GaussianPoles       = 4;                        // 滤波极点数 (1-4)

input group "════════ 趋势通道宽度 ════════"
input int              AtrLength          = 14;                       // ATR 周期
input double           FixedMultiplier    = 1.5;                      // 固定宽度倍数
input bool             AdaptiveWidth      = true;                     // 自适应宽度
input int              EfficiencyLength   = 10;                       // 效率比值周期
input double           TrendMultiplier    = 0.8;                      // 趋势倍数(自适应)
input double           ChopMultiplier     = 2.5;                      // 震荡倍数(自适应)
input int              EfficiencySmooth   = 5;                        // 效率比平滑周期

input group "════════ 视觉设置 ════════"
input ENUM_COLOR_PRESET ColorPreset       = Color_Custom;             // 颜色预设
input color             BullishInput      = clrAqua;                  // 多头颜色(自定义)
input color             BearishInput      = clrRed;                   // 空头颜色(自定义)
input color             NeutralInput      = clrGray;                  // 中性颜色
input int               LineWidth         = 4;                        // 线宽 (1-5)
input bool              ShowTrend         = true;                     // 显示趋势线
input bool              ShowStars         = true;                     // 显示星空散点
input bool              ShowCandles       = false;                    // 启用 K 线着色
input int               BarTransparency   = 0;                        // K线颜色透明度 (0-100)
input bool              ShowBackground    = false;                    // 启用背景着色
input int               BgTransparency    = 90;                       // 背景透明度 (0-100)

input group "════════ 警报 ════════"
input bool              EnableAlerts      = true;                     // 趋势反转时弹出警报

input group "════════ 多周期趋势面板 ════════"
input bool              ShowPanel          = true;                    // 显示多周期趋势面板
input string            PanelTimeframes    = "M5,M15,M30,H1,H4,D1";  // 面板周期列表(逗号分隔,可自定义)
input int               PanelBars          = 2000;                    // 面板计算使用的历史K线数
input color             PanelBullColor     = clrLime;                 // 多头箭头颜色(向上)
input color             PanelBearColor     = clrRed;                  // 空头箭头颜色(向下)
input color             PanelNeutralColor  = clrGray;                 // 中性/加载中颜色
input color             PanelBgColor       = C'22,28,40';             // 面板背景颜色
input color             PanelBorderColor   = C'90,100,130';           // 面板边框颜色
input color             PanelTextColor     = clrWhite;                // 面板文字颜色
input int               PanelFontSize      = 10;                      // 面板字体大小
input int               PanelXOffset       = 10;                      // 面板距图表右边缘距离(像素)
input int               PanelYOffset       = 30;                      // 面板距图表顶部距离(像素)

//              ╔════════════════════════════════╗
//              ║           指标缓冲区            ║
//              ╚════════════════════════════════╝

double TrendLineBuf[], TrendLineColorBuf[];
double InnerAValBuf[], InnerAColorBuf[];
double InnerBValBuf[], InnerBColorBuf[];
double OuterAValBuf[], OuterAColorBuf[];
double OuterBValBuf[], OuterBColorBuf[];
double CandleOBuf[], CandleHBuf[], CandleLBuf[], CandleCBuf[], CandleColorBuf[];
double BgTopBuf[], BgBotBuf[];

//--- 持久化计算状态(下标0=最旧K线,与非时间序列方向一致)
double Stage1[], Stage2[], Stage3[], Stage4[];
double SmoothedEff[];
int    TrendDir[];

//--- 预设解析后的工作参数
int    g_length, g_poles, g_atrLength, g_effLength, g_effSmooth;
double g_fixedMult, g_trendMult, g_chopMult;
color  g_bullish, g_bearish;
int    g_atrHandle = INVALID_HANDLE;

datetime g_lastAlertBull = 0, g_lastAlertBear = 0;

//              ╔════════════════════════════════╗
//              ║        多周期趋势面板           ║
//              ╚════════════════════════════════╝

#define DIR_LOAD  (-2)              // 状态:数据加载中
#define PANEL_W   140               // 面板宽度(像素)

string          g_panelPrefix = "GFTP_";      // 面板对象名前缀
string          g_panelFont   = "Microsoft YaHei"; // 面板中文字体
ENUM_TIMEFRAMES g_panelTF[];                  // 面板周期列表
int             g_panelATRH[];                // 各周期 ATR 指标句柄
datetime        g_panelBarTime[];             // 各周期最近一根K线开盘时间(新K线检测)
int             g_panelDir[];                 // 各周期趋势方向:1=多头 / -1=空头 / 0=中性 / -2=加载中
int             g_panelCount = 0;             // 面板周期数量
int             g_panelRowH = 20;             // 面板行高(像素)

//--- 周期名称/枚举对照表(解析用户自定义周期列表用)
string g_tfNames[21]=
  {
   "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30",
   "H1","H2","H3","H4","H6","H8","H12",
   "D1","W1","MN1"
  };
ENUM_TIMEFRAMES g_tfVals[21]=
  {
   PERIOD_M1,PERIOD_M2,PERIOD_M3,PERIOD_M4,PERIOD_M5,PERIOD_M6,
   PERIOD_M10,PERIOD_M12,PERIOD_M15,PERIOD_M20,PERIOD_M30,
   PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,
   PERIOD_D1,PERIOD_W1,PERIOD_MN1
  };

//+------------------------------------------------------------------+
//| 周期枚举 → 中文显示名(如 M15→"15分钟"、H4→"4小时"、D1→"日线")   |
//+------------------------------------------------------------------+
string TFToText(const ENUM_TIMEFRAMES tf)
  {
   if(tf==PERIOD_MN1) return("月线");
   if(tf==PERIOD_W1)  return("周线");
   if(tf==PERIOD_D1)  return("日线");
   if(tf>=PERIOD_H1 && tf<ERIOD_D1) return(IntegerToString(tf-PERIOD_H1+1)+"小时");
   if(tf>=PERIOD_M1 && tf<ERIOD_H1) return(IntegerToString(tf)+"分钟");
   return(EnumToString(tf));
  }

//+------------------------------------------------------------------+
//| 字符串 → 周期枚举(支持 m5/h4 等小写写法与 MN 别名)              |
//+------------------------------------------------------------------+
bool TFFromString(string s,ENUM_TIMEFRAMES &tf)
  {
   StringTrimLeft(s);
   StringTrimRight(s);
   if(StringLen(s)==0)
      return(false);
   StringToUpper(s);
   if(s=="MN" || s=="MN1" || s=="MONTH")
     {
      tf=PERIOD_MN1;
      return(true);
     }
   for(int i=0;i<21;i++)
      if(s==g_tfNames)
        {
         tf=g_tfVals;
         return(true);
        }
   return(false);
  }

//+------------------------------------------------------------------+
//| 解析面板周期列表参数(逗号分隔),自动去重、跳过无法识别的周期     |
//+------------------------------------------------------------------+
bool ParsePanelTimeframes()
  {
   g_panelCount=0;
   string list=PanelTimeframes;
   StringReplace(list,",",",");      // 容错:中文逗号
   StringReplace(list,";",",");       // 容错:分号分隔
   string parts[];
   int n=StringSplit(list,',',parts);
   for(int i=0;i<n;i++)
     {
      string s=parts;
      StringTrimLeft(s);
      StringTrimRight(s);
      if(StringLen(s)==0)
         continue;
      ENUM_TIMEFRAMES tf;
      if(!TFFromString(s,tf))
        {
         Print("多周期面板:无法识别的周期 \"",s,"\",已跳过(可用示例:M1 M5 M15 M30 H1 H4 D1 W1 MN)");
         continue;
        }
      bool dup=false;
      for(int k=0;k<g_panelCount;k++)
         if(g_panelTF[k]==tf)
           {
            dup=true;
            break;
           }
      if(dup)
         continue;
      ArrayResize(g_panelTF,g_panelCount+1);
      g_panelTF[g_panelCount]=tf;
      g_panelCount++;
     }
   ArrayResize(g_panelATRH,g_panelCount);
   ArrayResize(g_panelBarTime,g_panelCount);
   ArrayResize(g_panelDir,g_panelCount);
   for(int i=0;i<g_panelCount;i++)
     {
      g_panelATRH=INVALID_HANDLE;
      g_panelBarTime=0;
      g_panelDir=DIR_LOAD;
     }
   return(g_panelCount>0);
  }

//+------------------------------------------------------------------+
//| 面板第 i 行的 Y 坐标                                              |
//+------------------------------------------------------------------+
int PanelRowY(const int i)
  {
   return(PanelYOffset+30+i*g_panelRowH);
  }

//+------------------------------------------------------------------+
//| 面板总高度                                                        |
//+------------------------------------------------------------------+
int PanelHeight()
  {
   return(36+g_panelCount*g_panelRowH);
  }

//+------------------------------------------------------------------+
//| 创建/更新面板文本标签(锚定图表右上角,x 为距右边缘的像素距离)    |
//+------------------------------------------------------------------+
void PanelLabel(const string tag,const string text,const int x,const int y,
                const color clr,const int fontSize,const string font,
                const ENUM_ANCHOR_POINT anchor)
  {
   string name=g_panelPrefix+tag;
   if(ObjectFind(0,name)<0)
     {
      if(!ObjectCreate(0,name,OBJ_LABEL,0,0,0))
         return;
      ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
      ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
      ObjectSetInteger(0,name,OBJPROP_BACK,false);
      ObjectSetInteger(0,name,OBJPROP_ZORDER,100);
     }
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);
   ObjectSetString (0,name,OBJPROP_FONT,font);
   ObjectSetString (0,name,OBJPROP_TEXT,text);
  }

//+------------------------------------------------------------------+
//| 更新面板第 i 行的趋势箭头                                         |
//| 多头=绿色向上箭头 / 空头=红色向下箭头 / 中性=灰色圆点 / 加载中=…  |
//+------------------------------------------------------------------+
void PanelUpdateCell(const int i)
  {
   string text="…";
   string font=g_panelFont;
   color  clr=PanelNeutralColor;
   int    fs=PanelFontSize+1;
   if(g_panelDir==1)                       // 多头:绿色向上箭头
     {
      text=CharToString((uchar)233);          // Wingdings 上箭头
      font="Wingdings";
      clr=PanelBullColor;
      fs=PanelFontSize+4;
     }
   else if(g_panelDir==-1)                 // 空头:红色向下箭头
     {
      text=CharToString((uchar)234);          // Wingdings 下箭头
      font="Wingdings";
      clr=PanelBearColor;
      fs=PanelFontSize+4;
     }
   else if(g_panelDir==0)                  // 中性:灰色圆点
     {
      text="●";
     }
   PanelLabel("ARROW"+IntegerToString(i),text,PanelXOffset+16,PanelRowY(i),
              clr,fs,font,ANCHOR_RIGHT_UPPER);
  }

//+------------------------------------------------------------------+
//| 创建面板(背景 + 标题 + 各周期行),初始状态为"加载中"            |
//+------------------------------------------------------------------+
void PanelCreate()
  {
   //--- 背景矩形(矩形左上角锚定,向右延伸 PANEL_W 像素)
   string name=g_panelPrefix+"BG";
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
      ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
      ObjectSetInteger(0,name,OBJPROP_BACK,false);
      ObjectSetInteger(0,name,OBJPROP_ZORDER,90);
     }
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,PanelXOffset+PANEL_W);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,PanelYOffset);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,PANEL_W);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,PanelHeight());
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,PanelBgColor);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
   ObjectSetInteger(0,name,OBJPROP_COLOR,PanelBorderColor);

   //--- 标题
   PanelLabel("TITLE","多周期趋势",PanelXOffset+PANEL_W/2,PanelYOffset+5,
              PanelTextColor,PanelFontSize+1,g_panelFont,ANCHOR_UPPER);

   //--- 各周期行:左侧周期名 + 右侧趋势箭头
   for(int i=0;i<g_panelCount;i++)
     {
      PanelLabel("NAME"+IntegerToString(i),TFToText(g_panelTF),
                 PanelXOffset+PANEL_W-12,PanelRowY(i),
                 PanelTextColor,PanelFontSize,g_panelFont,ANCHOR_LEFT_UPPER);
      PanelUpdateCell(i);
     }
   ChartRedraw(0);
  }

//+------------------------------------------------------------------+
//| 对指定周期独立计算高斯滤波趋势方向(与主图完全相同的算法)        |
//| 返回最后一根已收盘K线的趋势方向:1=多头 / -1=空头 / 0=中性        |
//| 数据未就绪时返回 false,调用方稍后重试                            |
//+------------------------------------------------------------------+
bool ComputeTrendDir(const int idx,int &dirOut)
  {
   dirOut=0;
   ENUM_TIMEFRAMES tf=g_panelTF[idx];

   int need=PanelBars;                    // 计算使用的历史K线数(夹取到合理区间)
   if(need<400)  need=400;
   if(need>5000) need=5000;

   datetime t0=iTime(_Symbol,tf,0);       // 记录取数时刻,跨越新K线则本次放弃
   if(t0==0)
      return(false);

   //--- 该周期K线(下标0=最旧,末尾=当前未走完K线)
   MqlRates rates[];
   ArraySetAsSeries(rates,false);
   int copied=CopyRates(_Symbol,tf,0,need,rates);
   int minBars=g_atrLength+g_effLength+80;
   if(copied<minBars)
      return(false);                      // 历史数据尚在下载,稍后重试

   //--- 该周期 ATR
   double atr[];
   ArraySetAsSeries(atr,false);
   int atrCopied=CopyBuffer(g_panelATRH[idx],0,0,copied,atr);
   if(atrCopied<minBars)
      return(false);

   if(iTime(_Symbol,tf,0)!=t0)
      return(false);                      // 取数期间产生新K线,下一秒重算

   //--- 两序列按末端(最新K线)对齐
   int m=(copied<atrCopied)?copied:atrCopied;
   int rBase=copied-m;                    // rates 偏移
   int aBase=atrCopied-m;                 // atr 偏移

   //--- 价格源序列
   double src[];
   ArrayResize(src,m);
   for(int j=0;j<m;j++)
     {
      double hi=rates[rBase+j].high, lo=rates[rBase+j].low, cl=rates[rBase+j].close;
      if(PriceSource==Src_HL2)       src[j]=(hi+lo)/2.0;
      else if(PriceSource==Src_HLC3) src[j]=(hi+lo+cl)/3.0;
      else                           src[j]=cl;
     }

   double alpha;
   GaussianAlphaBeta(g_length,g_poles,alpha);
   double emaAlpha=2.0/(g_effSmooth+1.0);

   //--- 级联高斯滤波 + 自适应通道 + 趋势线棘轮(逐K线推进)
   double s1=src[0],s2=src[0],s3=src[0],s4=src[0];
   double smoothedEff=0.0, tl=src[0];
   int dir=0;
   int last=m-2;                          // 最后一根已收盘K线的下标(m-1 为未走完K线)

   for(int j=0;j<=last;j++)
     {
      double prevTL=tl;
      s1=alpha*src[j]      +(1.0-alpha)*s1;
      s2=alpha*s1          +(1.0-alpha)*s2;
      s3=alpha*s2          +(1.0-alpha)*s3;
      s4=alpha*s3          +(1.0-alpha)*s4;
      double filtered=(g_poles<=1)?s1g_poles==2)?s2g_poles==3)?s3:s4;
      if(j==0)
        {
         tl=filtered;
         prevTL=tl;
        }

      //--- 效率比值(用于自适应通道宽度)
      double eff=0.0;
      if(j>=g_effLength)
        {
         double netMove=MathAbs(src[j]-src[j-g_effLength]);
         double pathLen=0.0;
         for(int k=j-g_effLength+1;k<=j;k++)
            pathLen+=MathAbs(src[k]-src[k-1]);
         eff=(pathLen==0.0)?0.0:netMove/pathLen;
        }
      smoothedEff=(j==0)?effemaAlpha*eff+(1.0-emaAlpha)*smoothedEff);

      //--- 自适应 / 固定趋势通道宽度
      double widthMult=AdaptiveWidth?(g_chopMult+(g_trendMult-g_chopMult)*smoothedEff):g_fixedMult;
      double atrVal=atr[aBase+j];
      double upperBand=filtered+atrVal*widthMult;
      double lowerBand=filtered-atrVal*widthMult;

      //--- 趋势线棘轮
      if(j>0)
        {
         if(upperBand<tl) tl=upperBand;
         if(lowerBand>tl) tl=lowerBand;
         if(tl>prevTL)      dir=1;
         else if(tl<prevTL) dir=-1;
        }
      else
         dir=0;
     }

   dirOut=dir;                            // 最后一根已收盘K线的趋势方向
   return(true);
  }

//+------------------------------------------------------------------+
//| 定时器:每秒检查各周期是否产生新K线,                              |
//| 某周期K线走完(出现新K线)时刷新该周期趋势状态                     |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(g_panelCount<=0)
      return;
   bool updated=false;
   for(int i=0;i<g_panelCount;i++)
     {
      datetime t=iTime(_Symbol,g_panelTF,0);
      if(t==0)
         continue;                        // 该周期历史数据尚未就绪
      if(t==g_panelBarTime)
         continue;                        // 该周期尚无新K线(未走完,无需刷新)

      int dir=0;
      if(ComputeTrendDir(i,dir))
        {
         g_panelBarTime=t;
         if(dir!=g_panelDir)           // 方向变化(或首次计算成功)才重绘
           {
            g_panelDir=dir;
            PanelUpdateCell(i);
            updated=true;
           }
        }
      // 计算失败(数据未就绪):保持原显示,下一秒自动重试
     }
   if(updated)
      ChartRedraw(0);
  }

//+------------------------------------------------------------------+
//| 将前景色向图表背景色混合(Pine 风格透明度:0=不透明,100=全透明)  |
//+------------------------------------------------------------------+
//--- 由 Pine 风格 R,G,B 分量构造 MQL5 颜色值 (0x00BBGGRR)
color RGBColor(const int r,const int g,const int b)
  {
   return (color)(r|(g<<8)|(b<<16));
  }

color BlendColor(const color fg,const int transparencyPct)
  {
   color bg=(color)ChartGetInteger(0,CHART_COLOR_BACKGROUND);
   double a=MathMax(0.0,MathMin(100.0,(double)transparencyPct))/100.0;
   int r=(int)MathRound(((fg&0xFF))*(1.0-a)+((bg&0xFF))*a);
   int g=(int)MathRound((((fg>>8)&0xFF))*(1.0-a)+(((bg>>8)&0xFF))*a);
   int b=(int)MathRound((((fg>>16)&0xFF))*(1.0-a)+(((bg>>16)&0xFF))*a);
   return (color)(r|(g<<8)|(b<<16));
  }

//+------------------------------------------------------------------+
//| 初始化                                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, TrendLineBuf,      INDICATOR_DATA);
   SetIndexBuffer(1, TrendLineColorBuf, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, InnerAValBuf,      INDICATOR_DATA);
   SetIndexBuffer(3, InnerAColorBuf,    INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4, InnerBValBuf,      INDICATOR_DATA);
   SetIndexBuffer(5, InnerBColorBuf,    INDICATOR_COLOR_INDEX);
   SetIndexBuffer(6, OuterAValBuf,      INDICATOR_DATA);
   SetIndexBuffer(7, OuterAColorBuf,    INDICATOR_COLOR_INDEX);
   SetIndexBuffer(8, OuterBValBuf,      INDICATOR_DATA);
   SetIndexBuffer(9, OuterBColorBuf,    INDICATOR_COLOR_INDEX);
   SetIndexBuffer(10,CandleOBuf,        INDICATOR_DATA);
   SetIndexBuffer(11,CandleHBuf,        INDICATOR_DATA);
   SetIndexBuffer(12,CandleLBuf,        INDICATOR_DATA);
   SetIndexBuffer(13,CandleCBuf,        INDICATOR_DATA);
   SetIndexBuffer(14,CandleColorBuf,    INDICATOR_COLOR_INDEX);
   SetIndexBuffer(15,BgTopBuf,          INDICATOR_DATA);
   SetIndexBuffer(16,BgBotBuf,          INDICATOR_DATA);

   ArraySetAsSeries(TrendLineBuf,false);      ArraySetAsSeries(TrendLineColorBuf,false);
   ArraySetAsSeries(InnerAValBuf,false);      ArraySetAsSeries(InnerAColorBuf,false);
   ArraySetAsSeries(InnerBValBuf,false);      ArraySetAsSeries(InnerBColorBuf,false);
   ArraySetAsSeries(OuterAValBuf,false);      ArraySetAsSeries(OuterAColorBuf,false);
   ArraySetAsSeries(OuterBValBuf,false);      ArraySetAsSeries(OuterBColorBuf,false);
   ArraySetAsSeries(CandleOBuf,false);        ArraySetAsSeries(CandleHBuf,false);
   ArraySetAsSeries(CandleLBuf,false);        ArraySetAsSeries(CandleCBuf,false);
   ArraySetAsSeries(CandleColorBuf,false);
   ArraySetAsSeries(BgTopBuf,false);          ArraySetAsSeries(BgBotBuf,false);

   PlotIndexSetInteger(0,PLOT_DRAW_TYPE, ShowTrend ? DRAW_COLOR_LINE : DRAW_NONE);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,(int)MathMax(1,MathMin(5,LineWidth)));
   PlotIndexSetString (0,PLOT_LABEL,"高斯滤波趋势线");

   int starDraw = ShowStars ? DRAW_COLOR_ARROW : DRAW_NONE;
   for(int p=1;p<=4;p++)
     {
      PlotIndexSetInteger(p,PLOT_DRAW_TYPE,starDraw);
      PlotIndexSetInteger(p,PLOT_ARROW,159);
     }
   PlotIndexSetString(1,PLOT_LABEL,"内侧星点A");
   PlotIndexSetString(2,PLOT_LABEL,"内侧星点B");
   PlotIndexSetString(3,PLOT_LABEL,"外侧星点A");
   PlotIndexSetString(4,PLOT_LABEL,"外侧星点B");

   PlotIndexSetInteger(5,PLOT_DRAW_TYPE, ShowCandles ? DRAW_COLOR_CANDLES : DRAW_NONE);
   PlotIndexSetString (5,PLOT_LABEL,"趋势K线着色");

   PlotIndexSetInteger(6,PLOT_DRAW_TYPE, ShowBackground ? DRAW_FILLING : DRAW_NONE);
   PlotIndexSetString (6,PLOT_LABEL,"趋势背景");

   //--- 解析预设覆盖(对应 Pine 中的 `if preset ==` 分支)
   g_length=GaussianLength; g_poles=GaussianPoles; g_atrLength=AtrLength;
   g_fixedMult=FixedMultiplier; g_effLength=EfficiencyLength;
   g_trendMult=TrendMultiplier; g_chopMult=ChopMultiplier; g_effSmooth=EfficiencySmooth;

   if(PresetConfiguration==Fast_Response)
     {
      g_length=8; g_poles=2; g_atrLength=10; g_fixedMult=1.2;
      g_effLength=7; g_trendMult=0.6; g_chopMult=1.8; g_effSmooth=3;
     }
   else if(PresetConfiguration==Smooth_Trend)
     {
      g_length=21; g_poles=4; g_atrLength=21; g_fixedMult=2.0;
      g_effLength=18; g_trendMult=1.0; g_chopMult=3.2; g_effSmooth=8;
     }
   g_poles=(int)MathMax(1,MathMin(4,g_poles));

   //--- 解析颜色预设(对应 Pine 中的 `switch color_preset`)
   switch(ColorPreset)
     {
      case Color_Classic: g_bullish=RGBColor(0x00,0xFF,0x00); g_bearish=RGBColor(0xFF,0x00,0x00); break;
      case Color_Aqua:    g_bullish=RGBColor(0x00,0xD4,0xFF); g_bearish=RGBColor(0xFF,0x8C,0x00); break;
      case Color_Cosmic:  g_bullish=RGBColor(0x49,0xFF,0xCE); g_bearish=RGBColor(0x99,0x32,0xCC); break;
      case Color_Cyber:   g_bullish=RGBColor(0x00,0xCC,0xCC); g_bearish=RGBColor(0xFF,0x66,0x00); break;
      case Color_Neon:    g_bullish=RGBColor(0xFF,0xFF,0x00); g_bearish=RGBColor(0xFF,0x00,0xFF); break;
      default:            g_bullish=BullishInput;    g_bearish=BearishInput;   break;
     }

   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,g_bullish);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,g_bearish);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,NeutralInput);
   for(int p=1;p<=4;p++)
     {
      int trans = (p<=2) ? 30 : 70; // 内侧星点约30%透明,外侧星点约70%透明
      PlotIndexSetInteger(p,PLOT_LINE_COLOR,0,BlendColor(g_bullish,trans));
      PlotIndexSetInteger(p,PLOT_LINE_COLOR,1,BlendColor(g_bearish,trans));
      PlotIndexSetInteger(p,PLOT_LINE_COLOR,2,BlendColor(NeutralInput,trans));
     }
   PlotIndexSetInteger(5,PLOT_LINE_COLOR,0,BlendColor(g_bullish,BarTransparency));
   PlotIndexSetInteger(5,PLOT_LINE_COLOR,1,BlendColor(g_bearish,BarTransparency));
   PlotIndexSetInteger(5,PLOT_LINE_COLOR,2,clrNONE);
   PlotIndexSetInteger(6,PLOT_LINE_COLOR,0,BlendColor(g_bullish,BgTransparency));
   PlotIndexSetInteger(6,PLOT_LINE_COLOR,1,BlendColor(g_bearish,BgTransparency));

   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"高斯滤波趋势+多周期面板");

   g_atrHandle=iATR(_Symbol,_Period,g_atrLength);
   if(g_atrHandle==INVALID_HANDLE)
      return(INIT_FAILED);

   //--- 多周期趋势面板初始化
   g_panelCount=0;
   if(ShowPanel)
     {
      if(!ParsePanelTimeframes())
         Print("多周期面板:周期列表为空或全部无法识别,本次不显示面板。");
      else
        {
         //--- 为每个面板周期创建 ATR 句柄(首次访问会自动下载该周期数据)
         for(int i=0;i<g_panelCount;i++)
            g_panelATRH=iATR(_Symbol,g_panelTF,g_atrLength);
         g_panelRowH=PanelFontSize*2;
         PanelCreate();               // 先显示"加载中",数据就绪后自动填充
         EventSetTimer(1);            // 每秒检查各周期新K线(K线走完后刷新状态)
        }
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| 反初始化                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   if(g_atrHandle!=INVALID_HANDLE)
      IndicatorRelease(g_atrHandle);
   for(int i=0;i<g_panelCount;i++)
      if(g_panelATRH!=INVALID_HANDLE)
         IndicatorRelease(g_panelATRH);
   ObjectsDeleteAll(0,g_panelPrefix);   // 删除面板全部对象
   ChartRedraw(0);
  }

//+------------------------------------------------------------------+
//| 高斯滤波 beta/alpha 计算                                          |
//+------------------------------------------------------------------+
void GaussianAlphaBeta(int length,int poles,double &alpha)
  {
   double beta = (1.0-MathCos(2.0*M_PI/length))/(MathPow(1.414,2.0/poles)-1.0);
   alpha = -beta + MathSqrt(beta*beta + 2.0*beta);
  }

//+------------------------------------------------------------------+
//| 主计算(当前图表周期)                                            |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(rates_total < g_atrLength+2)
      return(0);

   ArraySetAsSeries(time,false);
   ArraySetAsSeries(open,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(close,false);

   ArrayResize(Stage1,rates_total); ArrayResize(Stage2,rates_total);
   ArrayResize(Stage3,rates_total); ArrayResize(Stage4,rates_total);
   ArrayResize(SmoothedEff,rates_total);
   ArrayResize(TrendDir,rates_total);

   double atrBuf[];
   ArraySetAsSeries(atrBuf,false);
   int atrCopied=CopyBuffer(g_atrHandle,0,0,rates_total,atrBuf);
   if(atrCopied<=0)
      return(0);

   double src[];
   ArrayResize(src,rates_total);
   for(int i=0;i<rates_total;i++)
     {
      if(PriceSource==Src_HL2)       src=(high+low)/2.0;
      else if(PriceSource==Src_HLC3) src=(high+low+close)/3.0;
      else                           src=close;
     }

   double alpha;
   GaussianAlphaBeta(g_length,g_poles,alpha);

   double emaAlpha = 2.0/(g_effSmooth+1.0);
   double visSpan[];
   ArrayResize(visSpan,rates_total);

   int start=(prev_calculated>1)?prev_calculated-1:0;

   for(int i=start;i<rates_total;i++)
     {
      //--- 级联高斯滤波
      double prev1 = (i==0)? src : Stage1[i-1];
      double prev2 = (i==0)? src : Stage2[i-1];
      double prev3 = (i==0)? src : Stage3[i-1];
      double prev4 = (i==0)? src : Stage4[i-1];
      Stage1 = alpha*src      + (1.0-alpha)*prev1;
      Stage2 = alpha*Stage1   + (1.0-alpha)*prev2;
      Stage3 = alpha*Stage2   + (1.0-alpha)*prev3;
      Stage4 = alpha*Stage3   + (1.0-alpha)*prev4;
      double filtered = (g_poles<=1)?Stage1 : (g_poles==2)?Stage2 : (g_poles==3)?Stage3 : Stage4;

      //--- 效率比值
      double effRatio=0.0;
      if(i>=g_effLength)
        {
         double netMove=MathAbs(src-src[i-g_effLength]);
         double pathLen=0.0;
         for(int j=i-g_effLength+1;j<=i;j++)
            pathLen += MathAbs(src[j]-src[j-1]);
         effRatio = (pathLen==0.0)?0.0:netMove/pathLen;
        }
      double prevSmoothed = (i==0)? effRatio : SmoothedEff[i-1];
      SmoothedEff = (i==0)? effRatio : (emaAlpha*effRatio + (1.0-emaAlpha)*prevSmoothed);

      //--- 自适应 / 固定趋势通道宽度
      double widthMult = AdaptiveWidth ? (g_chopMult + (g_trendMult-g_chopMult)*SmoothedEff) : g_fixedMult;
      double atrVal = (i<atrCopied)? atrBuf : 0.0;
      double trendWidth = atrVal*widthMult;
      double upperBand = filtered+trendWidth;
      double lowerBand = filtered-trendWidth;

      //--- 趋势线棘轮
      double prevTL = (i==0)? filtered : TrendLineBuf[i-1];
      double tl = prevTL;
      if(upperBand<tl) tl=upperBand;
      if(lowerBand>tl) tl=lowerBand;
      TrendLineBuf=tl;

      int prevDir = (i==0)?0:TrendDir[i-1];
      int dir=prevDir;
      if(i>0)
        {
         if(tl>prevTL)      dir=1;
         else if(tl<prevTL) dir=-1;
        }
      TrendDir=dir;

      double colIdx = (dir==1)?0.0dir==-1)?1.0:2.0;
      TrendLineColorBuf=colIdx;

      //--- 星空散点
      if(i>0) visSpan=visSpan[i-1]; // 先沿用旧值,累计足够K线后会被下方覆盖
      double sumRange=0.0; int cnt=0;
      for(int j=MathMax(0,i-13);j<=i;j++){ sumRange += (high[j]-low[j]); cnt++; }
      visSpan= (cnt>0)? sumRange/cnt : 0.0;

      double theta = i*0.52;
      double innerOrbit = visSpan*0.85;
      double outerOrbit = visSpan*1.75;

      InnerAValBuf = tl + MathSin(theta)*innerOrbit;
      InnerBValBuf = tl + MathSin(theta+M_PI)*innerOrbit;
      OuterAValBuf = tl + MathCos(theta*0.71+1.1)*outerOrbit;
      OuterBValBuf = tl + MathCos(theta*0.71+1.1+M_PI)*outerOrbit;
      InnerAColorBuf=colIdx; InnerBColorBuf=colIdx;
      OuterAColorBuf=colIdx; OuterBColorBuf=colIdx;

      //--- K线着色覆盖(对应 Pine 的 barcolor(),中性K线不着色)
      CandleOBuf=open; CandleHBuf=high; CandleLBuf=low; CandleCBuf=close;
      CandleColorBuf= (dir==0)?2.0:colIdx;

      //--- 背景着色(对应 Pine 的 bgcolor(),中性K线不着色)
      if(dir==0)
        {
         BgTopBuf=EMPTY_VALUE;
         BgBotBuf=EMPTY_VALUE;
        }
      else
        {
         double mid=close;
         double span=MathMax(atrVal*50.0, (high-low)*50.0+_Point*1000);
         if(dir==1) { BgTopBuf=mid+span; BgBotBuf=mid-span; }
         else       { BgTopBuf=mid-span; BgBotBuf=mid+span; }
        }

      //--- 刚收盘K线上出现趋势反转时报警
      if(EnableAlerts && i==rates_total-2 && i>0)
        {
         bool turnedBull = (dir==1 && prevDir!=1);
         bool turnedBear = (dir==-1 && prevDir!=-1);
         if(turnedBull && g_lastAlertBull!=time)
           {
            Alert(StringFormat("高斯滤波趋势:%s %s 多头趋势确认 ↑",_Symbol,TFToText((ENUM_TIMEFRAMES)_Period)));
            g_lastAlertBull=time;
           }
         if(turnedBear && g_lastAlertBear!=time)
           {
            Alert(StringFormat("高斯滤波趋势:%s %s 空头趋势确认 ↓",_Symbol,TFToText((ENUM_TIMEFRAMES)_Period)));
            g_lastAlertBear=time;
           }
        }
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+


06cd3e97-a99a-4548-aa76-4b0237e10738.png
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|量化魔方 ( 陕ICP备2025062059号-3 )|网站地图

GMT+8, 2026-9-16 02:26 , Processed in 0.188714 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表