主题切换
19.1 涨跌停板策略
中国 A 股市场最显著的特征之一就是涨跌停板制度(Price Limit)。这一机制对市场流动性、价格发现过程以及交易策略设计都有深远影响。理解涨跌停板制度下的市场微观结构是 A 股量化策略开发的基础。
涨跌停板制度概述
制度规则
A 股主板(含中小板)的涨跌停板限制为
涨跌停板的价格计算以前一交易日的收盘价为基准:
$$P_{\text{涨停}} = P_{\text{前收}} \times (1 + \text{limit}) \quad \text{(四舍五入到分)}$$ $$P_{\text{跌停}} = P_{\text{前收}} \times (1 - \text{limit}) \quad \text{(四舍五入到分)}$$
名词解释:封板
"封板"是指股票价格触及涨停(或跌停)后,买(卖)盘大量堆积,导致价格被"封锁"在涨跌停板价格上。封板期间的成交只能以涨跌停价格进行,且只有与封板方向相同的订单才能成交。
对市场微观结构的影响
流动性中断(Liquidity Disruption):当股票触及涨跌停板时,正常的连续竞价被中断。买方(涨停时)或卖方(跌停时)的流动性急剧收缩,订单在封板价格上排队等待成交。
价格发现延迟(Price Discovery Delay):涨跌停板人为地阻止了价格在一个交易日内的充分调整。原本应该在当日完成的价格变动,被迫延迟到随后的交易日。这导致了:
- 波动率溢出(Volatility Spillover):被压抑的价格变动能量在后续交易日释放,导致异于常模的波动率。
- 收益率自相关:涨停板的次日往往有正向收益(动量效应),跌停板的次日往往有负向收益(反转效应可能更强)。
磁吸效应(Magnet Effect):当价格接近涨跌停线时,交易者担心价格触及涨跌停后无法交易,可能加速买入/卖出,推动价格加速触碰涨跌停板。
涨停板排队策略
涨停板排队策略是 A 股最具特色的量化策略之一。其核心逻辑是:在股票涨停封板后,判断该封板的"质量"(封板强度),对于高质量封板的股票排队买入,博取次日的高开溢价。
封板强度量化
封板强度的核心量化指标:
封单量/成交额比(封成比):
$$\text{封成比} = \frac{\text{涨停价买一挂单量}}{\text{当日累计成交量}}$$
封成比越高,说明买盘意愿越强,封板质量越高。经验上封成比 > 1.0 的封板具有较好的持续性。
撤单率:在封板期间,部分挂出的买单会被撤掉(尤其是主力资金测试市场反应的试探性挂单)。撤单率反映了封板资金的坚定程度。
$$\text{撤单率} = \frac{\text{封板期间累计撤单量}}{\text{封板期间累计挂单量} + \text{封板期间累计撤单量}}$$
撤单率过高(>30%)通常意味着封板资金信心不足,属于"假封板"。
封板时间:封板时间越早(如开盘即封板),说明买方力量越强,次日溢价可能性越大。
开板次数:封板后又被打开的次数。多次开板表明多空分歧大,封板质量差。
封板时价格位置:封板发生在股价的相对低位(如长期横盘后的突破)还是高位(如连续涨停后),对后续走势有截然不同的含义。
信号生成逻辑
此处有展示代码展开 ▼
python
import numpy as np
import pandas as pd
class LimitUpSignalGenerator:
"""涨停板信号生成器"""
def __init__(self, tick_data: pd.DataFrame, daily_data: pd.DataFrame):
"""
Parameters
----------
tick_data : pd.DataFrame
tick级别数据,含买卖盘口
daily_data : pd.DataFrame
日频数据,含开盘价、收盘价、成交量等
"""
self.tick_data = tick_data
self.daily_data = daily_data
def identify_limit_up_events(self, limit_pct: float = 0.10) -> pd.DataFrame:
"""识别涨停事件"""
daily = self.daily_data.copy()
# 计算涨停价格
daily['limit_up_price'] = (daily['pre_close'] * (1 + limit_pct)).round(2)
daily['limit_down_price'] = (daily['pre_close'] * (1 - limit_pct)).round(2)
# 识别涨停日:收盘价 == 涨停价且成交量 > 0
daily['is_limit_up'] = (daily['close'] >= daily['limit_up_price'] - 0.001) & \
(daily['volume'] > 0)
return daily[['is_limit_up', 'limit_up_price']]
def compute_seal_strength(self, stock_code: str, date: str) -> dict:
"""计算封板强度指标"""
ticks = self.tick_data[
(self.tick_data['code'] == stock_code) &
(self.tick_data['date'] == date)
].copy()
if len(ticks) == 0:
return {}
# 找到封板区间(价格 == 涨停价 的 tick)
limit_up_price = self.daily_data.loc[
(self.daily_data['code'] == stock_code) &
(self.daily_data['date'] == date), 'limit_up_price'
].iloc[0]
sealed_ticks = ticks[abs(ticks['price'] - limit_up_price) < 0.01]
if len(sealed_ticks) == 0:
return {'is_sealed': False}
# 封板开始时间
seal_start = sealed_ticks['time'].min()
seal_duration = sealed_ticks['time'].max() - sealed_ticks['time'].min()
# 封单量(买一挂单量)
avg_bid_volume = sealed_ticks['bid_volume_1'].mean()
# 累计成交量
total_volume = ticks['volume'].sum()
# 封成比
seal_volume_ratio = avg_bid_volume / total_volume if total_volume > 0 else 0
# 撤单分析:比较挂单量的变化
bid_changes = sealed_ticks['bid_volume_1'].diff()
cancellations = abs(bid_changes[bid_changes < 0].sum())
total_bid = sealed_ticks['bid_volume_1'].sum()
cancel_rate = cancellations / (total_bid + cancellations) if (total_bid + cancellations) > 0 else 0
# 开板检测:价格曾离开涨停价又回来
seal_breaches = 0
prev_sealed = False
for _, row in ticks.iterrows():
is_at_limit = abs(row['price'] - limit_up_price) < 0.01
if prev_sealed and not is_at_limit:
seal_breaches += 1
prev_sealed = is_at_limit
return {
'is_sealed': True,
'seal_start_time': seal_start,
'seal_duration': seal_duration,
'seal_volume_ratio': seal_volume_ratio,
'cancel_rate': cancel_rate,
'seal_breaches': seal_breaches,
'avg_bid_volume': avg_bid_volume
}
def generate_signal(self, stock_code: str, date: str) -> dict:
"""生成涨停板交易信号"""
strength = self.compute_seal_strength(stock_code, date)
if not strength.get('is_sealed'):
return {'action': 'NONE', 'reason': '未涨停'}
score = 0
# 封成比评分(0-40分)
if strength['seal_volume_ratio'] > 2.0:
score += 40
elif strength['seal_volume_ratio'] > 1.0:
score += 30
elif strength['seal_volume_ratio'] > 0.5:
score += 15
# 撤单率评分(0-25分)
if strength['cancel_rate'] < 0.10:
score += 25
elif strength['cancel_rate'] < 0.20:
score += 15
elif strength['cancel_rate'] < 0.30:
score += 5
# 开板次数评分(0-20分)
if strength['seal_breaches'] == 0:
score += 20
elif strength['seal_breaches'] == 1:
score += 10
# 封板时间评分(0-15分,越早越好)
seal_hour = strength['seal_start_time'].hour
if seal_hour < 10:
score += 15
elif seal_hour < 11:
score += 10
elif seal_hour < 14:
score += 5
# 决策
if score >= 70:
action = 'BUY'
confidence = 'HIGH'
elif score >= 50:
action = 'BUY'
confidence = 'MEDIUM'
else:
action = 'NONE'
confidence = 'LOW'
return {
'action': action,
'confidence': confidence,
'score': score,
'strength_metrics': strength,
'expected_next_day_return': self._estimate_next_day_return(score)
}
def _estimate_next_day_return(self, score: float) -> float:
"""
估计次日溢价。基于历史数据拟合评分到次日收益的映射。
此处使用简化的经验公式。
"""
if score >= 70:
return 0.025 # 2.5% 预期次日收益
elif score >= 50:
return 0.012
else:
return -0.005点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:类 `LimitUpSignalGenerator`(涨停板信号生成器)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
策略逻辑
涨停板排队的典型策略逻辑:
- 盘中监控:实时扫描触及涨停板的股票。
- 封板质量评估:计算封成比、撤单率、开板次数等指标。
- 选择性排队:只在高评分封板上挂涨停价买单。注意:挂单时间越早,在涨停价队列中位置越靠前,成交概率越高。
- 次日卖出:默认次日开盘卖出。如果次日继续涨停(一字板),可以继续持有。
- 回撤控制:如果次日开盘大跌(如低开超过 2%),立即止损。
跌停板避险与逆向策略
跌停板不仅影响多头持仓的风险管理,也创造了逆向投资的机会。
跌停板避险
持有个股跌停时,持仓可能无法在当日卖出止损,导致亏损跨夜放大。应对策略:
- 预警减仓:在股票接近跌停(如跌幅达到 8%)但尚未封板时提前卖出,避免跌停后无法平仓。
- 跌停板计价:在策略回测中,跌停日的平仓价格不应取收盘价或中间价,而应以跌停板价格计算,且应考虑成交概率。
跌停板逆向策略
跌停板逆向策略的逻辑是:市场在恐慌性抛售中可能过度反应,跌停板作为一种极端的卖出信号,可能标志着价格见底。
入场条件:
- 股票连续跌停(通常 2-3 个跌停板后)
- 跌停板被打开(成交量放大,有大资金接盘)
- 基本面没有实质性恶化(排除财务造假等实质性利空)
此处有展示代码展开 ▼
python
def limit_down_reversal_signal(daily_data: pd.DataFrame,
consecutive_limit_downs: int = 2) -> pd.Series:
"""
跌停板逆向策略信号
逻辑:连续跌停后首次开板,可能是恐慌情绪的逆转点
"""
daily = daily_data.copy()
# 计算跌停价
daily['limit_down'] = daily['pre_close'] * 0.90
# 识别跌停日
daily['is_limit_down'] = daily['close'] <= daily['limit_down'] + 0.001
# 连续跌停计数
daily['consecutive_ld'] = daily.groupby('code')['is_limit_down'].transform(
lambda x: x * (x.groupby((x != x.shift()).cumsum()).cumcount() + 1)
)
# 信号条件:
# 1. 前一日连续跌停 >= consecutive_limit_downs
# 2. 当日不再跌停(开板)
# 3. 当日成交量放大(相对前5日均值的1.5倍)
prev_consecutive = daily.groupby('code')['consecutive_ld'].shift(1)
avg_vol_5d = daily.groupby('code')['volume'].transform(
lambda x: x.rolling(5).mean()
)
signal = (prev_consecutive >= consecutive_limit_downs) & \
(~daily['is_limit_down']) & \
(daily['volume'] > avg_vol_5d * 1.5) & \
(daily['close'] > daily['open']) # 当日收阳
return signal.astype(int)点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `limit_down_reversal_signal`(跌停板逆向策略信号)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
涨跌停板数据的时间序列特征
研究涨跌停板的时间序列特征,有助于理解市场情绪和风险状况:
此处有展示代码展开 ▼
python
class LimitBoardTimeSeriesAnalysis:
"""涨跌停板时间序列分析"""
def __init__(self, daily_data: pd.DataFrame):
self.daily = daily_data
def daily_limit_up_ratio(self) -> pd.Series:
"""每日涨停股票占比"""
limit_up_counts = self.daily[self.daily['is_limit_up']].groupby('date').size()
total_counts = self.daily.groupby('date').size()
return (limit_up_counts / total_counts).fillna(0)
def limit_up_concentration(self) -> pd.Series:
"""
涨停板集中度指数:涨停股票集中在少数行业还是分散在各行业
高集中度通常对应主题驱动行情,低集中度对应普涨行情
"""
limit_up_stocks = self.daily[self.daily['is_limit_up']]
# 使用赫芬达尔指数(HHI)衡量行业集中度
hhi = limit_up_stocks.groupby(['date', 'sector']).size() \
.groupby('date').apply(
lambda x: ((x / x.sum()) ** 2).sum()
)
return hhi
def limit_board_market_sentiment(self) -> pd.DataFrame:
"""
涨跌停板市场情绪指标
计算涨停数、跌停数、涨跌停比,作为市场情绪的量化代理
"""
daily_stats = pd.DataFrame()
daily_stats['limit_up_count'] = self.daily[self.daily['is_limit_up']].groupby('date').size()
daily_stats['limit_down_count'] = self.daily[self.daily['is_limit_down']].groupby('date').size()
daily_stats['up_down_ratio'] = daily_stats['limit_up_count'] / \
daily_stats['limit_down_count'].replace(0, np.nan)
# 情绪指标Z-score
daily_stats['sentiment_z'] = (daily_stats['up_down_ratio'] -
daily_stats['up_down_ratio'].rolling(60).mean()) / \
daily_stats['up_down_ratio'].rolling(60).std()
return daily_stats点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:类 `LimitBoardTimeSeriesAnalysis`(涨跌停板时间序列分析)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
涨跌停板策略是 A 股量化中最具本土特色的策略类别。随着注册制改革深化和市场成熟度提升,涨停板的频率和溢价水平在长期趋势中可能下降,但其作为市场微观结构的核心特征仍将持续发挥作用。掌握涨停板策略的分析框架,不仅有助于开发具体的交易策略,也有助于理解 A 股市场的整体运行逻辑。