使用 MQL5 绘制阻力和支撑级别·综合运用
📘

使用 MQL5 绘制阻力和支撑级别·综合运用

第 3/3 篇

「用柱线索引解支撑阻力线方程」

已经拿到四根极值柱的索引和对应高低价,下一步是把阻力和支撑线填进数组。线方程用 y = kx + b:x 是柱线索引,y 是价格(支撑取最低价、阻力取最高价),这样能避开用 1970 年以来秒数做 x 轴时休市区造成的折线错乱。 求 k、b 只需要两个同线极值点代入。把两组 (x,y) 联立,得到 K=(price_2-price_1)/(_bar2-_bar1) 和 B=price_1-K*_bar1,全局变量 K、B 即线系数。 Level() 被 OnCalculate 调两次:_line=false 算支撑、=true 算阻力;_first_ext 决定取哪两个极值柱。下面这段是核心求解与拷贝高低价的部分,注意 CopyHigh/CopyLow 的 bars 数量直接决定扫描深度。 别把索引当时间轴用 若拿 Time[] 秒数当 x,周末和停盘会在图上拉出斜飞线段,MT5 里画出的趋势线会明显偏离肉眼通道。坚持用柱序号,外汇和贵金属本就跳空频繁,乱轴只会放大误判。

MQL5 / C++
K=(price_2-price_1)/(_bar2-_bar1);&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//查找系数 K</span>
B=price_1-K*_bar1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//查找系数 B</span>
<span class="keyword">class="type">class="kw">double</span> K,B;
<span class="keyword">class="type">int</span> _bar1,_bar2;
<span class="keyword">class="type">class="kw">double</span> price_1,price_2;
<span class="keyword">class="type">void</span> Level(<span class="keyword">class="type">bool</span> _line,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//参数定义需要查找阻力和支撑线的哪根系数</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">class="type">bool</span> _first_ext,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//第一个极值的类型 (您已经熟悉了)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; st_Bars &amp;bars_ext,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//包含柱线索引的结构</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">class="type">class="kw">string</span> _symbol,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//品种</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="macro">ENUM_TIMEFRAMES</span> _period) <span class="comment">class=class="str">"cmt">//图表周期</span>
&nbsp;&nbsp;{
&nbsp;&nbsp; <span class="keyword">class="type">int</span> bars=Bars_H;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//分析柱线的数量</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> m_high[],m_low[];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//数组初始化</span>
&nbsp;&nbsp; <span class="functions">ArraySetAsSeries</span>(m_high,<span class="macro">true</span>);&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//数组从第一个元素开始索引</span>
&nbsp;&nbsp; <span class="functions">ArraySetAsSeries</span>(m_low,<span class="macro">true</span>);&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//...</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span> h_high = <span class="functions">CopyHigh</span>(_symbol, _period, <span class="number">class="num">0</span>, bars, m_high); <span class="comment">class=class="str">"cmt">//以蜡烛的最高价填充数组</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span> h_low = <span class="functions">CopyLow</span>(_symbol, _period, <span class="number">class="num">0</span>, bars, m_low);&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//以蜡烛的最低价填充数组</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> price_1,price_2;
&nbsp;&nbsp; <span class="keyword">class="type">int</span> _bar1,_bar2;
&nbsp;&nbsp; <span class="keyword">class="type">int</span> digits=(<span class="keyword">class="type">int</span>)<span class="functions">SymbolInfoInteger</span>(_symbol,<span class="macro">SYMBOL_DIGITS</span>);<span class="comment">class=class="str">"cmt">//当前品种的小数点位数</span>
&nbsp;&nbsp; <span class="keyword">if</span>(_line==<span class="macro">true</span>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//如果所需是阻力线</span>
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span>(_first_ext==<span class="macro">true</span>) <span class="comment">class=class="str">"cmt">//如果第一个极值是最大值</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; price_1 = <span class="functions">NormalizeDouble</span>(m_high[bars_ext.Bar_1], digits);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; price_2 = <span class="functions">NormalizeDouble</span>(m_high[bars_ext.Bar_3], digits);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bar1 = bars_ext.Bar_1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bar2 = bars_ext.Bar_3;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//如果是最小值</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; price_1 = <span class="functions">NormalizeDouble</span>(m_high[bars_ext.Bar_2], digits);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; price_2 = <span class="functions">NormalizeDouble</span>(m_high[bars_ext.Bar_4], digits);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bar1 = bars_ext.Bar_2;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _bar2 = bars_ext.Bar_4;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp; <span class="keyword">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//如果所需是支撑线</span>
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span>(_first_ext==<span class="macro">true</span>) <span class="comment">class=class="str">"cmt">//如果第一个极值是最大值</span>

用两点斜率把支撑阻力画成直线

这段代码在做一件事:取两段低点连成一条直线,把斜率 K 和截距 B 算出来,再灌进 buffer 里让 MT5 把线画出来。分叉逻辑在于,如果当前不是最小值,就取 Bar_2 和 Bar_4 的低点;是最小值则退一格取 Bar_1 和 Bar_3,目的都是避开极值噪声。 K=(price_2-price_1)/(_bar2-_bar1) 就是两点求斜率,B=price_1-K*_bar1 把直线平移到坐标系上。注意 price 全部过了 NormalizeDouble,小数位和品种 digits 对齐,不然 EURUSD 跑出 5 位、XAUUSD 跑出 3 位会直接画线错位。 后面两个 for 循环把 K*i+B 写进 resistanceBuffer 和 supportBuffer,i 是 bar 索引,从 0 到 Bars_H-1。外汇和贵金属杠杆高、跳空频繁,这种线性外推只在波段内有效,破位后 K 和 B 要重算,否则阻力线会漂在天上。 [CODE] { price_1 = NormalizeDouble(m_low[bars_ext.Bar_2], digits); price_2 = NormalizeDouble(m_low[bars_ext.Bar_4], digits); _bar1 = bars_ext.Bar_2; _bar2 = bars_ext.Bar_4; } else { price_1 = NormalizeDouble(m_low[bars_ext.Bar_1], digits); price_2 = NormalizeDouble(m_low[bars_ext.Bar_3], digits); _bar1 = bars_ext.Bar_1; _bar2 = bars_ext.Bar_3; } } K=(price_2-price_1)/(_bar2-_bar1); B=price_1-K*_bar1; } for(int i=0;i<Bars_H;i++) { resistanceBuffer[i]=NormalizeDouble(K*i+B,Dig); } Level(false,First_Ext,Bars_Ext,Trade_Symbol,Period_Trade); for(int i=0;i<Bars_H;i++) { supportBuffer[i]=NormalizeDouble(K*i+B,Dig); } [/CODE]

MQL5 / C++
      {
      price_1 = NormalizeDouble(m_low[bars_ext.Bar_2], digits);
      price_2 = NormalizeDouble(m_low[bars_ext.Bar_4], digits);
      _bar1 = bars_ext.Bar_2;
      _bar2 = bars_ext.Bar_4;
      }
      else
      {
      price_1 = NormalizeDouble(m_low[bars_ext.Bar_1], digits);
      price_2 = NormalizeDouble(m_low[bars_ext.Bar_3], digits);
      _bar1 = bars_ext.Bar_1;
      _bar2 = bars_ext.Bar_3;
      }
   }
   K=(price_2-price_1)/(_bar2-_bar1);
   B=price_1-K*_bar1;
 }
