作者:老余捞鱼
原创不易,转载请标明出处及原作者。

写在前面的话:本文详细介绍了如何利用 Python 和 EODHD API 来自动化检测股票交易市场中的蜡烛图形态。我会解释作为交易策略重要组成部分蜡烛图的基本概念,并说明这些数据如何在图表上展现形态,最后还会举例进行展示说明。
为了探讨今天这个主题,我们需要先从基础讲起。多数人都熟悉交易图表,它通常由绿红柱形图组成线形图,虽简单却蕴含大量数据信息。一根蜡烛代表一个数据区间,如一小时图表,包含开盘价、最高价、最低价和收盘价四个关键信息,简称 OHLC 数据。若收盘价高于开盘价,蜡烛图为绿色;反之则为红色(美股中的绿涨红跌和我们A股是反的,需要大家注意这个细节)。下图更清晰地说明了这一概念。

举例说明:

您可能会注意到蜡烛序列中出现的特定形态,即蜡烛图形态。交易策略通常就是根据这些形态制定的。
一、使用 EODHD API 中的标准普尔 500 指数进行演示
第一步是获取分析所需的数据集,为此我们将使用官方的 EODHD API Python 库。下面提供的代码片段可获取 720 小时(30 天)的数据。
官方库地址:https://eodhd.com/financial-apis/python-financial-libraries-and-code-samples/
import config as cfg
from eodhd import APIClient
api = APIClient(cfg.API_KEY)
def get_ohlc_data():
df = api.get_historical_data("AAPL.US", "1h", results=(24*30))
return df
if __name__ == "__main__":
df = get_ohlc_data()
print(df)

我们先来看一个简单明了的蜡烛图形态,即锤子或锤子形态。这种形态是一种看涨反转指标,通常出现在下跌趋势的末端。它的特点是开盘价和收盘价在顶部几乎完全相同,加上较长的低位灯芯,其长度至少是空头主体的两倍。
为说明这种形态,现将蜡烛图的修改版介绍如下:

总之,锤子形态是看涨转折的信号,被视为温和的反转形态,表明市场方向可能从下行转向上行。
我们开发了一些代码,以便在数据集中找出这些蜡烛。
import pandas as pd
import config as cfg
from eodhd import APIClient
api = APIClient(cfg.API_KEY)
def candle_hammer(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["high"] - df["low"]) > 3 * (df["open"] - df["close"]))
& (((df["close"] - df["low"]) / (0.001 + df["high"] - df["low"])) > 0.6)
& (((df["open"] - df["low"]) / (0.001 + df["high"] - df["low"])) > 0.6)
)
def get_ohlc_data():
df = api.get_historical_data("AAPL.US", "1h", results=(24*30))
return df
if __name__ == "__main__":
df = get_ohlc_data()
df["hammer"] = candle_hammer(df)
print(df)
print(df[df["hammer"] == True])

