从新手到专家:对K线进行编程
内容
引言
随着时间的推移,我们已经学习并记住了许多K线形态的名称。然而,在图表上用肉眼识别它们是一项费力的工作,并且可能会受到视差误差的影响。由于K线形态逻辑的典型定义方式,错误解读的可能性非常高。
例如,看涨吞没形态由一根看跌K线后跟一根看涨K线组成。这根看涨K线的开盘价低于前一根看跌K线的收盘价,并且其收盘价高于前者的开盘价,从而在时间序列中完全覆盖了看跌K线的实体。挑战在于,要准确判断看涨K线的开盘价相对于看跌K线收盘价的位置。人眼容易出现偶尔的误判,尤其是在进行视觉图表分析时。
现在,想象一下在历史数据上手动回测这种形态——这将是件艰巨的工作,并且容易产生多种错误。然而,如果一个算法被正确编码来检测这些形态并在图表上放置战略性标记,那么识别和回测它们就会变得显著更容易和更准确。
本文目的
在本文中,我旨在探讨K线形态的编程、其背后的MQL5基础数学,并最终在现有基础上开发一个K线形态库。
许多投资网站用自然语言列出了大量的K线形态,但只有少数会进一步探索其算法结构。有些人可能会声称,所有可能的K线形态都已经被定义过了。然而,我相信仍有创新的空间——新的形态可以被发现和命名。
在本文中,我们将涵盖几个著名的形态,同时赋予您能力,让您能够为自己在图表上观察到的任何K线形态进行编码,并以自己的方式为其命名。为了让内容更清晰明了,我们将专注于流行的形态以便更好地理解。
重要的是要认识到,编码和发明新形态可能是一个乏味的过程,但其回报是巨大的——创建一个能够自动识别形态的算法,将使您从重复性的手动分析中永久解放出来。
接下来是?
下一节充满了我的研究和关键概念,我整理这些是为了给本次讨论提供一个结构。请认真往下读,我相信您会发现本文的巨大价值。
理解K线数据及其基础编程操作
我假设您已经通过各种来源(包括MQL5社区、其他网站和书籍)熟悉了K线形态的基础知识。如果您需要复习,可以在继续之前快速浏览这个链接以获取一些背景信息。我在这里的目的不是重新发明轮子,而是展示我们如何应用MQL5语言将传统的K线分析转化为算法框架。这种方法有助于那些从概念上理解K线形态的人,培养一种更结构化、算法化的思维方式——这可能会使他们能够在MQL5中开始自动化自己的交易策略。
对于初学者来说,从简单的概念开始并逐步建立编码技能非常重要。首先,学习使用基本的关系运算符来定义看涨和看跌K线。当您对这些比较感到自如后,再通过整合算术运算来测量实体大小和影线长度,进而转向单根K线形态。在掌握了单根K线分析之后,再进入多根K线形态的学习,在那里您将学会使用索引来比较多根K线的数据。使用像 Print() 这样的函数来测试您的工作,有助于验证您的逻辑是否按预期工作。
简要回顾一下,K线是交易中用来显示价格在特定时期(如一小时或一天)内如何变动的一种可视化工具。每根K线由四个关键价格定义:开盘价(期间开始时的价格)、最高价(期间内的最高价格)、最低价(期间内的最低价格)和收盘价(期间结束时的价格)。K线的“实体”代表开盘价和收盘价之间的区间,而“影线”则从实体延伸至最高价和最低价。这种结构使您能够快速评估市场情绪。例如,如果收盘价高于开盘价,则该K线被认为是看涨的,表明上涨动能。相反,如果收盘价低于开盘价,则是看跌的,表明下跌趋势。
我想向您介绍几个关键术语,我认为,在您开始处理时间序列数据时,这些术语是必不可少的。这些概念对于在MQL5中理解和实现K线形态识别至关重要。我根据我的研究,用我自己的话解释了它们,以提供一个清晰且实用的解释:
1. 关系运算符
这些是比较运算符,类似于您在高中可能学过的不等式。然而,在MQL5中,它们是基于编程逻辑的角度被应用的。它们在 MQL5文档 中与其他常用操作一起得到了详尽的解释。以下是我们在讨论中使用的关系运算符列表。
- <(小于)
- >(大于)
- == (等于)
- != (不等于)
- <= (小于或等于)
- >= (大于或等于)
需要注意的是,这些运算符不仅限于K线形态编程。它们也可以用来比较各种市场价值,在算法交易的决策中扮演着至关重要的角色。
在时间序列数据中,每根K线(或柱)都通过一个索引来引用。最近的K线索引为0,而更早的K线则使用递增的索引值(例如1、2、3等)来引用。理解这一点有助于正确地遍历历史价格数据。
3. 时间序列
时间序列是一种特殊的数组,用于存储历史价格或指标数据,其索引是反向的。在时间序列中,最新的数据(如当前或最近的K线)通过索引0访问,而更旧的数据则跟在更高的索引号之后。
4. 平均真实波幅(ATR)
ATR是一个波动率指标,它为K线形态定义了动态阈值,确保其能适应市场状况。例如,锤子线形态要求一个较小的实体(小于ATR的30%)和一个至少是实体两倍长的下影线,从而能够在不同资产和时间框架上进行灵活检测。
挑战在于定义什么是“小”、“长”或“大”。一个固定值(例如,实体小于10个点)在不同的资产或市场条件下不会持续有效。在5分钟图表上,对于像EUR/USD这样的低波动性货币对,10个点的变动可能很重要;但对于像GBP/JPY这样的高波动性货币对在日线图上,这可能微不足道。这就是ATR大放异彩的地方——它提供了一个动态的、经过波动率调整的阈值,专为特定资产和时间框架量身定制。
通过使用ATR,识别K线形态的条件变得具有自适应性:
- 在高波动性市场(高ATR)中,“小实体”的绝对值可能更大,但相对于近期的价格波动来说仍然很小。
- 在低波动性市场(低ATR)中,即使是一个微小的绝对变动也可能被认为是显著的。
5. MathAbs
MathAbs是MQL5中的一个内置函数,用于计算一个数字的绝对值。绝对值就是数字到零的距离,其结果总是一个非负(正或零)的值。
在此情境下如何工作:
- 如果您给它一个负数,它会将其变为正数。例如,MathAbs(-5) 返回 5。
- 如果数字已经是正数或零,它保持不变。例如,MathAbs(5) 返回 5,MathAbs(0) 返回 0。
在K线形态中,MathAbs用于测量K线实体的大小,即收盘价和开盘价之间的差值,例如 Close[1] - Open[1]。
为什么使用MathAbs?
1. 因为实体大小需要是一个正值,无论K线是看涨(收盘价 > 开盘价)还是看跌(收盘价 < 开盘价)。例如:
- 看涨K线:Close[1] = 10, open[1] = 8 → 10 - 8 = 2。
- 看跌K线:Close[1] = 8, open[1] = 10 → 8 - 10 = -2,但 MathAbs(8 - 10) = 2。
2. 这确保了实体大小始终为正,以便在形态规则中进行一致的比较。
在MQL5中使用关系运算符比较价格
在MQL5中,关系运算符是必不可少的工具,它们允许您比较数值,例如K线的开盘价和收盘价。我们上面提到的运算符 <, >, ==, !=, <=, 和 >= 会返回真(1)或假(0),并帮助确定一根K线是看涨还是看跌。
例如,
- 当条件 close[0] > open[0] 成立时,就识别出了一根看涨K线,其中 [0] 指的是最新的K线索引。
另一方面,
- 看跌K线由 close[0] < open[0] 表示。
这种基本比较是K线形态识别的基石。将这些比较看作是关于价格的简单问题:“这根K线的收盘价是否高于其开盘价?” 如果是,那么您看到的就是一个看涨信号。
K线形态
根据我的研究,我们可以将K线形态分为两种主要类型:单根K线形态和多根K线形态。现在,我们到目前为止讨论的一切都将开始融会贯通。为了让您有更清晰的理解,让我们简要比较一下两者。我准备了两个包含详细信息的表格来突出它们的不同。
单根K线形态
在处理单根K线形态时,算术运算是必不可少的,用于测量K线的各个方面,如其实体大小、影线长度和整体范围。单根K线形态,如十字星,发生在开盘价和收盘价几乎相等时,非常重要,因为它们标志着市场的犹豫不决或潜在的反转。通过分析开盘价、最高价、最低价和收盘价之间的差异,您可以推导出这些形态,并获得对重要市场变化的洞察。
十字星K线
| K线名称 | 逻辑描述 | 参考图片 |
|---|---|---|
| 十字星 | 当开盘价和收盘价非常接近或相等时,就识别出了十字星K线形态,表明市场犹豫不决。这意味着 open[1] ≈ close[1],而最高价和最低价可能有显著差异。十字星可以以不同的形式出现,例如长腿十字星、蜻蜓十字星或墓碑十字星,具体取决于影线的位置。// Check for Doji pattern if( MathAbs(Open[1] - Close[1]) < Point * 2 ) // Open and close are almost equal { Print("Doji pattern detected"); } | ![]() |
多K线形态
多根K线形态要求我们分析连续K线之间的关系。在MQL5中,我们使用索引来引用过去的K线:close[1] 代表前一根K线的收盘价,而 close[2] 代表再前一根。一个流行的多根K线形态是 看涨吞没,其中一根小的看跌K线后跟一根更大的看涨K线,后者完全“吞没”了前者。
要编码这个形态,您需要验证前一根K线是看跌的(使用 close[1] < open[1]),然后检查当前K线是看涨的(使用 close[0] > open[0]),同时还要确认当前K线的实体延伸到了前一根K线的边界之外。您代码中的条件确保该形态遵循预期的序列和大小关系,这对于准确检测看涨吞没形态至关重要。
| K线形态 | 逻辑描述 | 参考图片 |
|---|---|---|
| 看涨吞没 | 当索引为2的K线是看跌的(其收盘价低于开盘价,即 Close[2] < Open[2]),并且索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1])时,就识别出了看涨吞没形态。此外,索引为1的K线必须通过在索引为2的K线收盘价之下开盘(Open[1] < Close[2])并在其开盘价之上收盘(Close[1] > Open[2])来吞没索引为2的K线的实体。// Check for bullish engulfing pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish Open[1] < Close[2] && // Candle at index 1 opens below candle at index 2 close Close[1] > Open[2] ) // Candle at index 1 closes above candle at index 2 open { Print("Bullish engulfing pattern detected"); } | ![]() |
构建已知K线形态的集合及一个可复用的K线形态函数库。
为了简化这个过程,我整理了两个表格,其中包含了一系列知名的K线形态,并创建了一个包含描述列和参考图片列的综合参考表。这个表格将在开发期间和为未来的读者提供一个宝贵的资源。此外,它可以随着时间的推移,通过新的发现进行扩展和完善,从而更容易构建一个更完整、更复杂的K线形态库。
单根K线形态集合
| K线形态 | 逻辑描述 | 参考图片 |
|---|---|---|
| 锤头线 | 当索引为1的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.3倍,即 MathAbs(Close[1] - Open[1]) < 0.3 * ATR)、长下影线(从开盘价或收盘价中较低者到最低价的距离至少是实体大小的两倍,即 MathMin(Open[1], Close[1]) - Low[1] >= 2 * MathAbs(Close[1] - Open[1])),以及很小或没有上影线(从开盘价或收盘价中较高者到最高价的距离小于或等于实体大小的一半,即 High[1] - MathMax(Open[1], Close[1]) <= 0.5 * MathAbs(Close[1] - Open[1]))时,就识别出了锤头线形态。// Check for Hammer pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body // Long lower wick (MathMin(Open[1], Close[1]) - Low[1]) >= 2 * MathAbs(Close[1] - Open[1]) && // Small or no upper wick (High[1] - MathMax(Open[1], Close[1]) <= 0.5 * MathAbs(Close[1] - Open[1])) { Print("Hammer pattern detected"); } | ![]() |
| 射击之星 | 当索引为1的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.3倍,即 MathAbs(Close[1] - Open[1]) < 0.3 * ATR)、长上影线(从开盘价或收盘价中较高者到最高价的距离至少是实体大小的两倍,即 High[1] - MathMax(Open[1], Close[1]) >= 2 * MathAbs(Close[1] - Open[1])),以及很小或没有下影线(从开盘价或收盘价中较低者到最低价的距离小于或等于实体大小的一半,即 MathMin(Open[1], Close[1]) - Low[1] <= 0.5 * MathAbs(Close[1] - Open[1]))时,就识别出了射击之星形态。// Check for Shooting Star pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body // Long upper wick (High[1] - MathMax(Open[1], Close[1]) >= 2 * MathAbs(Close[1] - Open[1]) && // Small or no lower wick (MathMin(Open[1], Close[1]) - Low[1]) <= 0.5 * MathAbs(Close[1] - Open[1]) ) { Print("Shooting Star pattern detected"); } | |
| 标准十字星 | 当索引为1的K线具有极小的实体,意味着开盘价和收盘价几乎相等(其收盘价和开盘价的绝对差值小于ATR的0.1倍,即 MathAbs(Close[1] - Open[1]) < 0.1 * ATR)时,就识别出了标准十字星形态。// Check for Standard Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] ) // Open and close are nearly equal { Print("Standard Doji pattern detected"); } | ![]() |
| 蜻蜓十字星 | 当索引为1的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.1倍,即 MathAbs(Close[1] - Open[1]) < 0.1 * ATR)、长下影线(从开盘价或收盘价中较低者到最低价的距离大于ATR的0.5倍,即 MathMin(Open[1], Close[1]) - Low[1] > 0.5 * ATR),以及几乎没有或完全没有上影线(从开盘价或收盘价中较高者到最高价的距离小于ATR的0.1倍,即 High[1] - MathMax(Open[1], Close[1]) < 0.1 * ATR)时,就识别出了蜻蜓十字星形态。// Check for Dragonfly Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] && // Small body (MathMin(Open[1], Close[1]) - Low[1]) > 0.5 * ATR[1] && // Long lower wick (High[1] - MathMax(Open[1], Close[1]) < 0.1 * ATR[1] ) // Little to no upper wick { Print("Dragonfly Doji pattern detected"); } | ![]() |
| 墓碑十字星 | 当索引为1的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.1倍,即 MathAbs(Close[1] - Open[1]) < 0.1 * ATR)、长上影线(从开盘价或收盘价中较高者到最高价的距离大于ATR的0.5倍,即 High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR),以及几乎没有或完全没有下影线(从开盘价或收盘价中较低者到最低价的距离小于ATR的0.1倍,即 MathMin(Open[1], Close[1]) - Low[1] < 0.1 * ATR)时,就识别出了墓碑十字星形态。// Check for Gravestone Doji pattern if( MathAbs(Close[1] - Open[1]) < 0.1 * ATR[1] && // Small body (High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR[1] && // Long upper wick (MathMin(Open[1], Close[1]) - Low[1]) < 0.1 * ATR[1] ) // Little to no lower wick { Print("Gravestone Doji pattern detected"); } | ![]() |
| 看涨光头/光脚阳线 | 当索引为1的K线是强烈的看涨K线(其收盘价高于开盘价,即 Close[1] > Open[1])且几乎没有影线,意味着开盘价非常接近最低价(Open[1] - Low[1] < 0.1 * ATR)并且收盘价非常接近最高价(High[1] - Close[1] < 0.1 * ATR)时,就识别出了看涨光头/光脚阳线形态。// Check for Bullish Marubozu pattern if( Close[1] > Open[1] && // Bullish candle (High[1] - Close[1]) < 0.1 * ATR[1] && // Close is very close to high (Open[1] - Low[1]) < 0.1 * ATR[1] ) // Open is very close to low { Print("Bullish Marubozu pattern detected"); } | ![]() |
| 看跌光头/光脚阴线 | 当索引为1的K线是强烈的看跌K线(其收盘价低于开盘价,即 Close[1] < Open[1])且几乎没有影线,意味着开盘价非常接近最高价(High[1] - Open[1] < 0.1 * ATR)并且收盘价非常接近最低价(Close[1] - Low[1] < 0.1 * ATR)时,就识别出了看跌光头/光脚阴线形态。// Check for Bearish Marubozu pattern if( Close[1] < Open[1] && // Bearish candle (High[1] - Open[1]) < 0.1 * ATR[1] && // Open is very close to high (Close[1] - Low[1]) < 0.1 * ATR[1] ) // Close is very close to low { Print("Bearish Marubozu pattern detected"); } | ![]() |
| 纺锤线 | 当索引为1的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.3倍,即 MathAbs(Close[1] - Open[1]) < 0.3 * ATR)和长长的上、下影线(从开盘价或收盘价中较高者到最高价的距离大于ATR的0.5倍,即 High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR,并且从开盘价或收盘价中较低者到最低价的距离也大于ATR的0.5倍,即 MathMin(Open[1], Close[1]) - Low[1] > 0.5 * ATR)时,就识别出了纺锤线形态。// Check for Spinning Top pattern if( MathAbs(Close[1] - Open[1]) < 0.3 * ATR[1] && // Small body (High[1] - MathMax(Open[1], Close[1]) > 0.5 * ATR[1] && // Long upper wick (MathMin(Open[1], Close[1]) - Low[1]) > 0.5 * ATR[1] ) // Long lower wick { Print("Spinning Top pattern detected"); } | ![]() |
多根K线形态集合
| K线形态 | 逻辑描述 | 参考图片 |
|---|---|---|
| 启明星 | 当索引为3的K线是看跌的(其收盘价低于开盘价,即 Close[3] < Open[3]),索引为2的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.3倍,即 MathAbs(Close[2] - Open[2]) < 0.3 * ATR),并且索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1])时,就识别出了启明星形态。此外,K线1的收盘价必须高于K线3实体的中点(Close[1] > (Open[3] + Close[3]) / 2)。// Check for Morning Star pattern if( Close[3] < Open[3] && // Candle at index 3 is bearish MathAbs(Close[2] - Open[2]) < 0.3 * ATR[1] && // Candle at index 2 has a small body Close[1] > Open[1] && // Candle at index 1 is bullish Close[1] > (Open[3] + Close[3]) / 2 ) // Candle at index 1 closes above midpoint of candle 3 { Print("Morning Star pattern detected"); } | ![]() |
| 黄昏之星 | 当索引为3的K线是看涨的(其收盘价高于开盘价,即 Close[3] > Open[3]),索引为2的K线具有小实体(其收盘价和开盘价的绝对差值小于ATR的0.3倍,即 MathAbs(Close[2] - Open[2]) < 0.3 * ATR),并且索引为1的K线是看跌的(其收盘价低于开盘价,即 Close[1] < Open[1])时,就识别出了黄昏星形态。此外,K线1的收盘价必须低于K线3实体的中点(Close[1] < (Open[3] + Close[3]) / 2)。// Check for Evening Star pattern if( Close[3] > Open[3] && // Candle at index 3 is bullish MathAbs(Close[2] - Open[2]) < 0.3 * ATR[1] && // Candle at index 2 has a small body Close[1] < Open[1] && // Candle at index 1 is bearish Close[1] < (Open[3] + Close[3]) / 2 ) // Candle at index 1 closes below midpoint of candle 3 { Print("Evening Star pattern detected"); } | ![]() |
| 三白兵 | 当出现三根连续的看涨K线时,就识别出了三白兵形态:索引为3的K线(Close[3] > Open[3]),索引为2的K线(Close[2] > Open[2]),以及索引为1的K线(Close[1] > Open[1])。每根K线的实体必须大于ATR(例如,Close[3] - Open[3] > ATR),具有小的上影线(例如,High[3] - Close[3] < 0.3 * ATR),并且每根K线的开盘价都在前一根K线的实体之内(例如,Open[2] > Open[3] && Open[2] < Close[3])。// Check for Three White Soldiers pattern // Candle 3 is bullish with large body and small upper wick if( Close[3] > Open[3] && (Close[3] - Open[3]) > ATR[1] && (High[3] - Close[3]) < 0.3 * ATR[1] && // Candle 2 is bullish with large body and small upper wick Close[2] > Open[2] && (Close[2] - Open[2]) > ATR[1] && (High[2] - Close[2]) < 0.3 * ATR[1] && // Candle 1 is bullish with large body and small upper wick Close[1] > Open[1] && (Close[1] - Open[1]) > ATR[1] && (High[1] - Close[1]) < 0.3 * ATR[1] && // Candle 2 opens within candle 3's body and closes higher Open[2] > Open[3] && Open[2] < Close[3] && Close[2] > Close[3] && // Candle 1 opens within candle 2's body and closes higher Open[1] > Open[2] && Open[1] < Close[2] && Close[1] > Close[2] ) { Print("Three White Soldiers pattern detected"); } | ![]() |
| 三只乌鸦 | 当出现三根连续的看跌K线时,就识别出了三只乌鸦形态:索引为3的K线(Close[3] < Open[3]),索引为2的K线(Close[2] < Open[2]),以及索引为1的K线(Close[1] < Open[1])。每根K线的实体必须大于ATR(例如,Open[3] - Close[3] > ATR),具有小的下影线(例如,Open[3] - Low[3] < 0.3 * ATR),并且每根K线的开盘价都在前一根K线的实体之内(例如,Open[2] < Open[3] && Open[2] > Close[3])。// Check for Three Black Crows pattern // Candle 3 is bearish with large body and small lower wick if( Close[3] < Open[3] && (Open[3] - Close[3]) > ATR[1] && (Open[3] - Low[3]) < 0.3 * ATR[1] && // Candle 2 is bearish with large body and small lower wick Close[2] < Open[2] && (Open[2] - Close[2]) > ATR[1] && (Open[2] - Low[2]) < 0.3 * ATR[1] && // Candle 1 is bearish with large body and small lower wick Close[1] < Open[1] && (Open[1] - Close[1]) > ATR[1] && (Open[1] - Low[1]) < 0.3 * ATR[1] && // Candle 2 opens within candle 3's body and closes lower Open[2] < Open[3] && Open[2] > Close[3] && Close[2] < Close[3] && // Candle 1 opens within candle 2's body and closes lower Open[1] < Open[2] && Open[1] > Close[2] && Close[1] < Close[2] ) { Print("Three Black Crows pattern detected"); } | ![]() |
| 看涨孕线 | 当索引为2的K线是看跌的(其收盘价低于开盘价,即 Close[2] < Open[2])且实体大于ATR(Open[2] - Close[2] > ATR),并且索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1])且其实体完全位于K线2的实体之内(Open[1] > Close[2] && Close[1] < Open[2])时,就识别出了看涨孕线形态。// Check for Bullish Harami pattern // Candle 2 is bearish with large body if( Close[2] < Open[2] && (Open[2] - Close[2]) > ATR[1] && // Candle 1 is bullish and within candle 2's body Close[1] > Open[1] && Open[1] > Close[2] && Close[1] < Open[2] ) { Print("Bullish Harami pattern detected"); } | ![]() |
| 看跌孕线 | 当索引为2的K线是看涨的(其收盘价高于开盘价,即 Close[2] > Open[2])且实体大于ATR(Close[2] - Open[2] > ATR),并且索引为1的K线是看跌的(其收盘价低于开盘价,即 Close[1] < Open[1])且其实体完全位于K线2的实体之内(Open[1] < Close[2] && Close[1] > Open[2])时,就识别出了看跌孕线形态。// Check for Bearish Harami pattern // Candle 2 is bullish with large body if( Close[2] > Open[2] && (Close[2] - Open[2]) > ATR[1] && // Candle 1 is bearish and within candle 2's body Close[1] < Open[1] && Open[1] < Close[2] && Close[1] > Open[2] ) { Print("Bearish Harami pattern detected"); } | ![]() |
| 看涨吞没 | 当索引为2的K线是看跌的(其收盘价低于开盘价,即 Close[2] < Open[2]),并且索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1])时,就识别出了看涨吞没形态。此外,索引为1的K线必须通过在索引为2的K线收盘价之下开盘(Open[1] < Close[2])并在其开盘价之上收盘(Close[1] > Open[2])来吞没索引为2的K线的实体。// Check for Bullish Engulfing pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish Open[1] < Close[2] && // Candle at index 1 opens below candle at index 2's close Close[1] > Open[2] ) // Candle at index 1 closes above candle at index 2's open { Print("Bullish Engulfing pattern detected"); } | ![]() |
| 看跌吞没 | 当索引为2的K线是看涨的(其收盘价高于开盘价,即 Close[2] > Open[2]),并且索引为1的K线是看跌的(其收盘价低于开盘价,即 Close[1] < Open[1])时,就识别出了看跌吞没形态。此外,索引为1的K线必须通过在索引为2的K线收盘价之上开盘(Open[1] > Close[2])并在其开盘价之下收盘(Close[1] < Open[2])来完全吞没索引为2的K线的实体。// Check for Bearish Engulfing pattern if( Close[2] > Open[2] && // Candle at index 2 is bullish Close[1] < Open[1] && // Candle at index 1 is bearish Open[1] > Close[2] && // Candle at index 1 opens above candle at index 2's close Close[1] < Open[2] ) // Candle at index 1 closes below candle at index 2's open { Print("Bearish Engulfing pattern detected"); } | ![]() |
| 看涨三内升 | 当索引为3的K线是看跌的(其收盘价低于开盘价,即 Close[3] < Open[3])且具有大实体(Open[3] - Close[3] > ATR),索引为2的K线是看涨的(Close[2] > Open[2])且被包含在K线3之内(Open[2] > Close[3] && Close[2] < Open[3]),并且K线1是看涨的(Close[1] > Open[1])且收盘价高于K线2的最高价(Close[1] > High[2])时,就识别出了看涨三内升形态。// Check for Three Inside Up pattern // Candle 3 is bearish with large body if( Close[3] < Open[3] && (Open[3] - Close[3]) > ATR[1] && // Candle 2 is bullish and within candle 3's body Close[2] > Open[2] && Open[2] > Close[3] && Close[2] < Open[3] && // Candle 1 is bullish and closes above candle 2's high Close[1] > Open[1] && Close[1] > High[2] ) { Print("Three Inside Up pattern detected"); } | ![]() |
| 看跌三内降 | 当索引为3的K线是看涨的(其收盘价高于开盘价,即 Close[3] > Open[3])且具有大实体(Close[3] - Open[3] > ATR),索引为2的K线是看跌的(Close[2] < Open[2])且被包含在K线3之内(Open[2] < Close[3] && Close[2] > Open[3]),并且K线1是看跌的(Close[1] < Open[1])且收盘价低于K线2的最低价(Close[1] < Low[2])时,就识别出了看跌三内降形态。// Check for Three Inside Down pattern // Candle 3 is bullish with large body if( Close[3] > Open[3] && (Close[3] - Open[3]) > ATR[1] && // Candle 2 is bearish and within candle 3's body Close[2] < Open[2] && Open[2] < Close[3] && Close[2] > Open[3] && // Candle 1 is bearish and closes below candle 2's low Close[1] < Open[1] && Close[1] < Low[2] ) { Print("Three Inside Down pattern detected"); } | ![]() |
| 镊子底 | 当索引为2的K线是看跌的(其收盘价低于开盘价,即 Close[2] < Open[2]),索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1]),并且两根K线的最低价几乎相等(Low[2] 和 Low[1] 之间的绝对差值小于ATR的0.1倍,即 MathAbs(Low[2] - Low[1]) < 0.1 * ATR)时,就识别出了镊子底形态。// Check for Tweezer Bottom pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish Close[1] > Open[1] && // Candle at index 1 is bullish // Lows of both candles are nearly equal MathAbs(Low[2] - Low[1]) < 0.1 * ATR[1] ) { Print("Tweezer Bottom pattern detected"); } | ![]() |
| 镊子顶 | 当索引为2的K线是看涨的(其收盘价高于开盘价,即 Close[2] > Open[2]),索引为1的K线是看跌的(其收盘价低于开盘价,即 Close[1] < Open[1]),并且两根K线的最高价几乎相等(High[2] 和 High[1] 之间的绝对差值小于ATR的0.1倍,即 MathAbs(High[2] - High[1]) < 0.1 * ATR)时,就识别出了镊子顶形态。// Check for Tweezer Top pattern if( Close[2] > Open[2] && // Candle at index 2 is bullish Close[1] < Open[1] && // Candle at index 1 is bearish // Highs of both candles are nearly equal MathAbs(High[2] - High[1]) < 0.1 * ATR[1] ) { Print("Tweezer Top pattern detected"); } | ![]() |
| 看涨向上跳空 | 当索引为2的K线是看跌的(其收盘价低于开盘价,即 Close[2] < Open[2]),并且索引为1的K线是看涨的(其收盘价高于开盘价,即 Close[1] > Open[1])且其开盘价高于K线2的开盘价(Open[1] > Open[2])时,就识别出了看涨向上跳空形态。// Check for Bullish Kicker pattern if( Close[2] < Open[2] && // Candle at index 2 is bearish // Candle at index 1 is bullish Close[1] > Open[1] && // Candle at index 1 opens above candle at index 2's open Open[1] > Open[2] ) { Print("Bullish Kicker pattern detected"); } | ![]() |
| 看跌向下跳空 | 当索引为2的K线是看涨的(其收盘价高于开盘价,即 Close[2] > Open[2]),并且索引为1的K线是看跌的(其收盘价低于开盘价,即 Close[1] < Open[1])且其开盘价低于K线2的开盘价(Open[1] < Open[2])时,就识别出了看跌向下跳空形态。// Check for Bearish Kicker pattern // Candle at index 2 is bullish if( Close[2] > Open[2] && // Candle at index 1 is bearish Close[1] < Open[1] && // Candle at index 1 opens below candle at index 2's open Open[1] < Open[2] { Print("Bearish Kicker pattern detected"); } | ![]() |
这些表格可以无限地列下去,因为我没有包含的形态还有很多。为了使讨论保持简洁,我现在将重点转向如何在一个有意义的程序中实现这些策略。最终目标是构建一个全面的K线形态库。
我进行了研究,并在MQL5的代码库中发现了杰出的作品——这些作品是由一些算法交易的先驱们十多年前开发的。您可以探索他们的工作,以获得更详细的方法。然而,在本文中,我们的目标是为初学者尽可能保持简单。考虑到这一点,我们现在将着手开发我们自己的K线形态库。
构建一个可复用的K线形态头文件
此时,我将演示如何创建一个包含一系列K线形态的函数库。我们称之为库,是因为它汇集了多个可复用的形态检测函数。一旦开发完成,只需在项目中包含该库并根据需要调用函数,就可以轻松地将这些形态集成到其他项目中。
这类文件的专业术语是头文件,我兴奋地将其命名为 infinity_candlestick_pattern.mqh,这个名字反映了它的可扩展性,因为随着时间的推移可以添加更多的形态。我已将其构建为一个模板,稍后我将在一个指标中演示它,以展示其实际用法。
在附件中,我将分享一个更全面的头文件版本,其中包含我们之前在参考表中列出的形态的函数。您可以遵循代码片段中的注释指南来进一步扩展这个库。
该文件包含两个主要函数,IsHammer 和 IsShootingStar,它们分析价格数据数组以及附带的平均真实波幅(ATR),以确定特定的K线是否满足这些形态的条件。每个函数都会验证所给索引是否有效,计算K线的实体大小,然后评估影线长度相对于实体大小和ATR值的长度。这种细致的方法使用精确的数学标准将视觉交易模式量化,从而实现能够适应市场波动的稳健形态识别能力。此外,使用 patternATR 参数(通过引用传递)有助于在后续的示例指标中使用ATR值时防止潜在的冲突和警告,确保所传递值的一致性。
要将这些函数集成到其他项目中,您只需使用 #include 指令将此头文件包含到您的源代码中。一旦包含,它们就可以通过传入适当的数组和感兴趣的索引来调用 IsHammer 或 IsShootingStar 函数。
//+------------------------------------------------------------------+ //| infinity_candlestick_pattern.mqh (Template) | //| Copyright 2025, Metaquotes Ltd | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Metaquotes Ltd" #property link "https://www.mql5.com/" #ifndef INFINITY_CANDLESTICK_PATTERNS_MQH #define INFINITY_CANDLESTICK_PATTERNS_MQH //+------------------------------------------------------------------+ //| Single-Candlestick Pattern Functions | //+------------------------------------------------------------------+ // Hammer Pattern bool IsHammer(double &open[], double &high[], double &low[], double &close[], double &patternATR[], int index) { if (index < 0) return false; // Ensure the index is valid // Calculate the body size (absolute difference between close and open) double body = MathAbs(close[index] - open[index]); // Check if the body is small relative to ATR (less than 30% of ATR) if (body >= 0.3 * patternATR[index]) return false; // Calculate wick lengths double upperWick = high[index] - MathMax(open[index], close[index]); double lowerWick = MathMin(open[index], close[index]) - low[index]; // Hammer conditions: long lower wick (2x body), small upper wick (≤0.5x body) if (lowerWick >= 2 * body && upperWick <= 0.5 * body) return true; return false; } // Shooting Star Pattern bool IsShootingStar(double &open[], double &high[], double &low[], double &close[], double &patternATR[], int index) { if (index < 0) return false; // Ensure the index is valid // Calculate the body size (absolute difference between close and open) double body = MathAbs(close[index] - open[index]); // Check if the body is small relative to ATR (less than 30% of ATR) if (body >= 0.3 * patternATR[index]) return false; // Calculate wick lengths double upperWick = high[index] - MathMax(open[index], close[index]); double lowerWick = MathMin(open[index], close[index]) - low[index]; // Shooting Star conditions: long upper wick (2x body), small lower wick (≤0.5x body) if (upperWick >= 2 * body && lowerWick <= 0.5 * body) return true; return false; } //+------------------------------------------------------------------+ //| How to Expand the Library | //+------------------------------------------------------------------+ // To add more patterns: // 1. Create a new function, e.g., IsDoji, IsEngulfing, etc. // 2. Use the same inputs: open[], high[], low[], close[], patternATR[], index // 3. Define the pattern’s conditions (e.g., for Doji, check if open ≈ close) // 4. Return true if the pattern matches, false otherwise // 5. For multi-candle patterns, adjust the index check (e.g., index < 1 for 2 candles) // 6. Use patternATR to adapt to volatility (optional) // 7. Add comments to explain your logic #endif //+------------------------------------------------------------------+
现在,让我们继续开发一个指标,该指标将演示如何应用我们刚刚创建的头文件。我决定将其命名为锤子线&射击之星指标,因为它将利用我们的库来检测这两种K线形态,并在图表上将它们可视化。这将提供一个实际的例子,展示我们的可复用函数如何在真实的交易场景中实现。通过在指标的开头包含该库,我们可以立即访问K线形态识别函数,在此情境下即 IsHammer 和 IsShootingStar。这种模块化设计使指标能够专注于收集和处理市场数据,同时将形态评估逻辑委托给库,从而确保一致性并简化维护工作。
在初始化阶段(OnInit),指标会设置其缓冲区和图表属性,包括定义两个用于可视化表示检测到的形态的箭头绘图。它还会创建一个ATR句柄,用于获取库函数所需的市场波动率数据。在计算阶段(OnCalculate),指标会检索价格数据和ATR值,然后遍历价格序列。在每次迭代中,它会调用库函数来检查特定的K线是否满足锤子线(买入信号)或射击之星(卖出信号)的标准。根据结果,相应的缓冲区会被填入应绘制箭头价格水平的数据。
此外,该指标的设计支持未来的扩展。如果库中集成了更多的形态识别函数,您可以轻松地添加更多的缓冲区。这种灵活的方法鼓励了对形态库的扩展,同时保持了核心指标逻辑与形态检测算法之间的清晰分离。如果您想获得更多的编码经验,可以使用附件库中的函数来构建更多的缓冲区。
//+------------------------------------------------------------------+ //| Hammer&ShootingStar.mq5 | //| Copyright 2025, Metaquotes Ltd | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Metaquotes Ltd" #property link "https://www.mql5.com/" #property version "1.00" #property indicator_chart_window //--- Include the library #include <infinity_candlestick pattern.mqh> //--- Indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_color1 0x0000FF #property indicator_label1 "Sell " #property indicator_type2 DRAW_ARROW #property indicator_color2 0xFF0000 #property indicator_label2 "Buy " //--- Indicator buffers and variables double Buffer1[]; double Buffer2[]; double Open[]; double High[]; double Low[]; double Close[]; double atr[]; int atrHandle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_ARROW, 242); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_ARROW, 241); // Create ATR handle atrHandle = iATR(_Symbol, _Period, 14); if (atrHandle == INVALID_HANDLE) { Print("Failed to create ATR handle"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { // Copy price data and ATR if (CopyOpen(Symbol(), PERIOD_CURRENT, 0, rates_total, Open) <= 0) return(rates_total); ArraySetAsSeries(Open, true); if (CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if (CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if (CopyClose(Symbol(), PERIOD_CURRENT, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if (CopyBuffer(atrHandle, 0, 0, rates_total, atr) <= 0) return(rates_total); ArraySetAsSeries(atr, true); ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); // Main loop for (int i = rates_total-2; i >= 0; i--) { // Sell Supply (Shooting Star) if (IsShootingStar(Open, High, Low, Close, atr, i)) Buffer1[i] = High[i]; // Arrow at high else Buffer1[i] = EMPTY_VALUE; // Buy Supply (Hammer) if (IsHammer(Open, High, Low, Close, atr, i)) Buffer2[i] = Low[i]; // Arrow at low else Buffer2[i] = EMPTY_VALUE; } return(rates_total); }
测试
在所有内容成功集成后,我能够在 MetaTrader 5 图表上运行锤子线&射击之星指标,并观察到了出色的结果。该指标有效地识别并高亮显示了K线形态,证明了我们的库在真实市场条件下的准确性和实用性。