for(class="type">int i=class="num">0;i<Bars_H;i++)
{
   resistanceBuffer[i]=NormalizeDouble(K*i+B,Dig);
}
Level(false,First_Ext,Bars_Ext,Trade_Symbol,Period_Trade);
for(class="type">int i=class="num">0;i<Bars_H;i++)
{
   supportBuffer[i]=NormalizeDouble(K*i+B,Dig);
}

◍ 从支撑阻力线的夹角读趋势变速

指标在新极值柱线出现后会重算支撑与阻力数组,级别自动重绘,这是动态区间的正常表现。 真正可挖的信号在夹角:若把某条支撑或阻力线与时间轴的夹角算出来并记住,等下一次同线重画后比对新夹角,就能判断这段趋势是在加速还是减速,原理前文已铺垫。 实操上,打开 MT5 把附带的指标文件拖进图表,观察极值刷新后线斜率的变化,比肉眼估倾斜度更稳。外汇与贵金属波动受杠杆放大,夹角转平往往意味着原方向动能衰减,但仅为概率倾向,需结合仓位控制。

「把线当成策略的原料而非终点」

手工画这些回归线并不麻烦,因为不用给每个品种和周期单独配指标参数;但把它嵌进 EA 才是正路——指标吐出的是两条线的数据数组,你拿到后第一件事是算倾角与方向,再去看两线围出的形状。 这类形状能直接映射信号强弱:通道内高抛低吸,或等价格破支撑阻力再跟。外汇和贵金属杠杆高,破线也可能是假突破,信号强度只是概率倾向,不是下单指令。 s_rind.mq5 那个 34.78 KB 的源文件就是现成底料,MT5 里加载后把数组接出来,先跑 EURUSD 的 H1 看线形反应,再决定要不要往自动交易系统里塞。

常见问题

取两根柱线的索引和对应价格作为两点,用(价格2-价格1)/(索引2-索引1)算斜率,再代入点斜式写出直线方程即可。
夹角变大通常说明价格脱离原区间的速度加快,趋势变速倾向增强;夹角收窄则可能是盘整或减速。
小布可以在对应品种页直接生成支撑阻力线并监控夹角变化,突破或变速时推送提醒,你只需看结论。
线只是价格行为的投影,用作触发条件或过滤信号比单纯等触碰更稳,能减少假突破带来的来回止损。
柱线索引提供横轴坐标,配合该柱收盘价或高低价就能定位点,没有索引就无法把价格锚定到确定时间位置。