第二章:数据源准备——获取行情数据

做量化交易,数据就是你的弹药库。

我见过太多人,策略写得天花乱坠,结果一跑回测,数据源就有问题。嗯,那感觉就像你精心准备了满汉全席,结果发现米是馊的。今天我们就来搞定情绪量化最核心的四个数据源:涨跌家数、成交量、换手率、北向资金。

2.1 涨跌家数——市场情绪的体温计

涨跌家数,说白了就是今天有多少股票在涨,多少在跌。这个数据简单粗暴,但极其有效。

我个人习惯用这个指标来判断市场是否出现极端情绪。比如某天上涨家数不到500家,那基本就是情绪冰点了。反过来,上涨家数超过3000家,那就是沸点区域。

核心逻辑: 涨跌家数比 = 上涨家数 / (上涨家数 + 下跌家数)。比值低于0.2为冰点,高于0.8为沸点。

获取这个数据,我一般用 tushare 或者 akshare。下面是我常用的代码:

import akshare as ak
import pandas as pd

# 获取A股涨跌家数
def get_advance_decline_data():
    """
    获取全市场涨跌家数数据
    返回:DataFrame,包含日期、上涨家数、下跌家数
    """
    df = ak.stock_market_activity_baidu()
    # 只保留需要的列
    result = df[['日期', '上涨家数', '下跌家数']].copy()
    result['涨跌比'] = result['上涨家数'] / (result['上涨家数'] + result['下跌家数'])
    return result

# 调用示例
data = get_advance_decline_data()
print(data.tail())
小技巧: 我建议你同时获取沪深300成分股的涨跌家数。全市场数据噪音大,沪深300更能反映主流资金的真实情绪。

2.2 成交量——资金的真实态度

成交量不会骗人。价格可以操纵,但成交量是实打实的真金白银。

我曾经踩过一个坑:只看价格不看量,结果在缩量反弹时追了进去,第二天就被埋了。从那以后,我每次分析情绪都会先看成交量。

获取成交量数据,我推荐用 tushare 的 pro 接口:

import tushare as ts

# 初始化tushare
pro = ts.pro_api('你的token')

# 获取上证指数成交量
def get_market_volume(start_date='20240101', end_date='20241231'):
    """
    获取市场整体成交量数据
    """
    df = pro.index_daily(ts_code='000001.SH', 
                         start_date=start_date, 
                         end_date=end_date)
    # 成交量单位:手
    df['vol_ratio'] = df['vol'] / df['vol'].rolling(20).mean()
    return df[['trade_date', 'vol', 'vol_ratio']]

volume_data = get_market_volume()
print(volume_data.head())
注意: 成交量数据要结合换手率一起看。单纯看成交量绝对值没有意义,因为市场总股本在变。我习惯用「成交量/20日均量」这个比值来判断放量还是缩量。

2.3 换手率——筹码的活跃度

换手率反映的是筹码交换的活跃程度。换手率越高,说明市场分歧越大,情绪越亢奋。

你想想看,如果一只股票换手率只有0.5%,说明没人愿意买卖,市场冷清得很。如果换手率突然飙升到5%以上,那一定是有什么大事发生了。

获取全市场换手率,我一般这样处理:

def get_turnover_rate():
    """
    获取全市场平均换手率
    使用akshare获取所有A股数据,然后计算平均值
    """
    # 获取全部A股实时数据
    df = ak.stock_zh_a_spot_em()
    
    # 计算全市场平均换手率
    avg_turnover = df['换手率'].mean()
    
    # 也可以按板块分组
    sector_turnover = df.groupby('板块')['换手率'].mean()
    
    return avg_turnover, sector_turnover

avg, sector = get_turnover_rate()
print(f"全市场平均换手率: {avg:.2f}%")
print(sector)
实战经验: 我通常把换手率分成三个区间:
- 低于1%:市场冷清,情绪冰点区域
- 1%-3%:正常交易状态
- 高于3%:情绪亢奋,注意风险

2.4 北向资金——聪明钱的动向

北向资金,江湖人称「聪明钱」。这帮外资机构的信息优势和判断力,确实比大多数散户强。

我记得2020年3月,全球股市暴跌,北向资金连续流出。但到了3月底,北向突然开始连续净流入。我当时就判断,底部可能到了。果不其然,后面就是一波大反弹。

获取北向资金数据,我推荐用东方财富的接口:

def get_northbound_flow():
    """
    获取北向资金流向数据
    包含:沪股通、深股通、合计
    """
    # 使用akshare获取北向资金
    df = ak.stock_hsgt_north_net_flow_in_em()
    
    # 计算累计净流入
    df['累计净流入'] = df['净流入'].cumsum()
    
    # 计算5日均值,用于判断趋势
    df['净流入_5日均值'] = df['净流入'].rolling(5).mean()
    
    return df

north_data = get_northbound_flow()
print(north_data.tail(10))
我的习惯: 北向资金单日净流入超过100亿,或者连续3日净流入超过50亿,我都会标记为「情绪积极信号」。反之,单日净流出超过100亿,就要警惕了。

2.5 数据整合——构建情绪数据库

上面四个数据源,单独看都有价值,但整合在一起威力更大。我习惯把它们合并成一个DataFrame,方便后续分析。

def build_sentiment_database():
    """
    整合所有情绪数据源
    返回:统一的DataFrame
    """
    # 获取各数据源
    adv_dec = get_advance_decline_data()
    volume = get_market_volume()
    turnover = get_turnover_rate()
    north = get_northbound_flow()
    
    # 按日期合并
    sentiment_db = adv_dec.merge(volume, on='trade_date', how='left')
    sentiment_db = sentiment_db.merge(north, on='trade_date', how='left')
    
    # 添加换手率(日频数据)
    sentiment_db['turnover_rate'] = turnover
    
    # 数据清洗
    sentiment_db = sentiment_db.dropna()
    sentiment_db = sentiment_db.sort_values('trade_date')
    
    return sentiment_db

# 构建数据库
sentiment_data = build_sentiment_database()
print(sentiment_data.info())
避坑指南: 我曾经因为数据对齐问题,把不同频率的数据直接合并,结果回测结果完全失真。记住:涨跌家数是日频,北向资金也是日频,但换手率可以做到分钟级。合并时一定要统一时间频率。

2.6 知识体系总览

下面这张图,是我自己整理的情绪数据源框架。你可以把它当作一个检查清单,每次做情绪分析时对照着看:

市场情绪数据源框架 情绪量化数据源 涨跌家数 成交量 换手率 北向资金 上涨家数 下跌家数 涨跌比 总成交量 量比 20日均量 全市场换手率 板块换手率 换手率分位数 沪股通净流入 深股通净流入 累计净流入 四个维度相互验证,才能准确判断市场情绪处于冰点还是沸点

数据源准备好了,下一步就是清洗和特征工程。不过那是下一章的内容了。今天先把这四个数据源跑通,你可以在自己的机器上试试看。

核心要点回顾:
1. 涨跌家数:判断市场极端情绪的最直接指标
2. 成交量:结合均量看,避免被单日异常值误导
3. 换手率:反映筹码活跃度,与成交量互补
4. 北向资金:聪明钱的动向,有领先指示作用
5. 四个数据源要整合使用,单一指标容易误判

专注资料整理