数据基础设施:主流ESG评级机构对比与数据清洗实战
做量化投资的朋友都知道一句话:垃圾进,垃圾出。ESG整合策略更是如此——评级数据本身就不干净,你指望它能跑出什么好结果?
今天咱们就聊聊ESG数据基础设施怎么搭。我踩过的坑不少,希望能帮你省点时间。
一、三大评级机构:谁的数据更靠谱?
目前市场上主流的ESG评级机构有三家:MSCI、Sustainalytics、Refinitiv。每家都有自己的脾气。
| 维度 | MSCI | Sustainalytics | Refinitiv |
|---|---|---|---|
| 覆盖范围 | 约8500家公司 | 约12000家公司 | 约7000家公司 |
| 评级体系 | AAA-CCC七档 | 0-100分+风险等级 | 0-100分+四档 |
| 数据更新频率 | 季度/事件驱动 | 月度/事件驱动 | 年度为主 |
| 争议事件处理 | 有专门模块 | 强项,实时监控 | 较弱 |
| API成熟度 | 中等 | 较好 | 优秀 |
我个人习惯:做多因子模型时用MSCI,做风险控制时用Sustainalytics。为什么?MSCI的评级更偏向「好公司」的筛选,而Sustainalytics对争议事件的敏感度更高——你想想看,一个突然爆出环境污染的公司,Sustainalytics的反应速度比MSCI快至少两周。
核心观点:不要迷信任何一家评级机构。我建议至少融合两家数据源,取交集或加权平均。单一数据源的偏差可能让你的策略在回测中看起来很美,实盘却一塌糊涂。
二、数据获取渠道与API实战
数据怎么拿?三种方式:
- 直接购买:MSCI、Sustainalytics都有官方数据订阅,价格不菲。小团队慎入。
- 第三方聚合平台:比如Bloomberg Terminal、FactSet,但API调用有次数限制。
- 开源/免费渠道:World Bank、CDP、SASB有部分免费数据,但覆盖不全。
这里我重点说说API调用。以Refinitiv为例,它的API设计得比较友好:
# Refinitiv ESG API 调用示例
import requests
import json
# 配置你的API密钥
api_key = "your_refinitiv_api_key"
base_url = "https://api.refinitiv.com/esg/v1"
# 获取某公司的ESG综合评分
def get_esg_score(ric_code):
endpoint = f"{base_url}/scores/{ric_code}"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
params = {
"fields": "esgScore,environmentalScore,socialScore,governanceScore",
"date": "2024-12-31"
}
response = requests.get(endpoint, headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
print(f"请求失败: {response.status_code}")
return None
# 调用示例
result = get_esg_score("AAPL.O")
print(json.dumps(result, indent=2))
避坑指南:我曾经在调用MSCI的API时,发现返回的数据里有些字段是空的。后来排查发现,MSCI对某些小市值公司只披露了部分指标。所以,一定要做缺失值检查,别直接拿过来就用。
三、数据清洗与标准化——这才是重头戏
数据拿到手了,但不同来源的格式、单位、评分标准都不一样。怎么办?
第一步:统一评分尺度
MSCI是AAA-CCC,Sustainalytics是0-100,Refinitiv也是0-100但分档不同。我一般会做百分制映射:
# MSCI评级转百分制
def msci_to_percent(msci_rating):
mapping = {
"AAA": 95, "AA": 85, "A": 75,
"BBB": 65, "BB": 55, "B": 45,
"CCC": 30
}
return mapping.get(msci_rating.upper(), None)
# Sustainalytics风险评分转正向评分(越低越好转越高越好)
def sustainalytics_to_percent(risk_score):
# 假设风险评分范围0-100,越低越好
return 100 - risk_score
# Refinitiv直接是0-100,但需要检查是否标准化
def refinitiv_to_percent(raw_score):
# 有些版本返回的是0-1的小数
if raw_score <= 1:
return raw_score * 100
return raw_score
第二步:处理时间对齐
不同机构的更新频率不同。MSCI可能3月更新,Sustainalytics可能4月才更新。你建模型时,时间戳必须对齐。
我的做法:取每个季度末的最新评级。如果某家机构在该季度没有更新,就用上一季度的数据填充。
注意:千万别用「前向填充」!我曾经犯过这个错——用未来的数据填充过去,回测结果漂亮得离谱,实盘直接打脸。一定要用「后向填充」或「最近可用值」。
第三步:异常值处理
ESG数据里经常出现极端值。比如某公司突然从AA跌到CCC,可能是数据错误,也可能是重大事件。怎么区分?
- 3σ原则:超过均值±3个标准差的值,标记为可疑
- IQR方法:四分位距法,更稳健
- 业务规则:比如评级不可能在一天内从AAA跌到CCC,除非有确凿证据
# 异常值检测示例
import numpy as np
def detect_outliers_iqr(data):
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
return (data < lower_bound) | (data > upper_bound)
# 应用
esg_scores = np.array([85, 90, 88, 92, 30, 87, 91]) # 30是异常值
outliers = detect_outliers_iqr(esg_scores)
print(f"异常值位置: {np.where(outliers)[0]}")
四、知识体系框架
下面这张图概括了ESG数据基础设施的核心流程:
说白了,数据基础设施就是四个字:干净、对齐、可用。你花80%的时间在数据清洗上,剩下20%的时间建模,这才是正常的比例。如果反过来,你的模型大概率会出问题。
最后说一句:ESG数据不像股价数据那样标准化。每家机构都有自己的方法论,甚至同一家机构不同年份的方法论都可能变。所以,版本控制很重要——我每次更新数据都会记录评级机构的方法论版本号,方便回溯。