1. 课程导入与数据准备

在讨论“板块上涨家数”和“市场宽度”之前,需要先明确一个前提:这两个指标都不是行情软件里现成的单一数字,而是由“板块成分股列表”和“每只成分股的日行情”两部分数据加工出来的派生指标。数据准备做得是否扎实,直接决定了后续宽度曲线、宽度背离、板块轮动判断是否可信。本章不急于计算指标,而是把分析目标、数据源选择、成分股与行情获取、清洗校验这条链路走通,最终得到一个可以直接进入计算环节的干净数据集。

一、先定义清楚要回答的问题

“板块上涨家数”通常指某一板块内当日收盘价高于前一交易日收盘价的成分股数量;“市场宽度”则是一个更宽的概念,常用上涨家数占比、涨跌家数比、站上某条均线的成分股比例等来刻画。两者共同回答的核心问题是:指数的涨跌,是由少数权重股拉动的,还是由多数个股共同推动的?

因此本课程的分析目标可以拆成三层:第一层是单日横截面,即某板块当日上涨家数、下跌家数、平盘家数及上涨占比;第二层是时间序列,即把上述统计量按交易日滚动,形成宽度曲线;第三层是结构对比,即把板块宽度与板块指数走势、与全市场宽度做对照,识别“指数涨但宽度缩”这类背离信号。目标一旦明确,数据需求就随之确定:需要板块成分股清单、每只成分股的日线收盘价,以及交易日历用于对齐。

分析目标决定了数据粒度。若只做单日板块强弱排序,日频收盘价足够;若要观察宽度拐点与指数背离,则必须保证时间序列连续、停牌与新股处理规则统一,否则宽度曲线会出现虚假跳变。

二、常用数据源及其取舍

实际工作中常见三类数据源,各有适用场景:

  • 行情软件导出(如同花顺、通达信、东方财富的板块成分与日线导出):上手快、字段直观,适合快速验证想法;缺点是批量导出繁琐、复权口径与字段命名不统一,长期维护成本高。
  • 交易所与官方披露数据:权威性最好,适合做成分股归属与停复牌的最终校验;但接口分散、更新节奏固定,不适合高频迭代。
  • Python 财经接口(如 AkShare、Tushare 等):可编程批量拉取,便于把“成分股—日行情—交易日历”串成流水线,是本课程推荐的主路径;需注意接口的积分权限、频率限制与字段变更。

本课程采用“Python 接口为主、行情软件抽样核对为辅”的策略:批量数据走接口,关键日期抽几只股票与软件对照,既保证效率又保留可验证性。

三、成分股列表与日行情获取

以 AkShare 为例,板块成分股可通过板块名称接口获取,日行情通过历史行情接口按股票代码逐只拉取。下面是一段可直接改造使用的示例代码,参数与返回结果均为教学示例,实际运行时以接口当前返回为准。

import akshare as ak
import pandas as pd

# 1) 获取板块成分股(示例:某行业板块)
cons = ak.stock_board_industry_cons_em(symbol="半导体")
codes = cons["代码"].tolist()

# 2) 逐只拉取日线,只保留需要的字段
frames = []
for code in codes:
    df = ak.stock_zh_a_hist(
        symbol=code, period="daily",
        start_date="20240101", end_date="20240630",
        adjust="qfq"          # 前复权,保证价格序列可比
    )
    df = df[["日期", "收盘", "成交量"]].copy()
    df["代码"] = code
    frames.append(df)

raw = pd.concat(frames, ignore_index=True)
raw["日期"] = pd.to_datetime(raw["日期"])
print(raw.shape, raw["代码"].nunique())

这里有两个容易被忽略的细节。其一是复权口径:计算“今日收盘是否高于昨日收盘”时,若中途发生除权除息而未复权,价格会出现向下跳空,被误判为下跌。统一使用前复权可以规避,但要注意前复权序列会随最新除权事件整体变化,因此每次重算都应重新拉取,而不是长期缓存旧复权价。其二是字段对齐:不同接口对“日期”“收盘”的命名不同,建议在拼接前统一重命名为固定列名,避免后续合并出错。

