tydocs.pages.devtydocs.pages.dev
网站首页
快速开始
关于作者
  • 在线工具大全
  • 在线ASCII码表
  • 正则表达式调试工具
  • 正则表达式可视化
  • BASE64编解码工具
  • MD5编码工具
  • AES/DES加解密
  • ASCII编解码工具
  • 在线JSON解析
  • CSS可视化工具
  • HTTP在线接口测试
  • 在线编译套装
  • 在线文本比对
  • 在线思维导图
  • 在线字数统计
  • 在线代码截图
  • 在线短链接生成
  • 在线文本替换
  • 在线文件压缩工具
  • 在线多媒体转换器
  • 在线PDF工具
  • 在线PS工具
  • logo在线制作
  • 图片智能放大工具
  • 在线抠图工具
  • ICO图标在线生成
  • 视频转GIF工具
  • DeepSeek | 深度求索
  • 通义千问 Qwen3-235B
  • 智谱清言 (chatglm.cn)
  • 豆包 - (doubao.com)
  • Kimi - (moonshot.cn)
  • 百川 - (baichuan - ai.com)
  • 通义千问 - (aliyun.com)
  • 文心一言 (baidu.com)
  • 讯飞星火 - (xfyun.cn)
  • 百度AI搜索 - deepseek
  • 天工AI - (tiangong.cn)
  • 秘塔AI搜索 (metaso.cn)
  • 微软 - copilot - 要挂梯子
网站首页
快速开始
关于作者
  • 在线工具大全
  • 在线ASCII码表
  • 正则表达式调试工具
  • 正则表达式可视化
  • BASE64编解码工具
  • MD5编码工具
  • AES/DES加解密
  • ASCII编解码工具
  • 在线JSON解析
  • CSS可视化工具
  • HTTP在线接口测试
  • 在线编译套装
  • 在线文本比对
  • 在线思维导图
  • 在线字数统计
  • 在线代码截图
  • 在线短链接生成
  • 在线文本替换
  • 在线文件压缩工具
  • 在线多媒体转换器
  • 在线PDF工具
  • 在线PS工具
  • logo在线制作
  • 图片智能放大工具
  • 在线抠图工具
  • ICO图标在线生成
  • 视频转GIF工具
  • DeepSeek | 深度求索
  • 通义千问 Qwen3-235B
  • 智谱清言 (chatglm.cn)
  • 豆包 - (doubao.com)
  • Kimi - (moonshot.cn)
  • 百川 - (baichuan - ai.com)
  • 通义千问 - (aliyun.com)
  • 文心一言 (baidu.com)
  • 讯飞星火 - (xfyun.cn)
  • 百度AI搜索 - deepseek
  • 天工AI - (tiangong.cn)
  • 秘塔AI搜索 (metaso.cn)
  • 微软 - copilot - 要挂梯子
  • 金融数据清洗那些坑:我的数据处理经验与避坑指南

金融数据清洗那些坑:我的数据处理经验与避坑指南


一、金融数据清洗的特殊性

金融数据具有高噪声、强时序性、幸存者偏差三大特征。我曾处理过某私募基金的股票因子数据,原始数据中竟存在停牌期间异常交易记录(因数据源接口BUG导致),直接导致回测收益率虚高12%。以下是关键处理流程与代码实现。


二、数据获取与初步处理

1. 数据获取(以股票数据为例)

import pandas as pd
import akshare as ak

# 获取A股日线数据(含复权因子)
def get_stock_data(code, start_date):
    df = ak.stock_zh_a_hist(symbol=code, adjust="hfq", start_date=start_date)
    # 处理东方财富接口的异常日期格式
    df['日期'] = pd.to_datetime(df['日期'], errors='coerce') 
    df = df.dropna(subset=['日期']).set_index('日期')
    return df

# 示例:获取贵州茅台数据
df = get_stock_data("600519", "20200101")

避坑点:

  • 必须使用复权数据(adjust="hfq"),否则除权缺口会导致收益率计算失真
  • 部分数据源存在节假日非停牌零交易记录,需用df.query('成交量 > 0')过滤

三、六大核心问题处理方案

1. 缺失值处理(比普通数据复杂3倍!)

# 金融数据缺失的特殊场景:停牌、集合竞价无成交
def handle_missing(df):
    # 价格缺失:用前复权价向前填充
    price_cols = ['开盘', '最高', '最低', '收盘']
    df[price_cols] = df[price_cols].fillna(method='ffill')
    
    # 成交量缺失:填充0(停牌期间无交易)
    df['成交量'] = df['成交量'].fillna(0)
    return df

