小型趋势指标、中型趋势指标和主要趋势指标(基础篇)
📘

小型趋势指标、中型趋势指标和主要趋势指标(基础篇)

第 1/3 篇

「三类趋势指标该怎么分清楚」

在 MT5 里看趋势,先得把周期层级掰开:小型趋势指标盯的是分钟级到小时级的毛刺运动,中型趋势指标通常对应日线附近的波段,主要趋势指标则落在周线及以上,用来定大方向。三层混在一起看,才不容易把噪音当信号。 实操上,很多自带指标(比如不同周期的均线或 MACD)都能分别套到这三个层级。外汇和贵金属杠杆高、跳空频繁,小周期指标容易假突破,大周期指标滞后明显,三层对照能压一压误判概率。 一个可验证的现象:同一品种在 H1 上金叉、在 W1 上却还是死叉,这种背离在 2014 年之后主流货币对里每周都能撞上几次,开 MT5 调出双周期叠加就能自己数。

◍ 甘氏三要素为何常被单拆使用

James Hyerczyk 在《形态-价格-时间:甘氏理论在交易系统里的运用》序言里点出一个实盘通病:交易者做分析时太爱只盯形态、价格或时间中的一项,而不是三者并行。他统计自己的期货经验发现,最常见的系统错误是围绕“进场看时间/出场看价格”或反过来“进场看价格/出场看时间”来搭建,用形态的人则常以较差价位或较差时机进出。 这类偏科直接导致信号质量下降。Hyerczyk 的结论是,形态、价格、时间三者组合才是市场生存的必要条件,他的书也是在这个前提下落笔的。 你可以不认同这个前提,但值得在 MT5 里亲自验证:把纯形态EA、纯均线(价格)EA、纯时间周期突破EA 分别跑同一品种,对比权益曲线离散度。本文后续会基于书中理念,聊怎么用指标和 EA 做自动化分析,建议先翻完该书第一部分“模型”再动手,否则参数含义容易看偏。

从相邻K线关系里抠出小型趋势线段

小型趋势不靠指标参数去拟合,只盯相邻两根 K 线的高低价关系。向上走势要求后一根最高价 > 前一根最高价,且后一根最低价 > 前一根最低价,这时把两根最高价连起来就是一段上升线段;向下则反过来,后一根最低价和最高价都分别小于前一根,连最低价得下降线段。 内侧柱和外侧柱会打断这种简单连接:若后一根最低价高于前一根最低价、同时最高价低于前一根最高价,就是内侧柱,不参与图形构建;若后一根最高价和最低价同时突破前一根的上下沿,就是外侧柱,按它本身方向接上对应区段。 方向切换点就是小型顶底。图 1 里左侧红标是小型底、右侧绿标是小型顶。若向上转向下却没跌破前一个底,只是纠正移动,方向未必真反转——下行同理。价格在顶底之间来回即摆动,可能夹杂纠正移动。 这套画线和常见峰谷指标形态接近,但区别在于它不在其他柱收盘后重绘,也没有外部可调参数去影响趋势线构造,等于把规则锁死在价格本身。外汇与贵金属波动大,纯价格规则也可能在毛刺行情里频繁切换,开 MT5 用历史单品种验证比直接信结论更稳妥。

「画一条小型趋势线:GannMicroTrend 的骨架」