Volatility 75 (1s) Index.0,5 : 锤子线&射击之星测试
结论
本次讨论内容广泛,但它将作为最有价值和最常被回顾的参考和学习主题之一。随着算法的到位,我们解决了手动扫描形态的问题。现在这个过程可以完全自动化,并且无需图表上的视觉指标,管理您的策略变得前所未有的简单。该算法通过处理所有计算(包括ATR值)来确保准确性,使过程既高效又精确。
我们涵盖了广泛的概念和技术,这些对于编程K线形态和构建多缓冲区指标非常有用。虽然本次讨论主要聚焦于K线形态,但我们引入了一种分析和利用它们的算法化方法,这使得它对于希望自动化其交易策略的初学者尤其有用。请记住,K线形态产生的信号可能需要额外的过滤器才能成为可靠的交易信号。如果您希望增强K线形态产生的信号或添加更高级的功能,代码库文档是一个极好的资源。
我很乐意在评论区看到您分享使用附件代码所取得的成果。如果时间允许,我将重新探讨这个主题,在我们已取得成就的基础上进行构建,并探索进一步的进展。| 文件名 | 说明 |
|---|---|
| infinity_candlestick_pattern.mqh | 一个包含用于最流行K线形态的布尔函数集合的头文件,可在其他项目中直接调用。 |
| Hammer&ShootingStar.mq5, | 一个集成了 infinity_candlestick_pattern.mqh 库的示例指标。 |
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17525
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
使用MQL5经济日历进行交易(第七部分):基于资源型新闻事件分析的策略测试准备
MQL5中表格模型的实现:应用MVC概念
重构经典策略(第十四部分):高胜率交易形态
开发多币种 EA 交易(第 23 部分):整理自动项目优化阶段的输送机(二)























您的想法是什么?您的名字是什么? 你的名字 是什么?
Tác giả:克莱蒙斯-本杰明