价格行为分析工具包开发(第十八部分):四分位理论(3)四分位看板·综合运用
(3/3)·手改布尔开关调四分位线太磨人?这篇把绘图脚本收口成可点击看板
按钮配色与图形对象的清理逻辑
在 MT5 自定义指标里,用 ObjectSetInteger 给三个控制按钮按开关变量切换颜色,是常见做法。下面这段代码把 SMALL_QUARTERS、OVERSHOOT、TREND 三个按钮的 OBJPROP_COLOR 直接绑定到对应的全局布尔量,开就染 onColor、关就染 offColor,省得在事件回调里反复判断。 DeleteQuarterLines 负责把已画的价位参考线全清掉。注意它用两段循环:第一段 i 从 1 到 3,删 LargeQuarter_、Overshoot_ 上冲和 Undershoot_ 下穿共 9 个对象;第二段 seg 从 0 到 9、j 从 1 到 3,删掉 30 根 SmallQuarter 小分位线。总共最多 39 个对象名,命名规则固定,手动在对象列表里也能对照着删。 趋势注解的维护分两个函数:DeleteTrendComment 只删 TREND_LABEL 一个文本对象;UpdateTrendComment 则取当前 SYMBOL_BID,若非零就建一个 50 周期收盘 SMA 句柄,CopyBuffer 取倒数第二根(shift=1)的值做方向参考。外汇与贵金属波动大,这类 SMA 仅作概率倾向判断,不预示必然方向。 开 MT5 把这段塞进你的指标源码,改一下 onColor / offColor 常量,就能直观看到按钮状态和图形层联动。
ObjectSetInteger(class="num">0, BUTTON_SMALL, OBJPROP_COLOR, g_DrawSmallQuarters ? onColor : offColor); ObjectSetInteger(class="num">0, BUTTON_OVERSHOOT, OBJPROP_COLOR, g_DrawOvershootAreas ? onColor : offColor); ObjectSetInteger(class="num">0, BUTTON_TREND, OBJPROP_COLOR, g_DrawTrendDirection ? onColor : offColor); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Delete quarter lines | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DeleteQuarterLines() { ObjectDelete(class="num">0, "MajorLower"); ObjectDelete(class="num">0, "MajorUpper"); for(class="type">int i = class="num">1; i < class="num">4; i++) { ObjectDelete(class="num">0, "LargeQuarter_" + IntegerToString(i)); ObjectDelete(class="num">0, "Overshoot_" + IntegerToString(i) + "_up"); ObjectDelete(class="num">0, "Undershoot_" + IntegerToString(i) + "_down"); } for(class="type">int seg = class="num">0; seg < class="num">10; seg++) { for(class="type">int j = class="num">1; j < class="num">4; j++) { ObjectDelete(class="num">0, "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j)); } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Delete trend commentary | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DeleteTrendComment() { ObjectDelete(class="num">0, TREND_LABEL); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Update trend commentary | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void UpdateTrendComment() { class="type">class="kw">double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(currentPrice == class="num">0) class="kw">return; class="type">class="kw">double smaValue = class="num">0.0; class="type">class="kw">double buffer[]; class="type">int handle = iMA(_Symbol, PERIOD_CURRENT, class="num">50, class="num">0, MODE_SMA, PRICE_CLOSE); if(handle != INVALID_HANDLE) { if(CopyBuffer(handle, class="num">0, class="num">1, class="num">1, buffer) > class="num">0) smaValue = buffer[class="num">0]; IndicatorRelease(handle); } class="type">class="kw">string trendComment;
「面板里的趋势判定与辅助线绘制」
在自定义面板里给趋势方向贴标签,核心就是拿当前价和 SMA 值比大小:大于判 Uptrend,小于判 Downtrend,相等归 Sideways。这段逻辑直接决定后续标签文本,写的时候注意等于分支别漏,否则横盘会被误判成前一次的状态。 标签坐标靠按钮布局反推:trendButtonY 取面板顶边往下 10 像素再加 3 组(按钮高+间距),标签再错开一个按钮高度和间距,X 统一缩进 10 像素。用 ObjectFind 判 -1 才创建 OBJ_LABEL,避免每帧重画闪屏;字号设 14、白色、左上角锚定,肉眼读起来不费劲。 画水平线封装成 DrawHorizontalLine,先找后删再建,OBJ_HLINE 的 RAY_RIGHT 设 true 让线往右无限延伸。外汇和贵金属点差跳动快,BID 取 0 时直接 return,能避开凌晨流动性断层导致的画线崩溃。 季度线按 MajorStep 向下取整铺:lowerMajor = MathFloor(currentPrice/MajorStep)*MajorStep,以 XAUUSD 为例 MajorStep 设 100 时,市价 2033.4 会落出 2000 基准线。这类辅助线只作结构参考,实际突破概率仍受利率事件扰动,属高风险品种请自行验证。
if(currentPrice > smaValue) trendComment = "Uptrend"; else if(currentPrice < smaValue) trendComment = "Downtrend"; else trendComment = "Sideways"; class=class="str">"cmt">// Calculate the position for the commentary label below the Trend Direction button class="type">int trendButtonY = PanelY + class="num">10 + class="num">3 * (ButtonHeight + ButtonSpacing); class="type">int trendLabelY = trendButtonY + ButtonHeight + ButtonSpacing; class="type">int trendLabelX = PanelX + class="num">10; if(ObjectFind(class="num">0, TREND_LABEL) == -class="num">1) { ObjectCreate(class="num">0, TREND_LABEL, OBJ_LABEL, class="num">0, class="num">0, class="num">0); ObjectSetInteger(class="num">0, TREND_LABEL, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(class="num">0, TREND_LABEL, OBJPROP_XDISTANCE, trendLabelX); ObjectSetInteger(class="num">0, TREND_LABEL, OBJPROP_YDISTANCE, trendLabelY); ObjectSetInteger(class="num">0, TREND_LABEL, OBJPROP_COLOR, clrWhite); ObjectSetInteger(class="num">0, TREND_LABEL, OBJPROP_FONTSIZE, class="num">14); } class="type">class="kw">string txt = "Trend Direction: " + trendComment; ObjectSetString(class="num">0, TREND_LABEL, OBJPROP_TEXT, txt); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Draw horizontal line utility | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DrawHorizontalLine(class="type">class="kw">string name, class="type">class="kw">double price, class="type">class="kw">color lineColor, class="type">int width, ENUM_LINE_STYLE style) { if(ObjectFind(class="num">0, name) != -class="num">1) ObjectDelete(class="num">0, name); if(!ObjectCreate(class="num">0, name, OBJ_HLINE, class="num">0, class="num">0, price)) { Print("Failed to create line: ", name); class="kw">return; } ObjectSetInteger(class="num">0, name, OBJPROP_COLOR, lineColor); ObjectSetInteger(class="num">0, name, OBJPROP_STYLE, style); ObjectSetInteger(class="num">0, name, OBJPROP_WIDTH, width); ObjectSetInteger(class="num">0, name, OBJPROP_RAY_RIGHT, true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Draw quarter lines based on toggle settings | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DrawQuarterLines() { DeleteQuarterLines(); class="type">class="kw">double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(currentPrice == class="num">0) class="kw">return; class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
◍ 大区间内的四分位与穿透带绘制
在主区间上下边界确定后,代码先把上边界算为下边界加 MajorStep,并分别画出主区间的两条水平线。若开启大四分位开关,会把主区间均分成 4 份,在 1/4、2/4、3/4 处生成三条次级线,名称用 LargeQuarter_1 到 _3 区分。 穿透带的逻辑嵌在四分位循环里:当 g_DrawOvershootAreas 为真,会以 MajorStep/40.0 为半宽,在每条大四分位上下各画一条线,形成约主区间 2.5% 宽度的缓冲带。价格触碰这类带子时,倾向视为对整数位的假突破或回拉,外汇与贵金属波动大,这种带子只作参考而非确认信号。 小四分位则是把主区间先切 10 段、每段再切 4 份,循环变量 seg 从 0 到 9、j 从 1 到 3,共生成 30 条线。线名带双下标如 SmallQuarter_3_2,方便在对象列表里定位。把下面代码直接贴进 MT5 自定义指标,改 g_DrawLargeQuarters 等开关就能看到图层变化。
class="type">class="kw">double upperMajor = lowerMajor + MajorStep; DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle); DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle); if(g_DrawLargeQuarters) { class="type">class="kw">double LQIncrement = MajorStep / class="num">4.0; for(class="type">int i = class="num">1; i < class="num">4; i++) { class="type">class="kw">double level = lowerMajor + i * LQIncrement; class="type">class="kw">string objName = "LargeQuarter_" + IntegerToString(i); DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle); if(g_DrawOvershootAreas) { class="type">class="kw">double smallQuarter = MajorStep / class="num">40.0; DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle); DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle); } } } if(g_DrawSmallQuarters) { class="type">class="kw">double segStep = MajorStep / class="num">10.0; class="type">class="kw">double smallQuarter = segStep / class="num">4.0; for(class="type">int seg = class="num">0; seg < class="num">10; seg++) { class="type">class="kw">double segStart = lowerMajor + seg * segStep; for(class="type">int j = class="num">1; j < class="num">4; j++) { class="type">class="kw">double level = segStart + j * smallQuarter; class="type">class="kw">string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j); DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle); } } }
面板状态与实测价位的对应关系
把 EA 拖到 EURUSD 图表后,控制面板直接显示四类开关:大四分位线、上冲/下探初始为绿色文字,代表禁用;小四分位线、趋势方向为红色文字,代表启用。点按钮即可让对应价位线在图上显隐,不需要进参数面板改设置。 实测截图中,大四分位线(蓝色实线)和上冲/下探(红色虚线)处于启用,按钮文本颜色与图上价线同时存在,可交叉验证。趋势方向启用后,图表评论实时变成“上涨趋势”,说明状态读取是跟着 tick 走的,不是写死的。 小四分位按钮在实测图里是红色,对应价位线不显示——这一项关掉后,图表干净很多,适合只盯大区间和假突破的交易者。外汇与贵金属杠杆高、滑点大,面板状态只是辅助判读,实盘前请在 MT5 策略测试器里先用历史数据跑一遍确认逻辑。
「把工具请下神坛」
带按钮的四分位看板已经能让你单击切换水平位,初始化或取消都不再依赖手动画线;同一套面板还能顺带给出当前价格相对四分位的趋势倾向,帮你判断市场是在大四分位之间游走还是已经突破。外汇与贵金属市场高波动,这类辅助判断只降低操作摩擦,不替你过滤风险。 从 01/10/24 的图表展示器到 11/03/25 的四分位看板,18 个工具横跨重影脚本、Telegram 推送、布林带+RSI+ATR 的波动率导航仪,直到可交互面板,路线很清楚:先把价格行为可视化,再逐步把控制权交回交易者手里。 打开 MT5 把 Quarters_Board.mq5 拖进图表,点一下按钮看水平位隐现,比读任何说明都直观;真要验证价值,只在你自己的行情里跑两遍。