不会量化?用 Python 玩转 TA-Lib,几行代码搞定技术指标
量化分析进阶(二):Python TA-Lib RSI 与布林带玩法
talib除了计算指标外,还可以计算K线形态,比如我们平时在观察K线图的时候 ,或多或少都有接触一些K线的形态,然后利用单根或多根K线组合判断市场心理。
常用到的形态:吞没形态 (Engulfing):比如阳线包住前阴线,十字星 (Doji):趋势反转信号,锤子线 / 上吊线:底部或顶部反转
简单的量化策略思路:先用指标或K线形态生成初步信号,再加上成交量或波动率条件过滤假信号,做组合信号,减少噪音,可以增加准确率。然后回测,调参数,优化。
这篇文章我们来说下 吞没形态 / 锤子线 / 上吊线
吞没如字面意思一样,就是后面一根K线把前一根K线实体全部吞没了。
import talibengulfing = talib.CDLENGULFING(open_, high_, low_, close_)current_signal = engulfing[-1]输出
100 → 当前是看多吞没(可以理解为原本是空方占优 → 多方突然全面反击)-100 → 当前是看空吞没 (可以理解为原本多头占优 → 空头突然反击成功)0 → 当前不是吞没形态即使我们获得了吞没状态,可是它不保证:一定反转趋势、一定能走多远、一定适合交易。还需要结合其他来判断,比如支撑位、压力位、成交量、下跌末端、连续下跌、连续上涨等。
我们随便取一份本地数据,计算输出来看下效果,这样方便理解。

代码
import talibimport pandas as pdimport matplotlib.pyplot as pltfrom sqlalchemy.orm import Sessionfrom datetime import datefrom db_stock import StockHistory, SessionLocal#解决中文乱码plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]plt.rcParams["axes.unicode_minus"] = False#从数据库中提取股票历史数据def get_stock_history( db: Session, stock_id: int, begin_date: date, end_date: date): records = ( db.query(StockHistory) .filter(StockHistory.stock_id == stock_id) .filter(StockHistory.date >= begin_date) .filter(StockHistory.date <= end_date) .order_by(StockHistory.date) .all() ) return records#把数据库记录转成DataFramedef records_to_dataframe(records): data = [] for r in records: data.append({ "date": r.date, "open": r.open_price, "high": r.high_price, "low": r.low_price, "close": r.close_price, "volume": r.volume }) df = pd.DataFrame(data) df.set_index("date", inplace=True) return df#创建数据库sessionsession = SessionLocal()#设置参数stock_id = 600519begin_date = date(2025, 1, 1)end_date = date(2025, 12, 31)#从数据库提取数据records = get_stock_history( session, stock_id, begin_date, end_date)#转成DataFrame处理df = records_to_dataframe(records)close = df["close"].valueshigh = df["high"].valueslow = df["low"].valuesopen = df["open"].valueslast_date = df.index[-1]last_price = df["close"].iloc[-1]engulfing = talib.CDLENGULFING(open, high, low, close)df["CDLENGULFING"] = engulfingbullish_idx = df["CDLENGULFING"] > 0 # 看多吞没bearish_idx = df["CDLENGULFING"] < 0 # 看空吞没plt.figure(figsize=(14, 6))# ① 画价格plt.plot( df.index, df["close"], label="收盘价", color="black", linewidth=1)# ② 看多吞没(▲)plt.scatter( df.index[bullish_idx], df["close"][bullish_idx], marker="^", s=100, label="看多吞没形态", zorder=3)# ③ 看空吞没(▼)plt.scatter( df.index[bearish_idx], df["close"][bearish_idx], marker="v", s=100, label="看空吞没形态", zorder=3)# 当前K线plt.scatter( last_date, last_price, s=200, edgecolors="red", facecolors="none", linewidths=2, label="当前K线")plt.title(f"{stock_id} 吞没形态(历史 + 当前)识别结果")plt.xlabel("Date")plt.ylabel("Price")plt.legend()plt.grid(alpha=0.3)plt.tight_layout()plt.show(block=True)锤子线的理解就是空头一度把价格砸下去,但最终被多头“硬拉回来”,而上吊线刚好反过来。
他们其实和位置配合起来才更有意义些比如锤子线必须出现在:下跌末端、回调低点、支撑位附近,就是个不错的信号,可是如果它出现在:高位、连续上涨中、突破后那这样的信号就需要再琢磨琢磨。
很多比较成熟的策略是锤子线第二天阳线确认。
同样的,我们来看实现一下锤子线 / 上吊线的效果,把他结合到上面的图里来如下:

