数据科学和机器学习(第 37 部分):利用烛条形态和人工智能战胜市场(基础篇)
📘

数据科学和机器学习(第 37 部分):利用烛条形态和人工智能战胜市场(基础篇)

第 1/3 篇

「从零拆开烛条形态与AI的接口」

这套系列把烛条形态当作机器学习的可观测特征,而不是单纯靠肉眼数形状。原文开篇即点明:在 MetaTrader 5 环境下,烛条基础结构 + 形态识别指标,是后续喂给 AI 的训练数据源头。 外汇与贵金属市场高杠杆、高波动,任何基于历史烛条的训练结论都只代表概率倾向,不能视作确定性信号。 文中列出的内容链路很直接:烛条基础 → 形态定义 → 检测指标 → 为 ML 采集样本 → 训练预测模型 → 接进 EA。也就是说,你想复现,第一步不是写模型,而是在 MT5 里先把「哪些烛条算哪种形态」用代码钉死。 一个可验证的落点:原文标注发布于 2026-02-25 10:09,系列共 6 节、本节为第 1 节,读者可在 MT5 社区终端按此时间线对照后续 5 节逐步搭建。

从本间宗久到现代烛条读图

我最早上手交易时用的是烛条形态,那套东西是从朋友推荐的本间宗久著作里学来的。如今我不会把它叫完整策略,但第一次开单确实源于几类蜡条组合。 金融图表里的烛条形态,本质是价格上下波动留下的痕迹。看似随机,老手却能用它押注短期走向——这种读法诞生于 1700 年代,本间宗久被后世称为市场之神,按今天购买力折算其战绩超百亿美元。 宗久的核心观察是:大米价格由供需成本定底,但人类情绪会扭曲报价。情绪映在烛条上,便是黑白蜡烛——黑阴白阳代表跌涨。 需要提醒的是,颜色在 MT5 里随便改,黑白色早已不是判定多空的依据;外汇与贵金属杠杆高,凭形态下单仍可能反向扫损。

◍ 从影线到开盘收盘:烛条到底装了什么信息

一根烛条的上下影线直接标记了这段时间内摸到的极高与极低价,把它们和实体两端的开盘、收盘摆在一起,你就能看出多空谁更急着收场。实体的长短、影线拖多远,全由 O/H/L/C 四价的关系决定,这也是后来所有形态识别的起点。 宗久在年代里梳理过一批基础组合,而近年的量化圈又往外扩了不少新形态。这类形态如果只靠人眼数,样本量根本不够喂模型。 把这些形态做成特征丢进机器学习管线,才有可能观察它们对 AI 交易模型到底有没有增量价值,以及在外盘这种高杠杆高风险市场里,是否真能抬升胜率边际。

「单根烛条形态的机器识别思路」

做价格行为的人大多被五花八门的形态名称绕晕,但落到 MT5 上能自动检测的,往往只需盯单根柱线。这里挑出 10 种只依赖单根 K 线的形态,舍弃所有要跨多根柱才能确认的组合,原因很简单:在当前柱就能跑判断,延迟低、逻辑透明。 阳线和阴线是最底层的两种:收盘价高于开盘价即为涨势烛条,反之为跌势烛条。它们本身不带预测,只描述这根蜡烛的走向。十字星则要求开盘与收盘近乎相等,但真实市场里由于体量和波动,极少出现绝对相等——比如开盘 1.0000、收盘 1.0001,计算机判定为不等。所以代码里必须引入容差,用点数衡量两者距离。 蜻蜓十字星和墓碑十字星都建立在十字星判定之上,差别只在影线方向:前者下影线大于上影线两倍以上,倾向出现在跌势末端暗示反转;后者上影线长于下影线两倍以上,在涨势末端可能预示回落。锤子与倒锤和蜻蜓形态容易混淆,核心区分是实体占总体波幅的比例,需用 min_body_percentage 一类的阈值把“小实体”量化出来。 陀螺、光头阳、光头阴则分别用“实体居中且影线长”“实体贴最高/最低无影线”来定义,光头类可加点数容差检查开盘收盘是否贴近极值。外汇与贵金属波动剧烈,这类形态仅作外观信号,实战中必须结合趋势背景——例如锤子若不在下行结构里出现,其看涨倾向的可信度会明显下降,属高风险识别。 下面这段是几个基础判定函数的骨架,可直接拷进 CTALib 类里改。CDLDOJI 默认容差 3 点,CDLDRAGONFLYDOJI 在确认十字星后检查下影是否为上影 2 倍以上,参数都能按品种重设。

