用 Python 自动检测交易图形态的实用指南请查收
作者:老余捞鱼
原创不易,转载请标明出处及原作者。
写在前面的话:
本文详细介绍了如何利用 Python 和 EODHD API 来自动化检测股票交易市场中的蜡烛图形态。我会解释作为交易策略重要组成部分蜡烛图的基本概念,并说明这些数据如何在图表上展现形态,最后还会举例进行展示说明。
为了探讨今天这个主题,我们需要先从基础讲起。多数人都熟悉交易图表,它通常由绿红柱形图组成线形图,虽简单却蕴含大量数据信息。一根蜡烛代表一个数据区间,如一小时图表,包含开盘价、最高价、最低价和收盘价四个关键信息,简称 OHLC 数据。若收盘价高于开盘价,蜡烛图为绿色;反之则为红色(美股中的绿涨红跌和我们A股是反的,需要大家注意这个细节)。下图更清晰地说明了这一概念。
举例说明:
您可能会注意到蜡烛序列中出现的特定形态,即蜡烛图形态。交易策略通常就是根据这些形态制定的。
一、使用 EODHD API 中的标准普尔 500 指数进行演示
第一步是获取分析所需的数据集,为此我们将使用官方的 EODHD API Python 库。下面提供的代码片段可获取 720 小时(30 天)的数据。
import config as cfg
from eodhd import APIClientapi = APIClient(cfg.API_KEY)def get_ohlc_data():df = api.get_historical_data("AAPL.US", "1h", results=(24*30))return dfif __name__ == "__main__":df = get_ohlc_data()print(df)
我们先来看一个简单明了的蜡烛图形态,即锤子或锤子形态。这种形态是一种看涨反转指标,通常出现在下跌趋势的末端。它的特点是开盘价和收盘价在顶部几乎完全相同,加上较长的低位灯芯,其长度至少是空头主体的两倍。
为说明这种形态,现将蜡烛图的修改版介绍如下:
总之,锤子形态是看涨转折的信号,被视为温和的反转形态,表明市场方向可能从下行转向上行。
我们开发了一些代码,以便在数据集中找出这些蜡烛。
import pandas as pd
import config as cfg
from eodhd import APIClientapi = 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 0df = 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 dfif __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 0df = 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 npdef candle_hammer(df: pd.DataFrame = None) -> pd.Series:"""* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up"""# Fill NaN values with 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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 0df = 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,交易者可以自动化地分析大量历史数据,快速识别潜在的交易机会。
- 蜡烛图形态的多样性和复杂性:文章列举了多种蜡烛图形态,并根据它们的可靠性和强度对它们进行了分类,从而为交易者提供了一个全面的参考框架。
- 综合交易策略的重要性:作者指出,虽然蜡烛图形态提供了有价值的市场信号,但交易者应该将它们与其他技术分析和基本面分析相结合,以形成一个更为健全的交易策略。
- 持续学习和适应市场变化:文章鼓励交易者持续学习新的分析技巧和工具,以适应不断变化的市场环境。
感谢您阅读到最后。如果对文中的内容有任何疑问,请给我留言,必复。
本文内容仅仅是技术探讨和学习,并不构成任何投资建议。
转发请注明原作者和出处。