价格行为分析工具包开发(第十五部分):引入四分位理论(1)四分位绘图脚本·进阶篇
「先给水平线定好样式与画法」
做整数位与四分位参考线,第一步是把线的样式和粗细参数暴露给输入变量,方便在 MT5 属性框里直接调。下面这组 input 把主线、大四分位、溢出线、小四分位分别定义了线型与宽度:主线用实线宽 4,大四分位用点线宽 3,溢出线用虚线宽 1,小四分位用实线宽 1;溢出线颜色单独设为红色(clrRed),用来标记价格越过整数边界后的回测区。 核心画图靠 DrawHorizontalLine 这个函数:先用 ObjectFind 查重,若存在就 ObjectDelete 删掉旧对象,再 ObjectCreate 建 OBJ_HLINE 水平线。注意创建时传的日期参数是 0、价格为传入的 price,说明它不绑定时点,纯水平。 建完立刻用 ObjectSetInteger 写四个属性:颜色、线型、宽度、以及 OBJPROP_RAY_RIGHT 置 true,让线向右无限延伸。这样每次 OnStart 重跑,线会被覆盖刷新而不是越画越多。 OnStart 里取 _Symbol 的 SYMBOL_BID 作当前价,用 MathFloor(currentPrice / MajorStep) * MajorStep 算出下边界整数区,加 MajorStep 得上边界。以 XAUUSD 为例,若 MajorStep=100、现价 2034.5,下边界 2000、上边界 2100,两条主线就落在这两个整数上;DrawLargeQuarters 开启时,再按 MajorStep/4 循环画 3 条大四分位线(i=1,2,3)。外汇与贵金属波动剧烈,这类参考线仅作区域概率判断,实盘须自担高风险。
input ENUM_LINE_STYLE MajorLineStyle = STYLE_SOLID; input class="type">int MajorLineWidth = class="num">4; input ENUM_LINE_STYLE LargeQuarterLineStyle = STYLE_DOT; input class="type">int LargeQuarterLineWidth = class="num">3; input ENUM_LINE_STYLE OvershootLineStyle = STYLE_DASH; input class="type">int OvershootLineWidth = class="num">1; input ENUM_LINE_STYLE SmallQuarterLineStyle = STYLE_SOLID; input class="type">int SmallQuarterLineWidth = class="num">1; input class="type">class="kw">color OvershootColor = clrRed; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| DrawHorizontalLine: Creates or replaces a horizontal line | 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) { class=class="str">"cmt">// Delete the object if it already exists if(ObjectFind(class="num">0, name) != -class="num">1) ObjectDelete(class="num">0, name); class=class="str">"cmt">// Create a new horizontal line object if(!ObjectCreate(class="num">0, name, OBJ_HLINE, class="num">0, class="num">0, price)) { Print("Failed to create line: ", name); class="kw">return; } class=class="str">"cmt">// Set properties: class="type">class="kw">color, style, width, and extension to the right 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="type">void OnStart() { class=class="str">"cmt">// Get current symbol price class="type">class="kw">string symbol = _Symbol; class="type">class="kw">double currentPrice = SymbolInfoDouble(symbol, SYMBOL_BID); if(currentPrice == class="num">0) class="kw">return; class=class="str">"cmt">// Calculate the major range based on the current price and MajorStep class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep; class="type">class="kw">double upperMajor = lowerMajor + MajorStep; class=class="str">"cmt">// Draw Major Whole Number lines at lower and upper boundaries DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle); DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle); class=class="str">"cmt">// Draw Large Quarter lines and overshoot/undershoot lines if enabled if(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;
大季度线之外的偏移区与小季度线绘制
大季度水平线画完后,若开关 DrawOvershootAreas 为真,会在每条大季度线上下各推一个微小区间。这个微小量取 MajorStep 的 1/40,即把主阶等分成 40 份后的单份宽度,用来标记价格可能短暂刺穿大季度位的「过冲 / 下冲」地带。 小季度线的粒度更细:先算 segStep = MajorStep / 10.0,再取 smallQuarter = segStep / 4.0,也就是主阶的 1/40。循环把每个主阶切成 10 段,每段内部在 1/4、2/4、3/4 处落三条线,最终每主阶出 30 条小季度线。 图表右上角会常驻一个 OBJ_LABEL 文本标签,内容写死版本与作者信息,距右边 80 像素、上边 10 像素、字号 14、黄色。每次重跑脚本先 ObjectFind 删旧标签再建新的,避免堆叠。 所有对象画完调用 ChartRedraw() 强制刷新。外汇与贵金属价格行为受事件驱动,这些参考线仅辅助读位,刺穿概率随波动率变化,实盘请自验。
class="type">class="kw">string objName = "LargeQuarter_" + IntegerToString(i); DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle); if(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); } class=class="str">"cmt">// Draw Small Quarter lines if enabled if(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); } } } class=class="str">"cmt">// Create a persistent label(logo) in the top-right corner if(ObjectFind(class="num">0, "ScriptLogo") != -class="num">1) ObjectDelete(class="num">0, "ScriptLogo"); if(ObjectCreate(class="num">0, "ScriptLogo", OBJ_LABEL, class="num">0, class="num">0, class="num">0)) { class="type">class="kw">string logoText = "Script: DrawQuarters_DarkBold\nv1.class="num">04\nby Christian Benjamin"; ObjectSetString(class="num">0, "ScriptLogo", OBJPROP_TEXT, logoText); ObjectSetInteger(class="num">0, "ScriptLogo", OBJPROP_COLOR, clrYellow); ObjectSetInteger(class="num">0, "ScriptLogo", OBJPROP_FONTSIZE, class="num">14); ObjectSetInteger(class="num">0, "ScriptLogo", OBJPROP_CORNER, CORNER_RIGHT_UPPER); ObjectSetInteger(class="num">0, "ScriptLogo", OBJPROP_XDISTANCE, class="num">80); ObjectSetInteger(class="num">0, "ScriptLogo", OBJPROP_YDISTANCE, class="num">10); } class=class="str">"cmt">// Redraw the chart to display all objects ChartRedraw();
◍ 把整数位与四分位画进图表
这套指标把价格轴按「整数大关 + 大四分位 + 小四分位」三层结构铺到 MT5 图上,MajorStep 默认 0.1000,意味着每 100 点画一条暗石板灰的实心主线,适合 EURUSD 这类报价精确到小数点后四位的品种。 大四分位(暗红点线)和小四分位(深蓝实线,宽 1)分别由 DrawLargeQuarters、DrawSmallQuarters 开关控制;前者把每个整数段再切 4 份,后者继续切细。OvershootColor 用纯红标出大四分位附近的穿越区,线型为虚线、宽 1,帮你肉眼捕捉假突破。 DrawHorizontalLine 是核心函数:先 ObjectFind 查重,若已存在同名对象就 ObjectDelete 清掉再重画,避免历史线堆积。下面这段代码是函数头部与查重逻辑,直接拷进 MQ5 文件就能用。 外汇与贵金属杠杆高、滑点大,这类辅助线只提示结构位,进出场仍要结合实时盘口与风控。
class=class="str">"cmt">//| Copyright class="num">2025, Christian Benjamin| class=class="str">"cmt">//| [MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Christian Benjamin" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.0" class="macro">#class="kw">property strict class=class="str">"cmt">//---- Input parameters ------------------------------------------------- input class="type">class="kw">double MajorStep = class="num">0.1000; class=class="str">"cmt">// Difference between major whole numbers. input class="type">bool DrawLargeQuarters = true; class=class="str">"cmt">// Draw intermediate large quarter lines. input class="type">bool DrawSmallQuarters = true; class=class="str">"cmt">// Draw small quarter lines. input class="type">bool DrawOvershootAreas = true; class=class="str">"cmt">// Mark overshoot/undershoot areas for large quarter lines. class=class="str">"cmt">//---- Color settings --------------------------------------------------- input class="type">class="kw">color MajorColor = 0x2F4F4F; class=class="str">"cmt">// Dark Slate Gray for major lines. input class="type">class="kw">color LargeQuarterColor = 0x8B0000; class=class="str">"cmt">// Dark Red for large quarter lines. input class="type">class="kw">color SmallQuarterColor = 0x00008B; class=class="str">"cmt">// Dark Blue for small quarter lines. input class="type">class="kw">color OvershootColor = clrRed; class=class="str">"cmt">// Red for overshoot/undershoot lines. class=class="str">"cmt">//---- Group style and thickness settings ------------------------------- input ENUM_LINE_STYLE MajorLineStyle = STYLE_SOLID; input class="type">int MajorLineWidth = class="num">4; input ENUM_LINE_STYLE LargeQuarterLineStyle = STYLE_DOT; input class="type">int LargeQuarterLineWidth = class="num">3; input ENUM_LINE_STYLE OvershootLineStyle = STYLE_DASH; input class="type">int OvershootLineWidth = class="num">1; class=class="str">"cmt">// For small quarter lines, we now use a continuous(solid) style. input ENUM_LINE_STYLE SmallQuarterLineStyle = STYLE_SOLID; input class="type">int SmallQuarterLineWidth = class="num">1; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| DrawHorizontalLine: Creates or replaces a horizontal line | 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);
「把价位网格画进图表的那段入口逻辑」
OnStart 是脚本跑起来的唯一入口,先抓当前品种的 BID 价:SymbolInfoDouble(_Symbol, SYMBOL_BID) 拿到后若返回 0 直接 return,避免在非交易时段或离线图表上瞎画。 以 MajorStep 为中枢,用 MathFloor(currentPrice / MajorStep) * MajorStep 向下取整得到下边界 lowerMajor,再加一步得 upperMajor,这两条大数线就是整数关卡的上下沿。 大四分之一线按 MajorStep/4.0 切三刀(i=1,2,3),若开了 DrawLargeQuarters 就逐条 DrawHorizontalLine;同时若 DrawOvershootAreas 为真,会在每个大四分之一线正负 MajorStep/40.0 处补画 overshoot/undershoot 辅助线,用来观察价格刺穿后的回归概率。 小四分之一线走的是 MajorStep/10.0 分十段、每段再除 4.0 的更密逻辑,仅画连续线不画刺穿区,适合 EURUSD 这类点差小的品种做微观支撑阻力参考。外汇与贵金属杠杆高,网格仅作结构参考,实盘须自担滑点与跳空风险。
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">//| Script entry point | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">// Get current symbol price class="type">class="kw">string symbol = _Symbol; class="type">class="kw">double currentPrice = SymbolInfoDouble(symbol, SYMBOL_BID); if(currentPrice == class="num">0) class="kw">return; class=class="str">"cmt">// Calculate the major range class="type">class="kw">double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep; class="type">class="kw">double upperMajor = lowerMajor + MajorStep; class=class="str">"cmt">// Draw Major Whole Number lines DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle); DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle); class=class="str">"cmt">// Draw Large Quarter lines and their overshoot/undershoot lines if(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(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); } } } class=class="str">"cmt">// Draw Small Quarter lines if enabled(continuous lines, without overshoot/undershoot) if(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++) {