四、清洗与校验:让数据可计算

原始拼接结果通常存在缺失交易日、停牌空值、重复行和新股上市初期数据不足等问题。清洗的目标不是“删得干净”,而是“规则统一、可追溯”。建议按以下顺序处理:

  1. 去重:按“代码 + 日期”去重,保留最后一条,防止重复拉取造成家数虚增。
  2. 对齐交易日历:以交易日历为基准做透视,缺失的“代码—日期”组合说明当日停牌或无数据,先标记为缺失而非直接删除。
  3. 停牌处理:停牌日不参与“上涨/下跌”计数,也不计入分母,否则会人为压低上涨占比。可在透视后统计每日有效交易股票数,作为宽度计算的分母。
  4. 新股与退市处理:上市不足一定天数(如 20 个交易日)的股票在计算“站上均线比例”类宽度时剔除,避免样本不足导致比例失真。
  5. 异常值核查:单日涨跌幅超过合理阈值(如 ±21%,考虑不同板块涨跌幅限制)的记录应回查,确认是复权错误还是数据源错误。

清洗完成后,把长表透视为“日期 × 代码”的收盘价矩阵,再逐列做 pct_change() 得到日收益率矩阵,就可以按行统计上涨家数。这一步是后续所有宽度指标的共同入口,务必保证矩阵的行是交易日、列是成分股、单元格是可比价格。

板块宽度分析的数据准备链路 目标 → 数据源 → 成分股与行情 → 清洗校验 → 可计算矩阵 分析目标 单日上涨家数 宽度时间序列 指数与宽度背离 数据源选择 行情软件导出 交易所官方数据 Python 财经接口 成分股 + 日行情 板块成分清单 前复权收盘价 交易日历对齐 清洗与校验 去重 / 停牌标记 新股剔除 / 异常核查 复权口径统一 可计算矩阵:日期 × 代码(前复权收盘价) 日期 600A 600B 600C 600D 06-03 12.40 8.15 停牌 21.30 06-04 12.86 8.02 停牌 21.05 示例数据:06-04 有效样本 3 只,上涨 1 只 → 上涨占比 33.3% 进入计算 上涨 / 下跌 / 平盘 上涨家数占比 宽度滚动曲线 与指数对照

上图把本章的链路压缩成一条可检查的路径:目标决定数据源,数据源产出成分股与行情,清洗校验把原始数据变成“日期 × 代码”的矩阵,矩阵再进入家数与占比计算。图中 06-04 这一行的示例说明了一个关键规则:停牌股票不计入分母,当日有效样本为 3 只,上涨 1 只,上涨占比为 33.3%,而不是按 4 只成分股计算出的 25%。这个分母口径必须在整条时间序列上保持一致,否则宽度曲线会在停牌密集期出现系统性偏差。

五、交付一份可复用的数据检查清单

为了让数据准备可复现,建议在每次更新数据后固定核对以下几项,形成一份简短的检查记录:

检查项判断标准不通过时的处理
成分股数量与板块最新披露数量一致重新拉取成分清单,核对调仓日期
日期覆盖起止日期内交易日无整段缺失补齐交易日历,定位缺失区间
复权口径全部为前复权且同一拉取批次整批重拉,禁止混用新旧复权价
停牌标记缺失值已标记,未混入涨跌计数透视后统计每日有效样本数
异常涨跌幅超出阈值记录已逐条回查修正数据源或剔除并记录原因

完成以上步骤后,你手里应当有一份按交易日排列、列名为股票代码、单元格为前复权收盘价的矩阵,以及一份每日有效样本数序列。前者用于计算涨跌方向,后者用于确定宽度指标的分母。数据准备阶段多花的时间,会在后续宽度背离判断中直接转化为结论的可靠性——因为宽度分析最怕的不是指标公式复杂,而是分母悄悄变了却没人发现。