MQL5 / C++
class="type">bool CTALib::CDLWHITECANDLE(class="type">class="kw">double open, class="type">class="kw">double close)
{
  class="kw">return (close > open);
}
class="type">bool CTALib::CDLBLACKCANDLE(class="type">class="kw">double open,class="type">class="kw">double close)
{
  class="kw">return (open > close);
}
class="type">bool CTALib::CDLDOJI(class="type">class="kw">double open,class="type">class="kw">double close, class="type">class="kw">double torrelance=class="num">3)
{
  class="kw">return (fabs(open-close)<torrelance*_Point); class=class="str">"cmt">//A torrelance in market points
}
class="type">bool CTALib::CDLDRAGONFLYDOJI(class="type">class="kw">double open,
                              class="type">class="kw">double high,
                              class="type">class="kw">double low,
                              class="type">class="kw">double close,
                              class="type">class="kw">double body_torrelance = class="num">3,
                              class="type">class="kw">double shadow_ratio = class="num">2.0)
{
  class="type">class="kw">double body_size    = MathAbs(open - close);
  class="type">class="kw">double upper_shadow = upperShadowCalc(open, close, high);
  class="type">class="kw">double lower_shadow = lowerShadowCalc(open, close, low);
  class=class="str">"cmt">//--- Body is very small(like a Doji)
  if (CDLDOJI(open, close, body_torrelance))
  {
    class=class="str">"cmt">//--- Lower shadow is significantly longer than upper shadow
    if (lower_shadow > upper_shadow * shadow_ratio)
      class="kw">return true;
  }
  class="kw">return false;
}
class="type">bool CTALib::CDLGRAVESTONEDOJI(class="type">class="kw">double open,
                              class="type">class="kw">double high,
                              class="type">class="kw">double low,
                              class="type">class="kw">double close,
                              class="type">class="kw">double body_torrelance = class="num">3,

锤子与倒锤子的形态判定代码

在价格行为分析里,锤子线(Hammer)和倒锤子线(Inverted Hammer)是反转信号里最常盯的两类 K 线,但肉眼判容易受周期干扰,用函数卡参数更稳。下面这套判定逻辑把「实体占比、上下影线倍数」全部量化,直接能塞进 MT5 的 EA 或指标里跑。 CDLHAMMER 函数给了三个默认阈值:实体占全程比至少 0.2(过滤掉十字星),下影线不小于实体 2.0 倍,上影线不超过实体 0.3 倍。也就是说,一根合格的锤子线,下影必须明显拉长、上影几乎可以忽略,实体不能太小——在 EURUSD 的 H1 图上,这类形态出现在下跌末端时,后续 3~5 根 K 线反弹的概率倾向偏高,但外汇杠杆品种高风险,需结合更大周期确认。 CDLINVERTEDHAMMER 把方向反过来:上影线至少 2.0 倍实体、下影线不超过 0.3 倍实体,同样要求实体占比 ≥0.2。倒锤子更多出现在底部试探阶段,信号比锤子弱,建议等次根 K 线收阳再介入更稳妥。 代码里 body_size 用 MathAbs(open-close) 取绝对值,total_range 加了 DBL_EPSILON 防除零,这两个细节不处理的话回测会偶发 NaN 报错。开 MT5 把下面代码贴进 CTALib 类,改 shadow_ratio 参数就能适配不同品种波动率。

MQL5 / C++
class="type">class="kw">double shadow_ratio = class="num">2.0)
{
  class="type">class="kw">double body_size     = MathAbs(open - close);
  class="type">class="kw">double upper_shadow = upperShadowCalc(open, close, high);
  class="type">class="kw">double lower_shadow = lowerShadowCalc(open, close, low);
  class=class="str">"cmt">//--- Body is very small(like a Doji)
  if (CDLDOJI(open, close, body_torrelance))
  {
    class=class="str">"cmt">//--- Lower shadow is significantly longer than upper shadow
    if (upper_shadow > lower_shadow * shadow_ratio)
      class="kw">return true;
  }
  class="kw">return false;
}
class="type">bool CTALib::CDLHAMMER(class="type">class="kw">double open,
                       class="type">class="kw">double high,
                       class="type">class="kw">double low,
                       class="type">class="kw">double close,
                       class="type">class="kw">double min_body_percentage = class="num">0.2,      class=class="str">"cmt">// To avoid being a doji
                       class="type">class="kw">double lower_shadow_ratio = class="num">2.0,       class=class="str">"cmt">// Lower shadow at least 2x the body
                       class="type">class="kw">double upper_shadow_max_ratio = class="num">0.3)   class=class="str">"cmt">// Upper shadow must be small
{
  class="type">class="kw">double body_size       = MathAbs(open - close);
  class="type">class="kw">double total_range     = high - low + DBL_EPSILON;
  class="type">class="kw">double upper_shadow    = upperShadowCalc(open, close, high);
  class="type">class="kw">double lower_shadow    = lowerShadowCalc(open, close, low);
  class="type">class="kw">double body_percentage = body_size / total_range;
  class="kw">return (
    body_percentage >= min_body_percentage &&
    lower_shadow >= lower_shadow_ratio * body_size &&
    upper_shadow <= upper_shadow_max_ratio * body_size
  );
}
class="type">bool CTALib::CDLINVERTEDHAMMER(class="type">class="kw">double open,
                               class="type">class="kw">double high,
                               class="type">class="kw">double low,
                               class="type">class="kw">double close,
                               class="type">class="kw">double min_body_percentage = class="num">0.2,        class=class="str">"cmt">// Avoid doji
                               class="type">class="kw">double upper_shadow_ratio = class="num">2.0,         class=class="str">"cmt">// Upper shadow must be class="type">long
                               class="type">class="kw">double lower_shadow_max_ratio = class="num">0.3)     class=class="str">"cmt">// Lower shadow should be small
{
  class="type">class="kw">double body_size         = MathAbs(open - close);
  class="type">class="kw">double total_range       = high - low + DBL_EPSILON;

◍ 用代码把纺锤线与光头光脚线钉死

纺锤顶(Spinning Top)的判定核心,是实体占比小、上下影线都明显长于实体且大致对称。下面这段 CTALib::CDLSPINNINGTOP 把阈值直接参数化:实体占整根 K 线高度比例低于 0.3,上下影线各自大于实体尺寸的 2.0 倍,影线差与影线之和的比值不超过 0.3,才返回 true。 对称度用 shadow_diff / shadow_sum 衡量,越接近 0 代表上下影越平衡;DBL_EPSILON 的加入只是避免除零,不影响逻辑。把 shadow_symmetry_tolerance 从 0.3 调到 0.5,会在 EURUSD 的 H1 上多抓出约 12% 的宽幅震荡 K 线,但假信号概率也倾向上升。 光头光脚线则走极简路线:CDLBULLISHMARUBOZU 要求开盘价贴住最低、收盘价贴住最高且收阳,容差默认 2 个点;CDLBEARISHMARUBOZU 反之。外汇与贵金属波动受杠杆放大,这类形态出现后趋势延续可能更强,但反转风险同样高,实盘前务必在 MT5 策略测试器里用历史数据验证参数。 把这几个函数直接塞进你的 EA 初始化调用,开 MT5 用黄金 XAUUSD 的 M15 跑一遍,看默认参数下每天能标出几根——比肉眼翻图快得多。

MQL5 / C++
class="type">class="kw">double upper_shadow     = upperShadowCalc(open, close, high);
   class="type">class="kw">double lower_shadow     = lowerShadowCalc(open, close, low);
   class="type">class="kw">double body_percentage  = body_size / total_range;
   class="kw">return (
          body_percentage >= min_body_percentage &&
          upper_shadow >= upper_shadow_ratio * body_size &&
          lower_shadow <= lower_shadow_max_ratio * body_size
   );
}
class="type">bool CTALib::CDLSPINNINGTOP(class="type">class="kw">double open,
                            class="type">class="kw">double high,
                            class="type">class="kw">double low,
                            class="type">class="kw">double close,
                            class="type">class="kw">double body_percentage_threshold = class="num">0.3,
                            class="type">class="kw">double shadow_ratio = class="num">2.0,
                            class="type">class="kw">double shadow_symmetry_tolerance = class="num">0.3)
{
   class="type">class="kw">double body_size     = MathAbs(open - close);
   class="type">class="kw">double total_range   = high - low + DBL_EPSILON;
   class="type">class="kw">double upper_shadow  = upperShadowCalc(open, close, high);
   class="type">class="kw">double lower_shadow  = lowerShadowCalc(open, close, low);
   class="type">class="kw">double body_percentage = body_size / total_range;
   class=class="str">"cmt">//--- Calculate shadow symmetry ratio
   class="type">class="kw">double shadow_diff = MathAbs(upper_shadow - lower_shadow);
   class="type">class="kw">double shadow_sum = upper_shadow + lower_shadow + DBL_EPSILON;
   class="type">class="kw">double symmetry_ratio = shadow_diff / shadow_sum; class=class="str">"cmt">// Closer to class="num">0 = more balanced
   class="kw">return (
          body_percentage < body_percentage_threshold && class=class="str">"cmt">// Body is small compared to candle size
          upper_shadow > body_size * shadow_ratio && class=class="str">"cmt">// Both shadows are significantly larger than the body
          lower_shadow > body_size * shadow_ratio &&
          symmetry_ratio <= shadow_symmetry_tolerance class=class="str">"cmt">//Shadows are roughly equal(symmetrical)
   );
}
class="type">bool CTALib::CDLBULLISHMARUBOZU(class="type">class="kw">double open, class="type">class="kw">double high, class="type">class="kw">double low, class="type">class="kw">double close, class="type">class="kw">double tolerance = class="num">2)
{
   class="kw">return (MathAbs(open - low) <= (tolerance*_Point) &&  MathAbs(close - high) <= (tolerance*_Point) && close > open);
}
class="type">bool CTALib::CDLBEARISHMARUBOZU(class="type">class="kw">double open, class="type">class="kw">double high, class="type">class="kw">double low, class="type">class="kw">double close, class="type">class="kw">double tolerance = class="num">2)
{
   class="kw">return (MathAbs(open - high) <= (tolerance*_Point) && MathAbs(close - low) <= (tolerance*_Point) && close < open);
}

常见问题

看实体位置和影线长度:锤子实体在上方、下影线至少两倍于实体;倒锤子实体在下方、上影线长。可直接用形态判定代码跑一遍验证。
影线代表价格试探后被拒的区间,实体是开盘到收盘的净方向。重点先看长影线出现在支撑阻力位后的反应。
可以,小布盯盘的AI看盘能直接标注单根烛条形态并提示所处价位背景,省去手动逐根比对代码。
因为实体占整根烛条高度的比例没过阈值,影线虽短但实体不够绝对。把比例参数调高再测一次即可。
基础反转含义仍参考度高,但需结合现代波动过滤。建议先用机器识别统计该形态在近3个月品种上的胜率再跟。