🔴
入学要求
💯
能力测试
🛣️
课程安排
🕹️
研究资源

第29讲:证券池选择 (Universe Selection)

💡

查看全集:💎Quantopia量化分析56讲

一、什么是股票池?

1.1 基本概念

股票池(Universe)是量化策略交易的标的资产集合。就像厨师需要选择优质食材一样,量化交易者需要精心挑选股票池。常见的股票池类型包括:

1.2 重要性说明

(演进过程示例):

2008年金融危机期间,仅包含金融股的策略普遍失效,而全市场策略表现更好。这说明:

策略收益=策略逻辑收益+股票池选择收益 策略收益 = 策略逻辑收益 + 股票池选择收益 

1.3 数据获取实践

import yfinance as yf
import pandas as pd

# 获取多只股票数据示例
tickers = ['AAPL', 'MSFT', 'GOOG']
start_date = '2020-01-01'
end_date = '2023-01-01'

data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
print(data.head())

# 计算日收益率
returns = data.pct_change().dropna()
print(returns.describe())

小练习:尝试添加TSLA股票数据,比较其收益率波动性

二、构建股票池的关键要素

2.1 行业分布分析

使用yfinance获取行业信息(示例):

# 获取单只股票信息
aapl = yf.Ticker("AAPL")
print(aapl.info['sector'])  # 输出行业分类

# 行业分布可视化
sector_counts = pd.Series({
    'Technology': 150,
    'Financials': 120,
    'Healthcare': 80
})
sector_counts.plot(kind='pie', autopct='%1.1f%%')

2.2 流动性筛选

常用流动性指标计算公式:

日流动金额=收盘价×成交量 日流动金额 = 收盘价 \times 成交量 

20日移动平均流动性筛选:

def liquidity_screen(data, window=20, threshold=1e6):
    volume = data['Volume']
    close = data['Close']
    dollar_volume = (volume * close).rolling(window).mean()
    return dollar_volume > threshold

2.3 换手率控制

换手率计算公式:

日换手率=新入选股票数+被剔除股票数股票池总数量×100% 日换手率 = \frac{新入选股票数 + 被剔除股票数}{股票池总数量} \times 100\% 

对比实验

# 原始股票池与平滑后对比
original_turnover = [...]  # 原始换手率数据
smoothed_turnover = [...]   # 使用移动平均后的数据

pd.DataFrame({
    '原始': original_turnover,
    '平滑': smoothed_turnover
}).plot(title='换手率对比')

三、高级筛选技巧

3.1 多条件复合筛选

def build_universe(data):
    # 条件1:市值大于100亿
    market_cap = data['MarketCap'] > 10e9

    # 条件2:过去20日平均成交量大于100万股
    volume_avg = data['Volume'].rolling(20).mean() > 1e6

    # 条件3:股价高于5美元
    price_condition = data['Close'] > 5

    return market_cap & volume_avg & price_condition

3.2 动态调整机制

使用3个月再平衡周期示例:

from dateutil.relativedelta import relativedelta

current_date = pd.to_datetime('2022-01-01')
rebalance_dates = [current_date + relativedelta(months=3*i) for i in range(4)]
print(rebalance_dates)

小练习:尝试修改再平衡周期为1个月,观察股票池变动频率

四、最佳实践案例:QTradableStocksUS

4.1 筛选标准

指标阈值作用
市值>5亿美元排除小盘股风险
日均成交额>250万美元(200日)确保流动性
股价>5美元降低交易摩擦成本

4.2 实现逻辑

def QTradableStocksUS(data):
    # 市值筛选
    market_cap = data['MarketCap'] > 5e8

    # 流动性筛选
    dollar_volume = (data['Volume'] * data['Close']).rolling(200).median() > 2.5e6

    # 价格筛选
    price_filter = data['Close'] > 5

    # 其他条件(示例)
    primary_share = data['IsPrimary']  # 假设有是否为优先股字段
    no_adr = ~data['IsADR']            # 排除美国存托凭证

    return market_cap & dollar_volume & price_filter & primary_share & no_adr

五、常见误区与解决方案

5.1 过拟合问题

错误做法:在历史数据上不断调整参数直到表现完美

正确方法

# 使用时间序列交叉验证
from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)
for train_idx, test_idx in tscv.split(data):
    train_data = data.iloc[train_idx]
    test_data = data.iloc[test_idx]
    # 执行回测...

5.2 幸存者偏差

解决方案:使用历史时点数据进行回测,包括已退市股票

示例数据集结构

Date       | Ticker | Price | Exists
2020-01-02 | ABC    | 50.2  | True
2021-05-15 | ABC    | NaN   | False  # 标记退市

六、课后练习

  1. 使用yfinance构建一个包含10只科技股的股票池
  1. 计算该股票池过去一年的行业分布变化
  1. 实现一个简单的换手率控制模块(阈值设为5%)
  1. 对比不同市值门槛(50亿 vs 100亿)对股票池数量的影响
# 练习模板代码
def tech_sector_universe():
    tech_tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']
    data = yf.download(tech_tickers, period='1y')
    # 添加你的筛选逻辑...
    return selected_stocks

(注:本教程示例代码需要配合实际市场数据使用,部分筛选条件需要根据具体数据字段调整实现)

附:练习合集