在 A 股的短线交易中,一段行情的启动往往伴随着“量价齐升”。当一只股票经过一段时间的盘整后,突然某一天成交量激增,并且价格突破了近期的前期高点,这通常是主力资金强力介入的信号。
今天,我们将把这种“放量突破平台”,严谨地翻译成计算机能够听懂的数学逻辑,并用 Pandas 瞬间扫描出所有符合条件的交易日。
人类语言中的“放量”和“突破”是非常模糊的。在代码的世界里,我们需要给出绝对清晰的定义:
避坑指南(极度重要):
在计算“过去 20 天最高价”时,绝对不能把今天包含进去,否则就犯了严重的“未来函数”错误。我们必须依靠上一节课学到的 shift(1) 将时间窗口严格卡在“昨天”。
我们将使用 Pandas 强大的 rolling() 滑动窗口函数。同样,我们坚决不使用广泛的错误包裹,让逻辑异常直接暴露。
import akshare as ak
import pandas as pd
def calculate_breakout_signals(symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
""" 计算股票的放量突破信号 """
print(f"正在拉取 {symbol} 的行情数据进行突破信号计算...")
df = ak.stock_zh_a_hist(symbol=symbol, period="daily", start_date=start_date, end_date=end_date, adjust="qfq")
if df is None or df.empty:
raise ValueError(f"数据获取异常!请核查股票代码:{symbol}")
df = df.rename(columns={'日期': 'date', '收盘': 'close', '最高': 'high', '成交量': 'volume'})
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
# ---------------- 核心信号逻辑 ----------------
# 1. 计算价格突破基准线:过去 20 个交易日的最高价
# shift(1) 确保从昨天开始往前推,rolling(20).max() 求极大值
df['past_20d_high'] = df['high'].shift(1).rolling(window=20).max()
# 2. 计算放量基准线:过去 5 个交易日的平均成交量
df['past_5d_vol_mean'] = df['volume'].shift(1).rolling(window=5).mean()
# 3. 生成布尔条件信号
condition_price = df['close'] > df['past_20d_high']
condition_volume = df['volume'] > (df['past_5d_vol_mean'] * 2)
# 4. 信号合并
df['buy_signal'] = condition_price & condition_volume
return df.dropna()
# === 测试环节 ===
if __name__ == "__main__":
# 以 浪潮信息 (000977) 为例,寻找其在 2023 年的爆发点
df_breakout = calculate_breakout_signals("000977", "20230101", "20231231")
signal_days = df_breakout[df_breakout['buy_signal'] == True]
print(f"信号触发日:\n{signal_days[['close', 'volume', 'buy_signal']]}").max() 或 .mean()。& 而非 and。在 Pandas 世界里,比较两列数据必须使用位运算符,这能极大提升扫描万只股票时的运算速度。本期思考题(供网站测试用):
如果我们要增加一个过滤条件:“突破当天的收盘价,不能是跌停板(假设跌停板定义为当日跌幅超过 9.8%)”,你应该如何结合第二专栏中的 pct_change() 函数,将新条件加入到 buy_signal 生成逻辑中?
第一阶段的基础底座已经打完!你现在已经具备了开发单只股票策略框架的能力。 下一篇,你是希望了解 事件驱动型回测和向量化回测的底层机制区别(理论深度),还是想直接学习 如何在策略中加入真实交易手续费的计算(实战精度)?