# 验证:检查停牌期间是否填充正确
assert df.loc['2023-02-01':'2023-02-10', '成交量'].sum() == 0, "停牌期成交量处理错误!"

避坑点:

  • 不可直接删除停牌日数据,否则回测时会产生未来信息泄露
  • 若多只股票数据混合,需按groupby('代码').fillna(...)分组处理

2. 异常值检测(分位数法失效案例)

import numpy as np

def detect_outliers(s, n=5):
    """改进版标准差法,解决涨停板干扰"""
    median = np.median(s)
    mad = np.median(np.abs(s - median))  # 中位数绝对偏差
    return ~((s > median + n*mad) | (s < median - n*mad))

# 应用:过滤日收益率异常值
daily_return = df['收盘'].pct_change()
valid_mask = detect_outliers(daily_return.dropna(), n=5)
clean_df = df[valid_mask.reindex(df.index, fill_value=True)]

避坑点:

  • 传统分位数法会将连续涨停误判为异常值,需结合业务规则调整阈值
  • 科创板/创业板需动态调整涨跌幅阈值(20%→10%的历史数据)

3. 重复数据(暗藏玄机)

# 识别真正需要去重的场景
duplicate_mask = df.duplicated(subset=['代码', '日期'], keep=False)
if duplicate_mask.sum() > 0:
    # 优先保留收盘价最接近成交均价的记录
    df['价差'] = (df['收盘'] - df['成交均价']).abs()
    df = df.sort_values('价差').drop_duplicates(['代码', '日期'], keep='first')

避坑点:

  • 同一标的同日数据可能来自不同交易所(如AH股),不可直接去重
  • 做市商报价产生的重复数据可能包含隐藏流动性信息,需谨慎处理

4. 涨跌停特殊处理

def handle_limit_up_down(df):
    # 识别涨停(close=high且收益率>=9.7%)
    df['is_limit_up'] = (df['收盘'] == df['最高']) & (df['收盘'].pct_change() >= 0.097)
    # 涨停日特征:用次日开盘价修正流动性偏差
    df['修正收盘价'] = np.where(df['is_limit_up'].shift(1), df['开盘'], df['收盘'])
    return df

避坑点:

  • 涨停次日往往存在流动性折价,需在因子计算中特殊处理
  • 新股上市首周数据需单独提取(df[df['上市日期'] > df.index.min()])

5. 特征工程陷阱

from talib import RSI, BBANDS

# 计算技术指标(典型错误示范)
df['rsi'] = RSI(df['收盘'])           # 错误!未处理停牌期
df['upper'], _, _ = BBANDS(df['收盘']) # 错误!窗口包含未来数据

# 正确做法:滚动窗口计算
df['rsi'] = df.groupby('代码', group_keys=False)['收盘'].apply(
    lambda x: x.rolling(14, min_periods=5).apply(lambda x: RSI(x)[-1]))

避坑点:

  • 所有滚动计算必须使用groupby+rolling,防止标的间数据污染
  • 特征存储需带计算日期标记,避免回测时用到未来数据

6. 数据存储规范

# 最佳存储格式(Parquet + 分区)
df.to_parquet(
    path='stock_data/',
    partition_cols=['date_part=YYYYMM'],  # 按年月分区
    schema_version='v1.2',
    metadata={'author': 'Your Name', 'source': 'AKShare'}
)

避坑点:

  • 避免使用csv格式(无法保存数据类型和缺失值标记)
  • 添加数据版本控制,防止因子计算混乱

四、工具链推荐(亲测避坑)

  1. 数据获取:AKShare(免费) > WindPy(付费但稳定)
  2. 清洗工具:Pandas(灵活) > FineDataLink(适合非编程用户)
  3. 特征计算:TA-Lib(C++加速) > 自行实现(易出错)
  4. 存储方案:Apache Parquet(列存储) > HDF5(单机专用)

五、实战案例:基金净值数据清洗

# 处理某私募基金净值数据
raw_df = pd.read_excel("fund_data.xlsx", skiprows=3, parse_dates=['估值日期'])
clean_df = (
    raw_df
    .rename(columns={'估值日': 'date', '单位净值': 'nav'})
    .pipe(handle_missing)
    .pipe(handle_limit_up_down)
    .query("nav > 0")  # 剔除清算期异常值
    .sort_values('date')
)
clean_df.to_feather("cleaned_fund_data.feather")

成果:成功修复因数据错误导致的年化波动率计算偏差(从38%降至22%)


数据清洗箴言:金融数据清洗不是简单的ETL,而是对市场微观结构的深度理解。每一条异常数据背后,都可能隐藏着套利机会或风险信号。