代码
import talibimport pandas as pdimport matplotlib.pyplot as pltfrom sqlalchemy.orm import Sessionfrom datetime import datefrom db_stock import StockHistory, SessionLocal#解决中文乱码plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"]plt.rcParams["axes.unicode_minus"] = False#从数据库中提取股票历史数据def get_stock_history( db: Session, stock_id: int, begin_date: date, end_date: date): records = ( db.query(StockHistory) .filter(StockHistory.stock_id == stock_id) .filter(StockHistory.date >= begin_date) .filter(StockHistory.date <= end_date) .order_by(StockHistory.date) .all() ) return records#把数据库记录转成DataFramedef records_to_dataframe(records): data = [] for r in records: data.append({ "date": r.date, "open": r.open_price, "high": r.high_price, "low": r.low_price, "close": r.close_price, "volume": r.volume }) df = pd.DataFrame(data) df.set_index("date", inplace=True) return df#创建数据库sessionsession = SessionLocal()#设置参数stock_id = 600519begin_date = date(2025, 1, 1)end_date = date(2025, 12, 31)#从数据库提取数据records = get_stock_history( session, stock_id, begin_date, end_date)#转成DataFrame处理df = records_to_dataframe(records)close = df["close"].valueshigh = df["high"].valueslow = df["low"].valuesopen = df["open"].valueslast_date = df.index[-1]last_price = df["close"].iloc[-1]engulfing = talib.CDLENGULFING(open, high, low, close)df["CDLENGULFING"] = engulfingbullish_idx = df["CDLENGULFING"] > 0 # 看多吞没bearish_idx = df["CDLENGULFING"] < 0 # 看空吞没hammer = talib.CDLHAMMER(open, high, low, close)df["CDLHAMMER"] = hammerhammer_idx = df["CDLHAMMER"] > 0 # 锤子线(偏多)hanging = talib.CDLHANGINGMAN(open, high, low, close)df["CDLHANGINGMAN"] = hanginghanging_idx = df["CDLHANGINGMAN"] < 0plt.figure(figsize=(14, 6))# ① 画价格plt.plot( df.index, df["close"], label="收盘价", color="black", linewidth=1)# ② 看多吞没(▲)plt.scatter( df.index[bullish_idx], df["close"][bullish_idx], marker="^", s=100, label="看多吞没形态", zorder=3)# ③ 看空吞没(▼)plt.scatter( df.index[bearish_idx], df["close"][bearish_idx], marker="v", s=100, label="看空吞没形态", zorder=3)# 当前K线plt.scatter( last_date, last_price, s=200, edgecolors="red", facecolors="none", linewidths=2, label="当前K线")# ④ 锤子线(●)plt.scatter( df.index[hammer_idx], df["close"][hammer_idx], marker="o", s=80, label="锤子线形态", zorder=3)# ⑤ 上吊线(×)plt.scatter( df.index[hanging_idx], df["close"][hanging_idx], marker="x", s=120, label="上吊线形态", zorder=3)plt.title(f"{stock_id} 吞没形态 + 锤子线 + 上吊线 识别结果")plt.xlabel("Date")plt.ylabel("Price")plt.legend()plt.grid(alpha=0.3)plt.tight_layout()plt.show(block=True)我们最后来总结下上面说到的形态,他们正解的解读方式:
吞没:是真正的“多空摊牌”锤子线:低位出现才有意义上吊线:高位出现才有风险提示意义
你很可能也注意到了一个现象,很多“上吊线”出现后,并不会立刻下跌, 这是因为上吊线本身不是卖点,它是 “高位松动的第一声警告”
交易有句老话:锤子,是低位有人接,上吊,是高位有人跑。
不过还是要提醒,股市无定论,一定要要结合后续K线确认。
除了上面形态外,talib还可以计算下列其他K线的形态,功能非常齐全。
名称 英文函数 信号说明十字星 CDLDOJI 趋势反转或 indecision锤子线 CDLHAMMER 底部反转信号上吊线 CDLHANGINGMAN 顶部反转信号反向锤子 CDLINVERTEDHAMMER 底部反转信号射击之星 CDLSHOOTINGSTAR 顶部反转信号长腿十字 CDLLONGLEGGEDDOJI 不确定走势名称 英文函数 信号说明吞没 CDLENGULFING 阳线吞阴线 → 买,阴线吞阳线 → 卖穿头破脚 CDLPIERCING 底部反转信号阴阳反并 CDLMORNINGSTAR / CDLEVENINGSTAR 顶/底部反转名称 英文函数 信号说明三只乌鸦 CDL3BLACKCROWS 顶部连续下跌 → 卖出三兵 CDL3WHITESOLDIERS 底部连续上涨 → 买入夹击线 CDL3INSIDE 顶部或底部反转三线打击 CDL3LINESTRIKE 反转信号CDLDOJISTAR → 十字星组合CDLCOUNTERATTACK → 反击线CDLUPSIDEGAP2CROWS → 缺口向上两乌鸦CDLDOWNGAP3METHODS → 下跌缺口三法最后需要强调的是:本文所介绍的形态,仅用于理解市场结构与多空行为,并不构成任何买卖建议。金融市场变化无常,没有永远有效的形态,也不存在放之四海而皆准的规律。任何技术工具,都需要在长期统计和风险控制下用。