液态图表·进阶篇
📘

液态图表·进阶篇

第 2/3 篇

「把液态图表写进独立窗口指标」

要在 MT5 里把「液态图表」跑起来,核心是写一个新指标,在副图窗口渲染,而不是覆盖主图。它支持三种位移模式:静态位移(SS)、动态开盘位移(DSO)、动态收盘位移(DSC),并且不靠参数对话框,直接用图表上的按钮切换模式和位移值。 输入参数里,Depth 决定副图展示多少根柱线,默认 100;BaseTF 是基准周期,默认 M1。inp_LC_mode 和 inp_LC_shift 只是初始值,运行时被 LC_mode 和 LC_shift 变量覆盖——按钮改的就是后者,这样不用重开参数面板。 RefreshBuffers() 是刷新缓存的发动机,OnCalculate 和 OnChartEvent 都会调它。函数先按模式给 shift 赋值:SS 模式直接取 LC_shift,DSO 给 -1,DSC 给 -2,再丢给 GetRatesLC() 算真实位移。算完把返回值写回 LC_shift 并调 refr_keys() 重绘按钮。 SS 模式下位移为 0 时,副图就是原始图表;把位移拉到 28,原本软弱的「轨道」会变成一根明显的「锤头」形态,这种结构在价格行为里倾向暗示做多机会,但外汇和贵金属波动剧烈,高杠杆下仅是概率信号,不是入场保证。 DSO 模式里新形成的柱线永远贴在最右;DSC 模式则保证柱线在基准周期时间间隔内即将收盘。三种模式切换逻辑和按钮绘制无关本文主题,但你要验证效果,直接挂 liquid_chart.mq5 即可。

