利用迪纳波利 (DiNapoli) 等级进行交易·进阶篇
📐

利用迪纳波利 (DiNapoli) 等级进行交易·进阶篇

(2/3)·从手绘 38.2% 与 61.8% 到自动识别 COP/OP/XOP,进阶篇只讲落地实现

进阶 第 2/3 篇

不少交易者把迪纳波利等级画在图上就等信号,却忽略了趋势切换时 61.8% 常不到场,而人工连续盯盘极易漏掉二次调整的入场窗口。把这套依赖 MA 与随机振荡指标确认的逻辑交给程序,才谈得上稳定执行。

双指标缓冲复制与信号初判

在 EA 初始化后取数阶段,随机振荡器与双色均线的缓冲区必须用 CopyBuffer 各拉 3 根柱。代码里主线 handle 取缓冲 0、信号线取缓冲 1,均从 0 号位开始复制长度 3;若返回值不等于 3,说明复制失败,直接用 Alert 把实际出错长度打出来,避免静默跑假信号。 随机振荡器的判定只看倒数第二根(索引 1):当主线与信号线都高于 stochastic_up_level 时,answer 置 2,代表价格超买、后续回落概率倾向上升;两者都低于 stochastic_down_level 时 answer 置 1,代表超卖、反弹概率倾向上升。这个 1/2 编码就是后面多指标投票的输入。 均线部分另写了一个 MA() 函数,入参带引用型的 answer、两条线变量及 ask/bid。内部同样复制 3 根,把 ma_blue[2] 与 ma_red[2] 赋给外部变量;若蓝线在 2 号位高于红线,即视为趋势向上的初步条件。外汇与贵金属杠杆高,这类交叉仅作概率参考,实盘前请在 MT5 策略测试器用历史数据验证复制逻辑与警报触发。

MQL5 / C++
class="type">int line_main=CopyBuffer(stochastic_handle,class="num">0,class="num">0,class="num">3,stochastic_line_main);
class="type">int line_signal=CopyBuffer(stochastic_handle,class="num">1,class="num">0,class="num">3,stochastic_line_signal);
if(line_main!=class="num">3 || line_signal!=class="num">3)
   {Alert("复制 iStochastic: 主线出错=",line_main,", 信号线=",line_signal);}    class=class="str">"cmt">// 检查复制随机振荡器数据
if(stochastic_line_main[class="num">1]>stochastic_up_level && stochastic_line_signal[class="num">1]>stochastic_up_level)
   {answer=class="num">2;}                                                                           class=class="str">"cmt">// 卖出有益