做微型趋势指标,核心是把逐根 K 线的高低点按规则串成线段,并在最近顶/底打上价格标签。它依赖标准库里的 CChartObjectTrend 画趋势线,顶部用左侧价签、底部用右侧价签,全部塞进 CList 方便按时间顺序取最新节点。 外部参数先定边界:MaxBars=1000 意味着默认只扫最近 1000 根柱,设 0 才全量计算;IsSaveTrendParams=true 会把当前趋势和最新顶底写进全局变量,ShowInfo=true 则在图上输出坐标。颜色与线宽也全暴露:UpTrendColor 浅绿、DnTrendColor 浅粉、LineWidth=4,顶底标签宽 StopLossWidth=1。 OnInit 里第一件事是 new 出三个列表指针,校验失败直接报错退出——错误码带 # 方便定位。OnCalculate 看 prev_calculated==0 就清盘重算:删图形对象、清列表,再按 MaxBars 与 rates_total 的关系算 start 起点(柱索引从 0 即最新一根起算)。 画线靠 CreateCut,内部用 GetUniqName 生成唯一名避免重名,成功就设色宽并 CList::Add;顶底则用类似的 CreateUpStopLoss / CreateDnStopLoss。算完用 GetLastNode 捞最新顶底对象填表。外汇与贵金属波动剧烈,这类辅助指标仅描述已发生结构,信号失效概率不低,请先在 MT5 策略测试器跑历史段验证。

MQL5 / C++
class="macro">#include  <TextDisplay.mqh>
input class="type">int     MaxBars = class="num">1000;
input class="type">bool    IsSaveTrendParams = true;
class=class="str">"cmt">//---------------------------------------------------------------------
input class="type">bool    ShowInfo = true;
input class="type">int     UpDownInfoShift = class="num">1;
input class="type">int     LeftRightInfoShift = class="num">1;
input class="type">color   TitlesColor = LightCyan;
input class="type">color   TopFieldsColor = Green;
input class="type">color   LowFieldsColor = Brown;
class=class="str">"cmt">//---------------------------------------------------------------------
input class="type">color   UpTrendColor = LightGreen;
input class="type">color   DnTrendColor = LightPink;
input class="type">int     LineWidth = class="num">4;
class=class="str">"cmt">//---------------------------------------------------------------------
input class="type">color   UpStopLossColor = Green;
input class="type">color   DnStopLossColor = Brown;
input class="type">int     StopLossWidth = class="num">1;
class="macro">#include  <Arrays\List.mqh>
class="macro">#include  <ChartObjects\ChartObjectsLines.mqh>
class="macro">#include  <ChartObjects\ChartObjectsArrows.mqh>
CList*   trend_list_Ptr = NULL;   class=class="str">"cmt">// list of the trend lines
CList*   up_list_Ptr = NULL;      class=class="str">"cmt">// list of the peaks
CList*   dn_list_Ptr = NULL;      class=class="str">"cmt">// list of the bottoms

