前2篇文章写了 底分型、双重底、头肩底、圆弧底, 这里继续往下写一写V形底、三重底。
前2篇文章链接:
如何量化识别股票底部形态(一)
如何量化识别股票底部形态(二)
V形底,又称“尖底”,是股价急跌后急跌后快速反弹,形成的“V”字形态。其核心特征:
V形底是“恐慌性反转”形态,多由重大利好(如政策刺激、行业拐点)触发。左侧是恐慌盘杀跌,右侧是聪明资金快速抄底,反转速度快、幅度大,但风险也高(容易二次探底)。
3、写一个例子演示
import numpy as np
import pandas as pd
import akshare as ak
def find_v_bottom(df, min_drop=0.15, min_rise=0.15, volume_ratio=2.0, window=10):
v_bottoms = []
for i in range(window, len(df) - window):
current_low = df['最低'].iloc[i]
current_date = df.index[i]
# 左侧:window天内跌幅超过min_drop
left_df = df.iloc[i - window:i]
left_drop = (left_df['开盘'].iloc[0] - current_low) / left_df['开盘'].iloc[0]
# 右侧:window天内涨幅超过min_rise
right_df = df.iloc[i + 1:i + 1 + window]
if len(right_df) < window:
continue
right_rise = (right_df['收盘'].iloc[-1] - current_low) / current_low
# 条件1:左侧跌幅+右侧涨幅达标
if (left_drop < min_drop) or (right_rise < min_rise):
continue
# 条件2:最低点成交量放大(较前5日平均)
current_volume = df['成交量'].iloc[i]
avg_volume_5 = df['成交量'].iloc[i - 5:i].mean()
if current_volume < avg_volume_5 * volume_ratio:
continue
# 条件3:左侧和右侧均线斜率陡峭(5日均线)
left_df['MA5'] = left_df['收盘'].rolling(5).mean()
right_df['MA5'] = right_df['收盘'].rolling(5).mean()
# 左侧MA5斜率(负,且绝对值大)
left_x = np.arange(len(left_df))
left_ma5 = left_df['MA5'].dropna()
if len(left_ma5) < 5:
continue
left_slope = np.polyfit(left_x[-len(left_ma5):], left_ma5, 1)[0]
# 右侧MA5斜率(正,且大)
right_x = np.arange(len(right_df))
right_ma5 = right_df['MA5'].dropna()
if len(right_ma5) < 5:
continue
right_slope = np.polyfit(right_x[:len(right_ma5)], right_ma5, 1)[0]
if (left_slope > -0.5) or (right_slope < 0.5): # 斜率阈值需根据股票调整
continue
v_bottoms.append({
'V底日期': current_date,
'最低价': current_low,
'左侧跌幅': f"{left_drop:.2%}",
'右侧涨幅': f"{right_rise:.2%}",
'成交量倍数': current_volume / avg_volume_5
})
return v_bottoms
# 获取股票数据(以平安银行000001为例)
def get_stock_data(symbol="000001", start_date="20250101", end_date="20250921"):
df = ak.stock_zh_a_hist(symbol=symbol, period="daily",
start_date=start_date, end_date=end_date, adjust="qfq")
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)
return df[['开盘', '收盘', '最高', '最低', '成交量']]
df_ningde = get_stock_data(symbol="300750", start_date="20220101", end_date="20251231")
v_bottoms = find_v_bottom(df_ningde)
if v_bottoms:
for vb in v_bottoms:
print(f"V形底确认:\n日期:{vb['V底日期']}(最低价:{vb['最低价']:.2f})")
print(f"左侧跌幅:{vb['左侧跌幅']},右侧涨幅:{vb['右侧涨幅']}")
print(f"成交量倍数:{vb['成交量倍数']:.2f}倍\n")
else:
print("未识别出符合条件的V形底形态")
三重底是W底的变体,由三个低点和两个反弹高点构成,形似“三个连在一起的碗”。其核心特征:
三重底是“多重探底”形态,比W底更扎实:三个低点意味着空方三次打压均未成功,多方力量占据绝对优势。突破后上涨幅度通常大于W底,目标价为“颈线位+低点到颈线位距离”。
3、写一个例子演示
import numpy as np
import pandas as pd
import akshare as ak
def find_triple_bottom(df, min_distance=15, price_tolerance=0.05, breakout_ratio=0.03):
# 第一步:找出局部低点
df['局部低点'] = False
for i in range(5, len(df) - 5):
if df['最低'].iloc[i] == df['最低'].iloc[i - 5:i + 5].min():
df.at[df.index[i], '局部低点'] = True
local_lows = df[df['局部低点']]
triple_bottoms = []
# 第二步:匹配三个连续低点
for i in range(len(local_lows) - 2):
low1 = local_lows.iloc[i]
low2 = local_lows.iloc[i + 1]
low3 = local_lows.iloc[i + 2]
# 条件1:三个低点间隔足够
days_12 = (low2.name - low1.name).days
days_23 = (low3.name - low2.name).days
if (days_12 < min_distance) or (days_23 < min_distance):
continue
# 条件2:三个低点价格相近
price_diff_12 = abs(low2['最低'] - low1['最低']) / low1['最低']
price_diff_23 = abs(low3['最低'] - low2['最低']) / low2['最低']
if (price_diff_12 > price_tolerance) or (price_diff_23 > price_tolerance):
continue
# 条件3:计算两个颈线位(low1-low2之间的高点,low2-low3之间的高点)
neckline1 = df[(df.index > low1.name) & (df.index < low2.name)]['最高'].max()
neckline2 = df[(df.index > low2.name) & (df.index < low3.name)]['最高'].max()
# 颈线位需平行(差异不超过5%)
neckline_diff = abs(neckline2 - neckline1) / neckline1
if neckline_diff > 0.05:
continue
# 条件4:突破第二个颈线位
after_low3 = df[df.index > low3.name]
if len(after_low3) == 0:
continue
breakout_close = neckline2 * (1 + breakout_ratio)
breakout_signals = after_low3[after_low3['收盘'] > breakout_close]
if len(breakout_signals) > 0:
triple_bottoms.append({
'第一个低点': low1.name,
'第二个低点': low2.name,
'第三个低点': low3.name,
'颈线位1': neckline1,
'颈线位2': neckline2,
'突破日期': breakout_signals.index[0]
})
return triple_bottoms
def get_stock_data(symbol="000001", start_date="20250101", end_date="20250921"):
df = ak.stock_zh_a_hist(symbol=symbol, period="daily",
start_date=start_date, end_date=end_date, adjust="qfq")
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)
return df[['开盘', '收盘', '最高', '最低', '成交量']]
df_byd = get_stock_data(symbol="002594", start_date="20220101", end_date="20250921")
triple_bottoms = find_triple_bottom(df_byd)
if triple_bottoms:
for tb in triple_bottoms:
print(
f"三重底确认:\n三个低点日期:{tb['第一个低点'].date()}、{tb['第二个低点'].date()}、{tb['第三个低点'].date()}")
print(f"颈线位1:{tb['颈线位1']:.2f},颈线位2:{tb['颈线位2']:.2f}")
print(f"突破日期:{tb['突破日期'].date()}\n")
else:
print("未识别出符合条件的股票")如果我的分享对你投资有所帮助,不吝啬给个点赞关注呗。