MQL5 / C++
<span class="keyword">input</span> <span class="macro">ENUM_TIMEFRAMES</span>&nbsp;&nbsp; BaseTF=<span class="macro">PERIOD_M1</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// LC Base Period</span>
<span class="keyword">input</span> <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Depth=<span class="number">class="num">100</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// Depth, bars</span>
<span class="keyword">input</span> ENUM_LC_MODE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inp_LC_mode=LC_MODE_SS; <span class="comment">class=class="str">"cmt">// LC mode</span>
<span class="keyword">input</span> <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inp_LC_shift=<span class="number">class="num">0</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// LC shift</span>
<span class="keyword">enum</span> ENUM_LC_MODE
&nbsp;&nbsp;{<span class="comment">class=class="str">"cmt">//plotting mode</span>
&nbsp;&nbsp; LC_MODE_SS=<span class="number">class="num">0</span>,&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// <b>S</b>tatic <b>S</b>hift</span>
&nbsp;&nbsp; LC_MODE_DSO=<span class="number">class="num">1</span>, <span class="comment">class=class="str">"cmt">// <b>D</b>ynamic <b>S</b>hift, just <b>O</b>pen</span>
&nbsp;&nbsp; LC_MODE_DSC=<span class="number">class="num">2</span>&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// <b>D</b>ynamic <b>S</b>hift, expected <b>C</b>lose</span>
&nbsp;&nbsp;};
<span class="keyword">class="type">bool</span> RefreshBuffers(<span class="keyword">class="type">int</span> total,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> &amp;buff1[],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> &amp;buff2[],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> &amp;buff3[],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> &amp;buff4[],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> &amp;col_buffer[])
&nbsp;&nbsp;{
&nbsp;&nbsp; <span class="predefines">class="type">MqlRates</span> rates[];
&nbsp;&nbsp; <span class="functions">ArrayResize</span>(rates,Depth);
<span class="comment">class=class="str">"cmt">//---</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span> copied=<span class="number">class="num">0</span>;
&nbsp;&nbsp; <span class="keyword">class="type">int</span> shift=<span class="number">class="num">0</span>;
&nbsp;&nbsp; <span class="keyword">if</span>(LC_mode==LC_MODE_SS)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shift = LC_shift;<span class="comment"> class=class="str">"cmt">//class="kw">static shift</span>
&nbsp;&nbsp; <span class="keyword">else</span> <span class="keyword">if</span>(LC_mode==LC_MODE_DSO)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shift = -<span class="number">class="num">1</span>;       <span class="comment">class=class="str">"cmt">//calculate shift(beginning of the bar formation)</span>
&nbsp;&nbsp; <span class="keyword">else</span> <span class="keyword">if</span>(LC_mode==LC_MODE_DSC)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shift = -<span class="number">class="num">2</span>;<span class="comment">       class=class="str">"cmt">//calculate shift(end of the bar formation)</span>
&nbsp;&nbsp; <span class="keyword">else</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span>(<span class="macro">false</span>);
<span class="comment">class=class="str">"cmt">//---</span>
&nbsp;&nbsp; copied=GetRatesLC(<span class="number">class="num">0</span>,Depth,rates,BaseTF,shift);
<span class="comment">class=class="str">"cmt">//---</span>
&nbsp;&nbsp; <span class="keyword">if</span>(copied&lt;=<span class="number">class="num">0</span>)
&nbsp;&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">Print</span>(<span class="class="type">class="kw">string">"No data"</span>);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">class="kw">return</span>(<span class="macro">false</span>);
&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp; LC_shift = shift;
&nbsp;&nbsp; refr_keys();
<span class="comment">class=class="str">"cmt">//--- initialize buffers with empty values</span>
&nbsp;&nbsp; <span class="functions">ArrayInitialize</span>(buff1,<span class="number">class="num">0.0</span>);
&nbsp;&nbsp; <span class="functions">ArrayInitialize</span>(buff2,<span class="number">class="num">0.0</span>);
&nbsp;&nbsp; <span class="functions">ArrayInitialize</span>(buff3,<span class="number">class="num">0.0</span>);
&nbsp;&nbsp; <span class="functions">ArrayInitialize</span>(buff4,<span class="number">class="num">0.0</span>);
<span class="comment">class=class="str">"cmt">//---</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span> buffer_index=total-copied;
&nbsp;&nbsp; <span class="keyword">for</span>(<span class="keyword">class="type">int</span> i=<span class="number">class="num">0</span>;i&lt;copied;i++)
&nbsp;&nbsp;&nbsp;&nbsp; {

◍ 把K线四价灌进缓冲区并标阴阳

这段逻辑跑在自定义指标的 OnCalculate 里,逐根把当前柱的 open/high/low/close 写进四个独立缓冲区,方便后续在副图叠加或做形态判断。 rates[i].open<=rates[i].close 时给 col_buffer 打 1,代表阳线或十字;否则打 0 代表阴线。注意这里把开盘等于收盘也归为多头色,和 MT5 内置蜡烛图的 doji 着色习惯一致。 buffer_index++ 在循环尾推进,保证每根 K 对应唯一槽位;函数最终 return(true) 告知终端计算成功。外汇与贵金属波动大,这种着色仅反映已发生结构,不预示后续方向。

MQL5 / C++
   buff1[buffer_index]=rates[i].open;
   buff2[buffer_index]=rates[i].high;
   buff3[buffer_index]=rates[i].low;
   buff4[buffer_index]=rates[i].close;
      class=class="str">"cmt">//---
    if(rates[i].open<=rates[i].close)
       col_buffer[buffer_index]=class="num">1;class=class="str">"cmt">//bullish or doji
    else
       col_buffer[buffer_index]=class="num">0;class=class="str">"cmt">//bearish
   class=class="str">"cmt">//
      buffer_index++;
   }
class=class="str">"cmt">//
   class="kw">return(true);
   }

把均线EA和夹针EA改成可位移版本

以 MT5 自带的 Moving Average 例程(Experts\Examples\Moving Average)为基底,我们改出两个 EA:一个按均线交叉,一个按“夹针柱线”形态。两者都挂上 liquidchart.mqh,目的只有一个——在开启 LC_on 后,用 GetRatesLC() 替换标准 CopyRates(),从而把静态移位改成动态移位,方便后面比两种策略的优化差异。外汇和贵金属杠杆高,回测结论只代表历史概率,实盘可能明显偏离。 均线版新增了 LC_on、LC_shift、BaseTF 三个输入。LC_on 设为 true 且 LC_shift=0 时,结果应当和 LC_on=false 完全一致,这可以用来验证 GetRatesLC() 没接错。原版依赖指标句柄,改写后得手工算均价值,于是加了 CopyMABuffer():它返回 ma[] 里所需元素数,出错返回 0。 原版用即时报价成交量控开盘,我们没那数据,改成 newbar() 比前一根开盘时间。CheckForOpen() 和 CheckForClose() 里都调 newbar(),完整代码在 moving_average_lc.mq5。 夹针柱线(匹诺曹)由三根 K 线组成:中间 r[1] 是长影“鼻子”,两侧 r[0]、r[2] 是“眼睛”,极值不能越过中间影线。下行反转要求 r[0] 阳、r[2] 阴,A=r[0]最高、C=r[2]最高、B=r[1]最高,且 A 和 C 的最大值不超过 B;r[1] 实体不超过 inp 点数,影线不小于 inp 点数,影线/实体比不小于 inp 比值。形态在 r[3] 开盘时判定。 检测函数对历史数组要求至少 4 根:上夹针返回 1,下夹针返回 -1,无形态返回 0。策略极简——下夹针做空、上夹针做多,不带指标确认以保持实验纯粹。但严格参数下夹针极少出现,只靠反向夹针平仓容易踏空或扛亏,所以加了 inp_tp_pp、inp_sl_pp 止盈止损,设 0 就不挂。完整代码见 pinbar_lc.mq5,开 MT5 把这两个文件丢进 Experts 就能跑。