if(stochastic_line_main[class="num">1]<stochastic_down_level && stochastic_line_signal[class="num">1]<stochastic_down_level)
   {answer=class="num">1;}                                                                           class=class="str">"cmt">// 买入有益
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 从指标 MA 中获得信号                                                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void MA(class="type">char &answer,                                                                     class=class="str">"cmt">// class="num">0 - 无信号; class="num">1 - 信号向上; class="num">2 - 信号向下
        class="type">class="kw">double &line_blue,
        class="type">class="kw">double &line_red,
        class="type">class="kw">double ask,
        class="type">class="kw">double bid)
  {
   answer=class="num">0;                                                                              class=class="str">"cmt">// 应答
   class="type">class="kw">double ma_red[class="num">3];
   class="type">class="kw">double ma_blue[class="num">3];
   class="type">int red=CopyBuffer(ma_red_handle,class="num">0,class="num">0,class="num">3,ma_red);
   class="type">int blue=CopyBuffer(ma_blue_handle,class="num">0,class="num">0,class="num">3,ma_blue);
   if(red!=class="num">3 || blue!=class="num">3)
      {Alert("复制 iMA 出错: MA 红=",red,", MA 蓝=",blue);}   class=class="str">"cmt">// 检查复制红/蓝两色均线数据
   line_blue=ma_blue[class="num">2];
   line_red=ma_red[class="num">2];
   if(ma_blue[class="num">2]>ma_red[class="num">2])                                                              class=class="str">"cmt">// 假定趋势向上

◍ 用双均线位置判定回滚与趋势延续

在趋势判定里,把蓝线(快均线)和红线(慢均线)在偏移 2 根的位置拿来比对,能直接区分回滚与顺势。当 ma_blue[2] 大于 ma_red[2] 即视为向上趋势,此时若 ask 低于蓝线但高于红线,价格处于回滚位,后续向上移动的概率偏高;反之向下趋势中 bid 高于蓝线且低于红线,则向下延续可能更大。 下面这段逻辑就是上述判定的核心:先判向上趋势分支,再在回滚区给 answer 赋 1;否则进向下趋势分支赋 2。外汇与贵金属波动剧烈,这类判定只作概率参考,实盘须自担高风险。 [CODE] 部分另附分形数据接收函数 Fractals(),用 CopyBuffer 从 iFractals 句柄拉 100 根上下分形到数组,若复制数量不为 100 就弹 Alert 报错;随后从 x=99 往回扫,遇到小于 10000 的有效上分形就初始化 price_high。开 MT5 把 fractals_handle 接好,就能直接验证分形捕获是否漏数据。

MQL5 / C++
   if(ask<ma_blue[class="num">2])                                                        class=class="str">"cmt">// 假定价格处于回滚位置
      if(ask>ma_red[class="num">2])
       {answer=class="num">1;}                                                                     class=class="str">"cmt">// 很快向趋势方向 (向上) 移动成为可能
   if(ma_blue[class="num">2]<ma_red[class="num">2])                                                        class=class="str">"cmt">// 假定趋势向下
      if(bid>ma_blue[class="num">2])                                                            class=class="str">"cmt">// 假定价格处于回滚位置
       if(bid<ma_red[class="num">2])
        {answer=class="num">2;}                                                                   class=class="str">"cmt">// 很快向趋势方向 (向下) 移动成为可能
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 接收来自分形指标的数据                                                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Fractals(class="type">class="kw">double &price_up,
              class="type">class="kw">double &price_down)
  {
   price_up=class="num">0;
   price_down=class="num">0;
   class="type">class="kw">double fractals_up[class="num">100];
   class="type">class="kw">double fractals_down[class="num">100];
   class="type">int up=CopyBuffer(fractals_handle,class="num">0,class="num">0,class="num">100,fractals_up);
   class="type">int down=CopyBuffer(fractals_handle,class="num">1,class="num">0,class="num">100,fractals_down);
   if(up!=class="num">100 || down!=class="num">100)
     {Alert("复制 iFractals 出错: 上分形=",up,", 下分形=",down);} class=class="str">"cmt">// 检查复制上/下分形数据
   class="type">class="kw">double price_high=class="num">0;
   class="type">class="kw">double price_low=class="num">0;
   for(class="type">int x=class="num">99; x>class="num">0; x--)                                                            class=class="str">"cmt">// 顶部分形循环
     {
      if(fractals_up[x]<class="num">10000)                                                        class=class="str">"cmt">// 检查分形可用性
        {
         if(price_high==class="num">0){price_high=fractals_up[x];}                                class=class="str">"cmt">// 初始化检查

「把上下分形夹成可下单区间」

这段逻辑干的事很直接:从最近的顶部分形往下扫,遇到更高的高点就停,否则把 price_high 不断刷新成当前分形值;底部反过来从 99 循环到 1,用 10000 做无效分形过滤,把 price_low 钉在最低的可用底分形上。 扫完分形后立刻取当前品种卖价与买价:price_high 必须同时大于 Ask 和 Bid,且 price_low 同时小于二者,才把这两个边界赋给 price_up / price_down。也就是说,只有市价被夹在上下分形之间,后续开仓函数才拿得到有效参考价。 外汇与贵金属杠杆高、滑点跳空频繁,分形边界只是概率上的结构位,实盘前请在 MT5 用策略测试器跑一遍 EURUSD 的 M15,确认 price_high 在 100 根内非空。

MQL5 / C++
if(price_high>fractals_up[x]){class="kw">break;} class=class="str">"cmt">// 如果分形正在向下停止循环
else{price_high=fractals_up[x];} class=class="str">"cmt">// 如果分形正在向上, 复制
}
}
for(class="type">int x=class="num">99; x>class="num">0; x--) class=class="str">"cmt">// 重复循环检查底部分形
{
 if(fractals_down[x]<class="num">10000) class=class="str">"cmt">// 检查分形可用性
 {
  if(price_low==class="num">0){price_low=fractals_down[x];} class=class="str">"cmt">// 初始化检查
  if(price_low<fractals_down[x]){class="kw">break;} class=class="str">"cmt">// 如果分形正在向上停止循环
  else{price_low=fractals_down[x];} class=class="str">"cmt">// 如果分形正在向下, 复制
 }
}
class="type">class="kw">double price_ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK); class=class="str">"cmt">// 买入价格请求
class="type">class="kw">double price_bid=SymbolInfoDouble(_Symbol,SYMBOL_BID); class=class="str">"cmt">// 卖出价格请求
if(price_high>price_ask && price_high>price_bid) class=class="str">"cmt">// 检查竞卖/竞卖价是否在上/下分形之间
 if(price_low<price_ask && price_low<price_bid)
  {
   price_up=price_high; class=class="str">"cmt">// 分派应答值
   price_down=price_low;
  }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 计算开仓价格                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Price_for_order(class="type">class="kw">double high_price,
                     class="type">class="kw">double low_price,

用区间百分比算挂单与止损的边界

这段函数把一根 K 线的高低差当作基准尺度,再按百分比切出进场区、止盈和止损的距离。percent_min_enter、percent_max_enter、percent_for_tp、percent_for_sl 这几个外部参数直接决定仓位在空间里的位置,调 1 个数字,挂单带就整体偏移。 先看尺度换算:point_price 是高价减低价,四个 point_* 分别乘对应百分比再除以 100,蓝红双线绝对值差的一半作为均线缓冲带 point_ma_line。所有结果都过 NormalizeDouble 对齐 _Digits,避免 XAUUSD 的 0.01 精度或 EURUSD 的 0.00001 精度下出现报价拒绝。 向上趋势里,进场下限从 high_price 往下扣 point_enter_min;若算出来比红线上移半个缓冲带还高,就压到缓冲带边界,防止挂单悬在均线上方太远。进场上限同理,若比下限还高则直接落到红线。止盈设在进场下限加 point_tp,止损设在最高价减 point_sl。 向下时镜像处理:进场下限从 low_price 往上加,若低于红线下移缓冲带则抬到边界;止盈朝下减 point_tp,止损在最低价加 point_sl。外汇和贵金属杠杆高,这类按区间百分比自动铺单的逻辑在震荡段可能频繁触发,实盘前务必在 MT5 策略测试器用历史数据验证参数敏感性。

MQL5 / C++
class="type">class="kw">double &p_enter_min,
class="type">class="kw">double &p_enter_max,
class="type">class="kw">double &p_tp,
class="type">class="kw">double &p_sl,
class="type">char trend,                   class=class="str">"cmt">// class="num">1 - 向上; class="num">2 - 向下
class="type">class="kw">double blue_line,
class="type">class="kw">double red_line
  )
{
 class="type">class="kw">double point_price=(high_price-low_price);
 class="type">class="kw">double point_enter_min=point_price*percent_min_enter/class="num">100;
 class="type">class="kw">double point_enter_max=point_price*percent_max_enter/class="num">100;
 class="type">class="kw">double point_tp=point_price*percent_for_tp/class="num">100;
 class="type">class="kw">double point_sl=point_price*percent_for_sl/class="num">100;
 class="type">class="kw">double point_ma_line=MathAbs(blue_line-red_line)/class="num">2;
 point_enter_min=NormalizeDouble(point_enter_min,_Digits);
 point_enter_max=NormalizeDouble(point_enter_max,_Digits);
 point_ma_line=NormalizeDouble(point_ma_line,_Digits);
 point_tp=NormalizeDouble(point_tp,_Digits);
 point_sl=NormalizeDouble(point_sl,_Digits);
 if(trend==class="num">1)                                          class=class="str">"cmt">// 向上
   {
   p_enter_min=high_price-point_enter_min;
   class="type">class="kw">double p_ma_min=red_line+point_ma_line;
   if(p_enter_min>p_ma_min)
     {p_enter_min=p_ma_min;}
   p_enter_max=high_price-point_enter_max;
   if(p_enter_max>p_enter_min)
     {p_enter_max=red_line;}
   p_tp=p_enter_min+point_tp;
   p_sl=high_price-point_sl;
   }
 if(trend==class="num">2)                                          class=class="str">"cmt">// 向下
   {
   p_enter_min=low_price+point_enter_min;
   class="type">class="kw">double p_ma_min=red_line-point_ma_line;
   if(p_enter_min<p_ma_min)
     {p_enter_min=p_ma_min;}
   p_enter_max=low_price+point_enter_max;
   if(p_enter_max<p_enter_min)
     {p_enter_max=red_line;}
   p_tp=p_enter_min-point_tp;
   p_sl=low_price+point_sl;
   }
}

◍ 把止损推到保本位的触发逻辑

上面这段函数接收 bid、point、profit、stochastic 四个参数,核心是在 OnTick 里根据持仓方向与实时报价把止损移动到保本位附近。买入单若 sl 低于开仓价且 bid 已越过 price+sl_point,就把止损抬到 price+profit*_Point;卖出单对称处理,sl 高于价时且 ask 跌破 price-sl_point 则下移到 price-profit*_Point。 sl_point 直接用 point*_Point 换算成绝对价格,profit 参数同理。tp_point 取的是 MathAbs(tp-price)/2,即当前止盈距离的一半,这部分在片段里只算了没直接用,实盘可以接去分批平仓。 stochastic 标志位负责反手预警:买入仓收到 stochastic==2(倾向下行)会立即市价平仓;卖出仓收到 stochastic==1(倾向上行)同样清仓。外汇与贵金属波动大,这种硬平仓可能吃滑点,上 MT5 用策略测试器跑 EURUSD 15M 看成交偏差最直观。 下面 OnTick 里留了 price_high、price_low、price_enter_min、price_enter_max 四个双精度变量初始化为 0,显然是给分形高低点和入场区间备的,接下去你把分形识别填进这几个变量就能串起整套信号。

MQL5 / C++
class="type">class="kw">double bid,
class="type">int point,
class="type">int profit,
class="type">char stochastic)
  {
  class="type">class="kw">double price=trade.RequestPrice();
  class="type">class="kw">double tp=trade.RequestTP();
  class="type">class="kw">double sl=trade.RequestSL();
  class="type">class="kw">double sl_point=point*_Point;
  class="type">class="kw">double sl_profit=profit*_Point;
  class="type">class="kw">double tp_point=(MathAbs(tp-price))/class="num">2;
  if(trade.RequestType()==ORDER_TYPE_BUY)              class=class="str">"cmt">// 买入订单
     {
      if(sl<price && bid>(price+sl_point))
        {
         sl_profit=sl_profit+price;
         trade.PositionModify(_Symbol,sl_profit,tp);
        }
      if(stochastic==class="num">2)                                class=class="str">"cmt">// 预计下行
        {
         trade.PositionClose(_Symbol,order_deviation);
        }
     }
  if(trade.RequestType()==ORDER_TYPE_SELL)             class=class="str">"cmt">// 卖出订单
     {
      if(sl>price && ask<(price-sl_point))
        {
         sl_profit=sl_profit-price;
         trade.PositionModify(_Symbol,sl_profit,tp);
        }
      if(stochastic==class="num">1)                                class=class="str">"cmt">// 预计上行
        {
         trade.PositionClose(_Symbol,order_deviation);
        }
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 智能系统分笔报价函数                                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//---
   class="type">class="kw">double price_high=class="num">0;                                                       class=class="str">"cmt">// 分形计算的最高价格
   class="type">class="kw">double price_low=class="num">0;                                                        class=class="str">"cmt">// 分形计算的最低价格
   class="type">class="kw">double price_enter_min=class="num">0;                                                  class=class="str">"cmt">// 最小入场价格
   class="type">class="kw">double price_enter_max=class="num">0;                                                  class=class="str">"cmt">// 最大入场价格
让小布替你跑这套
这些诊断与小布盯盘的 AIGC 已内置,打开对应品种页即可看到迪纳波利等级与 COP 标记的自动叠加,你只管判断趋势是否有效。

常见问题

COP 为 61.8%,OP 为 100%,XOP 为 161.8%,均以趋势长度百分比度量,常用于分批止盈。
灌木丛在首次调整即入场且偏激进,扫雷 A 等第二次调整才开仓,两者止损放置逻辑也不同。
可以,小布在对应品种页自动绘制回撤与扩展线并标注 COP/OP/XOP,省去手动拉菲波纳奇工具的麻烦。
等级常被频繁趋势变化击穿或不触发,叠加 MA 与随机指标可过滤假突破,提高入场确认质量。
难点在多因素联合判断与长时间空仓等待的订单管理,人工监控艰巨,机器执行更有优势。