2. 数据获取与处理:A股数据源选择、碳中和概念股池构建、财务数据获取、数据清洗与预处理
各位同学,欢迎来到实战环节的第一站。
做量化投资,说白了就是和数据打交道。数据质量不行,后面模型再花哨也是白搭。我见过太多人把精力全花在策略上,结果数据源一换,回测结果直接翻车。嗯,咱们今天就把地基打牢。
2.1 A股数据源选择:Tushare vs AkShare
国内做A股量化,绕不开两个库:Tushare和AkShare。我个人两个都用过,各有各的脾气。
| 对比维度 | Tushare | AkShare |
|---|---|---|
| 数据全面性 | 非常全面,财务、行情、概念股都有 | 覆盖广,但部分数据源不稳定 |
| 使用门槛 | 需要注册、实名、获取token | pip安装即用,无需注册 |
| 稳定性 | 高,付费用户有保障 | 中等,免费接口偶尔断流 |
| 适合场景 | 正式策略、生产环境 | 快速原型、学习研究 |
我的建议: 学习阶段先用AkShare,上手快。做正式策略时,建议上Tushare Pro。我在项目中遇到过AkShare某天突然拿不到数据,排查了半天发现是对方网站改版了。从那以后,生产环境我都用Tushare。
2.2 碳中和概念股池构建
概念股池怎么来?最直接的办法是用Tushare的概念股分类接口。碳中和相关的概念标签包括:
- 新能源(光伏、风电、储能)
- 新能源汽车产业链
- 节能减排(环保设备、碳交易)
- 绿色电力(水电、核电)
代码实现如下:
import tushare as ts
# 初始化,记得替换成你自己的token
pro = ts.pro_api('your_token_here')
# 获取概念股列表
concept = pro.concept()
print(concept[concept['name'].str.contains('碳中和|新能源|光伏|风电')])
# 获取具体概念成分股
carbon_neutral = pro.concept_detail(id='你的概念ID')
stock_list = carbon_neutral['concept_name'].tolist()
print(f'共获取到 {len(stock_list)} 只碳中和概念股')
避坑指南: 我曾经发现Tushare的概念股列表更新有延迟。新纳入的概念股可能要等2-3个交易日才能查到。建议每周手动核对一次,或者用多个数据源交叉验证。
2.3 财务数据获取
有了股票池,下一步就是拉财务数据。量化轮动策略最常用的财务指标包括:
- 营业收入(季度/年度)
- 净利润
- ROE(净资产收益率)
- 毛利率
- 资产负债率
获取代码示例:
# 获取单只股票的财务数据
df = pro.fina_indicator(ts_code='600519.SH',
start_date='20230101',
end_date='20231231',
fields='ts_code,end_date,roe,profit_dedt')
# 批量获取整个股票池
def get_financial_data(stock_list):
all_data = []
for code in stock_list:
try:
data = pro.fina_indicator(ts_code=code,
start_date='20230101',
fields='ts_code,end_date,roe,profit_dedt')
all_data.append(data)
except Exception as e:
print(f'{code} 数据获取失败: {e}')
return pd.concat(all_data, ignore_index=True)
financial_df = get_financial_data(stock_list)
你想想看,如果手动去一个个股票查财务数据,几百只股票得查到什么时候?用代码批量拉,几分钟搞定。
2.4 数据清洗与预处理
数据拿到手,千万别直接用。原始数据里什么妖魔鬼怪都有。我总结了一套清洗流程:
- 缺失值处理:财务数据常有空值,尤其是新上市的公司。我习惯用行业均值填充,或者直接剔除缺失超过30%的股票。
- 异常值检测:比如ROE突然飙到200%,明显是数据错误。用3σ原则或者箱线图来过滤。
- 数据类型转换:日期字段转datetime,金额字段转float。
- 去重:同一个股票同一天可能有重复记录,保留最新一条。
import pandas as pd
import numpy as np
def clean_financial_data(df):
# 1. 缺失值处理
df = df.dropna(thresh=len(df.columns) * 0.7) # 删除缺失超过30%的行
# 2. 行业均值填充
df['roe'] = df.groupby('industry')['roe'].transform(
lambda x: x.fillna(x.mean()))
# 3. 异常值过滤(3σ原则)
for col in ['roe', 'profit_dedt']:
mean = df[col].mean()
std = df[col].std()
df = df[(df[col] >= mean - 3*std) & (df[col] <= mean + 3*std)]
# 4. 日期格式统一
df['end_date'] = pd.to_datetime(df['end_date'])
return df
clean_df = clean_financial_data(financial_df)
print(f'清洗前: {len(financial_df)} 条, 清洗后: {len(clean_df)} 条')
核心要点: 数据清洗不是一次性的活。每次跑策略前都要做一遍,因为数据源会更新,异常值也会变。我习惯把清洗逻辑封装成函数,每次调用就行。
2.5 本章知识体系总览
下面这张图,把咱们这章的核心逻辑串起来了:
这张图把咱们这章的内容串起来了。从数据源选择开始,到概念股池构建,再到财务数据获取,最后经过清洗得到干净的数据集。每一步都有坑,但每一步也都有解法。
个人经验: 数据清洗这一步,我建议你多花点时间。我早期做策略时,就因为没处理好异常值,导致回测收益率虚高20%。后来排查了三天才发现是某只股票的数据录入错误。嗯,从那以后,我对数据清洗再也不敢马虎了。
好了,数据准备这块就讲到这里。记住一句话:好数据是好策略的起点。下一章咱们会基于这些数据,开始构建真正的轮动策略。