MQL5 / C++
input class="type">class="kw">double MaximumRisk   = class="num">0.1;  class=class="str">"cmt">// Maximum Risk in percentage
input class="type">class="kw">double DecreaseFactor = class="num">3;    class=class="str">"cmt">// Decrease factor
input class="type">int    MovingPeriod   = class="num">12;   class=class="str">"cmt">// Moving Average period
input class="type">int    MovingShift    = class="num">6;    class=class="str">"cmt">// Moving Average shift
input ENUM_TIMEFRAMES  BaseTF=PERIOD_M1;   class=class="str">"cmt">// LC Base Period
input class="type">bool             LC_on = true;       class=class="str">"cmt">// LC mode ON
input class="type">int              LC_shift = class="num">0;       class=class="str">"cmt">// LC shift
   class="type">int copied;
   if(LC_on==true)
     {
       class="type">int shift = LC_shift;
       copied=GetRatesLC(class="num">0,class="num">2,rt,BaseTF,shift);
     }
   else
       copied = CopyRates(_Symbol,_Period,class="num">0,class="num">2,rt);
   if(copied!=class="num">2)
     {
       Print("CopyRates of ",_Symbol," failed, no history");
       class="kw">return;
     }
class="type">int CopyMABuffer(class="type">int len,class="type">class="kw">double &ma[])
  {
   if(len<=class="num">0)
      class="kw">return(class="num">0);
   class="type">MqlRates rates[];
   class="type">int l=len-class="num">1+MovingPeriod;
   class="type">int copied;
   if(LC_on==true)
     {
       class="type">int shift = LC_shift;
       ArrayResize(rates,l);
       copied=GetRatesLC(MovingShift,l,rates,BaseTF,shift);
     }
   else
       copied=CopyRates(_Symbol,_Period,MovingShift,l,rates);
class=class="str">"cmt">//
   if(copied<l)
      class="kw">return(class="num">0);
class=class="str">"cmt">//

「上插针形态判定与K线遍历的裸逻辑」

这段逻辑把均线计算和 pin bar 识别拆成了两块独立函数,先说均线部分:外层循环跑 len 根 K 线,内层按 MovingPeriod 窗口累加 close 价,LC_on 开关决定是从头部还是尾部取序列,最终 ma[i] 存的是窗口均值。 newbar() 用静态变量 t_prev 卡住时间轴,只有出现新柱才放行后续判断,避免同根 K 线内重复触发——外汇和贵金属这种高波动品种,重复信号会直接放大滑点风险。 IsPinbar() 要求数组至少 4 根:索引 1 作为候选针杆,条件 r[0].open<r[0].close 且 r[2].open>r[2].close,且 r[1].high 必须高于两侧高点,这是典型上插针的「眼睛」结构。 针杆实体用 oc=MathAbs(open-close)/_Point 换算成点数,若超过 inp_pb_max_OC 直接弃;影线 shdw 低于 inp_pb_min_shdw 也弃;两者比例 shdw/oc 小于 inp_pb_min_ratio 同样不认。调这三个输入参数,就能在 MT5 里收紧或放宽形态过滤。

MQL5 / C++
for(class="type">int i=class="num">0;i<len;i++)
  {
    class="type">class="kw">double sum=class="num">0;
    for(class="type">int j=class="num">0;j<MovingPeriod;j++)
      {
        if(LC_on==true)
          sum+=rates[j+i].close;
        else
          sum+=rates[copied-class="num">1-j-i].close;
      }
    ma[i]=sum/MovingPeriod;
  }
  class="kw">return(len);
}
  if(rt[class="num">1].tick_volume>class="num">1)
    class="kw">return;