class="type">int OnInit()
{
  trend_list_Ptr = new CList();
  if(CheckPointer(trend_list_Ptr) != POINTER_DYNAMIC)
  {

◍ 指针校验与初始化的坑

在 MT5 自定义指标里用 CList 管理多组趋势线段,第一步就是动态申请三个链表指针:trend_list_Ptr、up_list_Ptr、dn_list_Ptr。每段 new 出来后必须用 CheckPointer 比对 POINTER_DYNAMIC,否则一旦返回 POINTER_INVALID 或 POINTER_STATIC,后面 Clear()、Add() 都会直接崩。 代码里对三个指针分别做了独立判断,失败时 Print 出对应编号的错误串并返回 -1,这种写法能在日志里精确定位是第几个对象申请失败,比统一报错省不少排查时间。 OnCalculate 首次跑(prev_calculated==0)时会先把三个链表 Clear 一遍,再根据 MaxBars 决定 start 位置:若 MaxBars>0 且 rates_total 超过它,就从 rates_total-MaxBars 根 K 线开始算,否则从头扫。这个截断逻辑直接影响图形绘制的计算量。 CreateCut 函数封装了一段趋势线的绘制:用 GetUniqName 生成不重名对象,new 一个 CChartObjectTrend,Create 时传入起止时间价格,再设颜色和线宽,最后挂进 trend_list_Ptr。若 CheckPointer 不等于 POINTER_INVALID 才往里加,避免空指针入列。外汇与贵金属波动剧烈,这类对象若未释放可能在长时间挂 EA 时累积内存,建议定期清理链表。

MQL5 / C++
  Print("Error of creating the object CList #class="num">1");
  class="kw">return(-class="num">1);
  }
  up_list_Ptr = new CList();
  if(CheckPointer(up_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Error of creating the obkect CList #class="num">2");
    class="kw">return(-class="num">1);
  }
  dn_list_Ptr = new CList();
  if(CheckPointer(dn_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Error of creating the object CList #class="num">3");
    class="kw">return(-class="num">1);
  }
  if(InitGraphObjects() != class="num">0)
  {
    Print("Error of creating the object TableDisplay");
    class="kw">return(-class="num">1);
  }
  class="kw">return(class="num">0);
}
class="type">int index, start = prev_calculated - class="num">1;
if(prev_calculated == class="num">0)
{
  if(CheckPointer(trend_list_Ptr) != POINTER_INVALID)
  {
    trend_list_Ptr.Clear();
  }
  if(CheckPointer(up_list_Ptr) != POINTER_INVALID)
  {
    up_list_Ptr.Clear();
  }
  if(CheckPointer(dn_list_Ptr) != POINTER_INVALID)
  {
    dn_list_Ptr.Clear();
  }
class=class="str">"cmt">//  Determine the bar number of the beginning of calculations:
  if(MaxBars > class="num">0 && rates_total > MaxBars)
  {
    start = rates_total - MaxBars;
  }
  else
  {
    start = class="num">0;
  }
  time_prev = class="num">0;
  trend_prev = class="num">0;
}
    start = rates_total - MaxBars;
class=class="str">"cmt">//---------------------------------------------------------------------
class=class="str">"cmt">//  Drawing of a section
class=class="str">"cmt">//---------------------------------------------------------------------
class="type">void  CreateCut(class="type">class="kw">datetime _dt1, class="type">class="kw">double _prc1, class="type">class="kw">datetime _dt2, class="type">class="kw">double _prc2, class="type">color _clr, class="type">int _wd)
{
  class="type">class="kw">string  name = GetUniqName(prefix + " ");
  CChartObjectTrend*  trend_obj = new CChartObjectTrend();
  if(CheckPointer(trend_obj) != POINTER_INVALID)
  {
    trend_obj.Create(class="num">0, name, class="num">0, _dt1, _prc1, _dt2, _prc2);
    trend_obj.Color(_clr);
    trend_obj.Width(_wd);
    trend_list_Ptr.Add(trend_obj);
  }
}

双柱法刻画中型趋势的转向与纠正

中型趋势用连续两根柱的极值关系来定义,即「双柱走势」。向上段要求后一根柱的最高价与最低价同时高于前两根柱对应极值,向下段则同时低于,连点成线就是中型趋势线。 若原向上段里,后一根最高价未超前两柱最高、但最低价却跌破前两柱最低,方向直接翻为向下;反向同理。这段规则里原文重复了一遍同一条件,实际只需记一次。 内侧柱(最低高于前低、最高低于前高)不参与图形构建,外侧柱(最高破前高、最低破前低)则按自身方向续画一段。这两类形态在 MT5 周线或日线叠加手动连线时很容易肉眼漏掉,建议用脚本标出。 中型趋势反向的唯一信号是对应顶部或底部价位的穿越:上升段被中型底部打穿才转空,下降段被中型顶部打穿才转多。若仅出现反向摆动但未吞掉前一极点,那只是纠正,趋势骨架未断。外汇与贵金属杠杆高,这种纠正常伴临时扫损,验证时请用历史数据核对穿越点。

常见问题

小型看相邻几根K线关系,中型看双柱转向结构,主要看更高层级波段;切换周期时先确认K线聚合层级再挂指标。
因角度和时间需主观校准易错,趋势线可客观画出;建议先用线段抓方向,熟练后再补角度验证。
小布会按K线聚合与双柱结构标注趋势层级,打开对应品种页即可直接看层级标签,不用自己数K线。
内包K线不破坏原线段方向,跳过即可;只有外收突破前高/低才更新线段端点。
多为未校验数组下标越界或首根K线数据不足;初始化时限制起点索引并做空值判断即可避坑。