|
|
//+------------------------------------------------------------------+
//| 高斯滤波趋势 + 多周期趋势面板.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)?s1 g_poles==2)?s2 g_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)?eff emaAlpha*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.0 dir==-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);
}
//+------------------------------------------------------------------+
|
-
|