class="type">bool newbar(class="type">class="kw">datetime t)
  {
    class="kw">static class="type">class="kw">datetime t_prev=class="num">0;
    if(t!=t_prev)
      {
        t_prev=t;
        class="kw">return(true);
      }
    class="kw">return(false);
  }
  if(newbar(rt[class="num">1].time)==false)
    class="kw">return;
  if(r[class="num">0].open<r[class="num">0].close && r[class="num">2].open>r[class="num">2].close && r[class="num">1].high>MathMax(r[class="num">0].high,r[class="num">2].high))
    {
class=class="str">"cmt">//--- eyes of the upper pin bar
      class="type">class="kw">double oc=MathAbs(r[class="num">1].open-r[class="num">1].close)/_Point;
      if(oc>inp_pb_max_OC)
        class="kw">return(class="num">0);
      class="type">class="kw">double shdw=(r[class="num">1].high-MathMax(r[class="num">1].open,r[class="num">1].close))/_Point;
      if(shdw<inp_pb_min_shdw)
        class="kw">return(class="num">0);
      if(oc!=class="num">0)
        {
          if((shdw/oc)<inp_pb_min_ratio)
            class="kw">return(class="num">0);
        }
      class="kw">return(class="num">1);
    }
class="type">int IsPinbar(class="type">MqlRates &r[])
  {
class=class="str">"cmt">//--- there must be class="num">4 values in the r[] array
    if(ArraySize(r)<class="num">4)
      class="kw">return(class="num">0);
    if(r[class="num">0].open<r[class="num">0].close && r[class="num">2].open>r[class="num">2].close && r[class="num">1].high>MathMax(r[class="num">0].high,r[class="num">2].high))
      {class=class="str">"cmt">//--- eyes of the upper pin bar
        class="type">class="kw">double oc=MathAbs(r[class="num">1].open-r[class="num">1].close)/_Point;
        if(oc>inp_pb_max_OC)
          class="kw">return(class="num">0);
        class="type">class="kw">double shdw=(r[class="num">1].high-MathMax(r[class="num">1].open,r[class="num">1].close))/_Point;
        if(shdw<inp_pb_min_shdw)
          class="kw">return(class="num">0);
        if(oc!=class="num">0)
          {

◍ 下插针的判定与信号触发逻辑

上一段处理了上 pin bar 的返回 1,这里接着看下插针分支:当最新 K 线为阴线、倒数第三根 K 线为阳线、且中间那根 K 线的最低价低于左右两根的最低价时,才进入下插针判定。 代码先算中间 K 线的实体点数 oc,若 oc 超过 inp_pb_max_OC(默认 20 点)直接淘汰;再算下方影线 shdw = 实体下沿到最低价的点数,若小于 inp_pb_min_shdw(默认 40 点)也淘汰。 若实体不为 0,还要求 shdw/oc 不小于 inp_pb_min_ratio(默认 2.0),否则返回 0。全部通过则返回 -1,代表下插针成立,对应做多倾向。 外部输入参数写死为:inp_pb_min_shdw=40、inp_pb_max_OC=20、inp_pb_min_ratio=2.0,三者共同框定针杆比例。实盘里把 40 调到 25,可能更容易抓到小周期黄金的刺透形态,但假信号概率会上升。 历史抓取用 CopyRates 取 4 根 K 线,若 copied!=4 就打印失败并返回;只有 newbar 为真才跑 IsPinbar。pb==1 给卖信号,pb==-1 给买信号,已有同向持仓时 signal 置 true。外汇与贵金属波动剧烈,pin bar 仅作概率参考,开 MT5 调参验证前先想清点差与滑点。

MQL5 / C++
   else if(r[class="num">0].open>r[class="num">0].close && r[class="num">2].open<r[class="num">2].close && r[class="num">1].low<MathMin(r[class="num">0].low,r[class="num">2].low))
   {
class=class="str">"cmt">//--- eyes of the lower pin bar
      class="type">class="kw">double oc=MathAbs(r[class="num">1].open-r[class="num">1].close)/_Point;
      if(oc>inp_pb_max_OC)
         class="kw">return(class="num">0);
      class="type">class="kw">double shdw=(MathMin(r[class="num">1].open,r[class="num">1].close)-r[class="num">1].low)/_Point;
      if(shdw<inp_pb_min_shdw)
         class="kw">return(class="num">0);
      if(oc!=class="num">0)
         {
          if((shdw/oc)<inp_pb_min_ratio)
            class="kw">return(class="num">0);
         }
      class="kw">return(-class="num">1);
   }
   class="kw">return(class="num">0);
}
input class="type">uint   inp_pb_min_shdw     = class="num">40;     class=class="str">"cmt">// Pin bar min shadow, point
input class="type">uint   inp_pb_max_OC       = class="num">20;     class=class="str">"cmt">// Pin bar max OC, point
input class="type">class="kw">double inp_pb_min_ratio    = class="num">2.0;   class=class="str">"cmt">// Pin bar shadow to OC min ratio
   class="type">int copied;
   if(LC_on==true)
   {
      class="type">int shift = LC_shift;
      copied=GetRatesLC(class="num">0,class="num">4,rt,BaseTF,shift);
   }
   else
      copied = CopyRates(_Symbol,_Period,class="num">0,class="num">4,rt);
   if(copied!=class="num">4)
      {
         Print("CopyRates of ",_Symbol," failed, no history");
         class="kw">return;
      }
   if(newbar(rt[class="num">3].time)==false)
      class="kw">return;
   class="type">int pb=IsPinbar(rt);
   if(pb==class="num">1)       class=class="str">"cmt">// upper pin bar
      signal=ORDER_TYPE_SELL; class=class="str">"cmt">// sell conditions
   else if(pb==-class="num">1) class=class="str">"cmt">// lower pin bar
      signal=ORDER_TYPE_BUY;  class=class="str">"cmt">// buy conditions
   if(type==(class="type">long)POSITION_TYPE_BUY && pb==class="num">1)
      signal=true;
   if(type==(class="type">long)POSITION_TYPE_SELL && pb==-class="num">1)
      signal=true;
   class="type">class="kw">double sl=class="num">0,tp=class="num">0,p=class="num">0;
   class="type">class="kw">double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);

挂单价格与止损止盈的双向换算

这段逻辑解决了一个实操痛点:信号方向不同,开仓价、止损价、止盈价的基准和加减方向完全反过来。做空时以 bid 为基准,止损放在 ask 上方、止盈在 ask 下方;做多则反过来用 ask 基准、止损在 bid 下方、止盈在 bid 上方。 代码里 inp_sl_pp 和 inp_tp_pp 是以点数(_Point)为单位的偏移量,经 NormalizeDouble 按品种精度 _Digits 规整后才写入。注意原文做空分支的止盈用了 inp_sl_pp 而非 inp_tp_pp,这大概率是笔误,实盘复制时建议改成对应变量,否则空单止损止盈会对称重叠。 外汇与贵金属杠杆高,点值跳空可能让 sl/tp 失效,上述换算只保证报价逻辑自洽,不预示任何胜率。开 MT5 把这段塞进 EA 的 OrderSend 前处理块,改完变量名跑一次回测就能看出差异。

MQL5 / C++
  class="type">class="kw">double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
  if(signal==ORDER_TYPE_SELL)
  {
    p=bid;
    if(inp_sl_pp!=class="num">0)
      sl=NormalizeDouble(ask+inp_sl_pp*_Point,_Digits);
    if(inp_tp_pp!=class="num">0)
      tp=NormalizeDouble(ask-inp_sl_pp*_Point,_Digits);
  } else {
    p=ask;
    if(inp_sl_pp!=class="num">0)
      sl=NormalizeDouble(bid-inp_sl_pp*_Point,_Digits);
    if(inp_tp_pp!=class="num">0)
      tp=NormalizeDouble(bid+inp_sl_pp*_Point,_Digits);
  }
  CTrade trade;
  trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),p,sl,tp);

常见问题

新建指标时把绘图放到独立窗口,用自定义缓冲区接收K线四价数据,再按液态渲染逻辑绘制,避免污染主图价格坐标。
比较每根K线的开盘价与收盘价,收盘价高标阳、低标阴,把对应颜色和数值写入独立颜色缓冲区即可。
小布可读取你的指标代码与历史K线,自动跑形态遍历并标出上插针、下插针信号,省去手动逐根核对。
遍历每根K线,比较实体与上下影线长度,当上影线大于实体N倍且下影线极短即判上插针,参数N按品种波动率调。
以入场价为基准,用点数差分别加减得到挂单价与止损止盈价,注意贵金属和外汇点值不同,换算时统一用报价精度。