为了便于演示,我们将数据集显示两次。初始数据集显示锤形蜡烛的识别。随后的数据集只显示检测到锤子形态的情况。在过去的 720 个小时中,锤子形态出现了 67 次。
在此基础上,自然会出现一种相关的蜡烛图形态–倒锤子形态。作为锤子的对应形态,它在图形上类似于一个倒转的锤子。它仍然是一个看涨信号,通常出现在下跌趋势的末端。
def candle_inverted_hammer(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Inverted Hammer ("Weak - Continuation - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["high"] - df["low"]) > 3 * (df["open"] - df["close"]))
& ((df["high"] - df["close"]) / (0.001 + df["high"] - df["low"]) > 0.6)
& ((df["high"] - df["open"]) / (0.001 + df["high"] - df["low"]) > 0.6)
)

二、烛台形态
蜡烛图形态基本上可分为两类:
- 看涨或看跌
- 犹豫不决/中性、弱、可靠或强
下面简要介绍一下流行的蜡烛图形态:
2.1 犹豫不决/中性(Indecision / Neutral)
- Doji
2.2 弱(Weak)
- 锤子(看涨)
- 倒锤(看涨)
- Shooting Star (看跌)
2.3 可靠(Reliable)
- Hanging Man (看跌)
- Three Line Strike (看涨)
- Two Black Gapping (看跌)
- Abandoned Baby (看涨)
- Morning Doji Star (看涨)
- Evening Doji Star (看跌)
2.4 强(Strong)
- Three White Soldiers (三个白兵)(看涨)
- Three Black Crows(三只黑鸦) (看跌)
- Morning Star (看涨)
- Evening Star (看跌)
我们将这些烛台形态编码成 Python 函数,并使用 Numpy 来处理一些更复杂的形态。
import numpy as np
def candle_hammer(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["high"] - df["low"]) > 3 * (df["open"] - df["close"]))
& (((df["close"] - df["low"]) / (0.001 + df["high"] - df["low"])) > 0.6)
& (((df["open"] - df["low"]) / (0.001 + df["high"] - df["low"])) > 0.6)
)
def candle_inverted_hammer(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Inverted Hammer ("Weak - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["high"] - df["low"]) > 3 * (df["open"] - df["close"]))
& ((df["high"] - df["close"]) / (0.001 + df["high"] - df["low"]) > 0.6)
& ((df["high"] - df["open"]) / (0.001 + df["high"] - df["low"]) > 0.6)
)
def candle_shooting_star(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Shooting Star ("Weak - Reversal - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["open"].shift(1) < df["close"].shift(1)) & (df["close"].shift(1) < df["open"]))
& (df["high"] - np.maximum(df["open"], df["close"]) >= (abs(df["open"] - df["close"]) * 3))
& ((np.minimum(df["close"], df["open"]) - df["low"]) <= abs(df["open"] - df["close"]))
)
def candle_hanging_man(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Hanging Man ("Weak - Reliable - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["high"] - df["low"]) > (4 * (df["open"] - df["close"])))
& (((df["close"] - df["low"]) / (0.001 + df["high"] - df["low"])) >= 0.75)
& (((df["open"] - df["low"]) / (0.001 + df["high"] - df["low"])) >= 0.75)
& (df["high"].shift(1) < df["open"])
& (df["high"].shift(2) < df["open"])
)
def candle_three_white_soldiers(df: pd.DataFrame = None) -> pd.Series:
"""*** Candlestick Detected: Three White Soldiers ("Strong - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["open"] > df["open"].shift(1)) & (df["open"] < df["close"].shift(1)))
& (df["close"] > df["high"].shift(1))
& (df["high"] - np.maximum(df["open"], df["close"]) < (abs(df["open"] - df["close"])))
& ((df["open"].shift(1) > df["open"].shift(2)) & (df["open"].shift(1) < df["close"].shift(2)))
& (df["close"].shift(1) > df["high"].shift(2))
& (
df["high"].shift(1) - np.maximum(df["open"].shift(1), df["close"].shift(1))
< (abs(df["open"].shift(1) - df["close"].shift(1)))
)
)
def candle_three_black_crows(df: pd.DataFrame = None) -> pd.Series:
"""* Candlestick Detected: Three Black Crows ("Strong - Reversal - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["open"] < df["open"].shift(1)) & (df["open"] > df["close"].shift(1)))
& (df["close"] < df["low"].shift(1))
& (df["low"] - np.maximum(df["open"], df["close"]) < (abs(df["open"] - df["close"])))
& ((df["open"].shift(1) < df["open"].shift(2)) & (df["open"].shift(1) > df["close"].shift(2)))
& (df["close"].shift(1) < df["low"].shift(2))
& (
df["low"].shift(1) - np.maximum(df["open"].shift(1), df["close"].shift(1))
< (abs(df["open"].shift(1) - df["close"].shift(1)))
)
)
def candle_doji(df: pd.DataFrame = None) -> pd.Series:
"""! Candlestick Detected: Doji ("Indecision / Neutral")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((abs(df["close"] - df["open"]) / (df["high"] - df["low"])) < 0.1)
& ((df["high"] - np.maximum(df["close"], df["open"])) > (3 * abs(df["close"] - df["open"])))
& ((np.minimum(df["close"], df["open"]) - df["low"]) > (3 * abs(df["close"] - df["open"])))
)
def candle_three_line_strike(df: pd.DataFrame = None) -> pd.Series:
"""** Candlestick Detected: Three Line Strike ("Reliable - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["open"].shift(1) < df["open"].shift(2)) & (df["open"].shift(1) > df["close"].shift(2)))
& (df["close"].shift(1) < df["low"].shift(2))
& (
df["low"].shift(1) - np.maximum(df["open"].shift(1), df["close"].shift(1))
< (abs(df["open"].shift(1) - df["close"].shift(1)))
)
& ((df["open"].shift(2) < df["open"].shift(3)) & (df["open"].shift(2) > df["close"].shift(3)))
& (df["close"].shift(2) < df["low"].shift(3))
& (
df["low"].shift(2) - np.maximum(df["open"].shift(2), df["close"].shift(2))
< (abs(df["open"].shift(2) - df["close"].shift(2)))
)
& ((df["open"] < df["low"].shift(1)) & (df["close"] > df["high"].shift(3)))
)
def candle_two_black_gapping(df: pd.DataFrame = None) -> pd.Series:
"""*** Candlestick Detected: Two Black Gapping ("Reliable - Reversal - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
((df["open"] < df["open"].shift(1)) & (df["open"] > df["close"].shift(1)))
& (df["close"] < df["low"].shift(1))
& (df["low"] - np.maximum(df["open"], df["close"]) < (abs(df["open"] - df["close"])))
& (df["high"].shift(1) < df["low"].shift(2))
)
def candle_morning_star(df: pd.DataFrame = None) -> pd.Series:
"""*** Candlestick Detected: Morning Star ("Strong - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
(np.maximum(df["open"].shift(1), df["close"].shift(1)) < df["close"].shift(2)) & (df["close"].shift(2) < df["open"].shift(2))
) & ((df["close"] > df["open"]) & (df["open"] > np.maximum(df["open"].shift(1), df["close"].shift(1))))
def candle_evening_star(df: pd.DataFrame = None) -> np.ndarray:
"""*** Candlestick Detected: Evening Star ("Strong - Reversal - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
(np.minimum(df["open"].shift(1), df["close"].shift(1)) > df["close"].shift(2)) & (df["close"].shift(2) > df["open"].shift(2))
) & ((df["close"] < df["open"]) & (df["open"] < np.minimum(df["open"].shift(1), df["close"].shift(1))))
def candle_abandoned_baby(df: pd.DataFrame = None) -> pd.Series:
"""** Candlestick Detected: Abandoned Baby ("Reliable - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (
(df["open"] < df["close"])
& (df["high"].shift(1) < df["low"])
& (df["open"].shift(2) > df["close"].shift(2))
& (df["high"].shift(1) < df["low"].shift(2))
)
def candle_morning_doji_star(df: pd.DataFrame = None) -> pd.Series:
"""** Candlestick Detected: Morning Doji Star ("Reliable - Reversal - Bullish Pattern - Up")"""
# Fill NaN values with 0
df = df.fillna(0)
return (df["close"].shift(2) < df["open"].shift(2)) & (
abs(df["close"].shift(2) - df["open"].shift(2)) / (df["high"].shift(2) - df["low"].shift(2)) >= 0.7
) & (abs(df["close"].shift(1) - df["open"].shift(1)) / (df["high"].shift(1) - df["low"].shift(1)) < 0.1) & (
df["close"] > df["open"]
) & (
abs(df["close"] - df["open"]) / (df["high"] - df["low"]) >= 0.7
) & (
df["close"].shift(2) > df["close"].shift(1)
) & (
df["close"].shift(2) > df["open"].shift(1)
) & (
df["close"].shift(1) < df["open"]
) & (
df["open"].shift(1) < df["open"]
) & (
df["close"] > df["close"].shift(2)
) & (
(df["high"].shift(1) - np.maximum(df["close"].shift(1), df["open"].shift(1)))
> (3 * abs(df["close"].shift(1) - df["open"].shift(1)))
) & (
np.minimum(df["close"].shift(1), df["open"].shift(1)) - df["low"].shift(1)
) > (
3 * abs(df["close"].shift(1) - df["open"].shift(1))
)
def candle_evening_doji_star(df: pd.DataFrame = None) -> pd.Series:
"""** Candlestick Detected: Evening Doji Star ("Reliable - Reversal - Bearish Pattern - Down")"""
# Fill NaN values with 0
df = df.fillna(0)
return (df["close"].shift(2) > df["open"].shift(2)) & (
abs(df["close"].shift(2) - df["open"].shift(2)) / (df["high"].shift(2) - df["low"].shift(2)) >= 0.7
) & (abs(df["close"].shift(1) - df["open"].shift(1)) / (df["high"].shift(1) - df["low"].shift(1)) < 0.1) & (
df["close"] < df["open"]
) & (
abs(df["close"] - df["open"]) / (df["high"] - df["low"]) >= 0.7
) & (
df["close"].shift(2) < df["close"].shift(1)
) & (
df["close"].shift(2) < df["open"].shift(1)
) & (
df["close"].shift(1) > df["open"]
) & (
df["open"].shift(1) > df["open"]
) & (
df["close"] < df["close"].shift(2)
) & (
(df["high"].shift(1) - np.maximum(df["close"].shift(1), df["open"].shift(1)))
> (3 * abs(df["close"].shift(1) - df["open"].shift(1)))
) & (
np.minimum(df["close"].shift(1), df["open"].shift(1)) - df["low"].shift(1)
) > (
3 * abs(df["close"].shift(1) - df["open"].shift(1))
)
探索我们的数据集,看看能否识别出任何强势蜡烛图形态…
if __name__ == "__main__":
df = get_ohlc_data()
df["three_white_soldiers"] = candle_three_white_soldiers(df)
df["three_black_crows"] = candle_three_black_crows(df)
df["morning_star"] = candle_morning_star(df)
df["evening_star"] = candle_evening_star(df)
print(df[(df["three_white_soldiers"] == True) | (df["three_black_crows"] == True) | (df["morning_star"] == True) | (df["evening_star"] == True)])

事实上,在过去的 30 天里,强势形态已经出现了很多次。从分享的数据中,我们可以看出蜡烛图形态出现的时间和类型。一个有趣的练习是查看标准普尔 500 指数小时图中的这些特定时间段,并尝试找出这些形态。
观点回顾
请大家记住,没有任何一种策略能保证交易成功。与其他交易方法一样,基于蜡烛图形态的策略的可行性受市场动态、流动性和波动性的影响。因此,建议交易者将这些策略纳入更全面、更多样化的交易方法中,并通过其他分析和工具对其进行强化,以获得更全面的视角。
- 蜡烛图形态是交易分析的关键工具:文章强调了蜡烛图形态在交易策略中的作用,并通过实际的 Python 代码示例展示了如何识别这些形态。
- 自动化分析提高了交易效率:通过使用 Python 和 EODHD API,交易者可以自动化地分析大量历史数据,快速识别潜在的交易机会。
- 蜡烛图形态的多样性和复杂性:文章列举了多种蜡烛图形态,并根据它们的可靠性和强度对它们进行了分类,从而为交易者提供了一个全面的参考框架。
- 综合交易策略的重要性:作者指出,虽然蜡烛图形态提供了有价值的市场信号,但交易者应该将它们与其他技术分析和基本面分析相结合,以形成一个更为健全的交易策略。
- 持续学习和适应市场变化:文章鼓励交易者持续学习新的分析技巧和工具,以适应不断变化的市场环境。
感谢您阅读到最后。如果对文中的内容有任何疑问,请给我留言,必复。
本文内容仅仅是技术探讨和学习,并不构成任何投资建议。
转发请注明原作者和出处。
Be First to Comment