Python pandas金融数据分析实战:用真实行情数据学会数据处理

0 阅读6分钟

2026年5月7日,A股市场迎来"五一"后首个交易日,芯片板块集体爆发,寒武纪股价首次突破1900元,科创板芯片指数单日暴涨5.92%。这样的行情数据背后,藏着大量值得分析的信息。

今天这篇文章,船长用Python的pandas库,手把手带你从零开始处理真实的股票行情数据。学完这篇,你就能自己动手分析任意一只股票的历史走势。

一、环境准备

本文使用pandas + matplotlib,数据来源为AKShare免费行情接口。先安装依赖:

pip install pandas matplotlib akshare

如果你的网络无法访问PyPI,可以使用国内镜像:

pip install pandas matplotlib akshare -i https://pypi.tuna.tsinghua.edu.cn/simple

二、获取股票数据

使用AKShare获取寒武纪(688256)的历史行情数据:

import pandas as pd
import matplotlib.pyplot as plt
import akshare as ak

# 获取寒武纪(688256)近一年日线数据
df = ak.stock_zh_a_hist(symbol="688256", period="daily",
                         start_date="20250508", end_date="20260508",
                         adjust="qfq")

print(f"获取到 {len(df)} 条数据")
print(df.head())
print(df.dtypes)

输出字段说明:

  • 日期:交易日期

  • 开盘:当日开盘价

  • 收盘:当日收盘价

  • 最高:当日最高价

  • 最低:当日最低价

  • 成交量:当日成交股数

  • 成交额:当日成交金额(元)

  • 涨跌幅:当日涨跌百分比

三、数据清洗基础

原始数据往往存在缺失值、异常值,需要先清洗再分析。

3.1 检查缺失值

# 检查每列缺失值数量
print(df.isnull().sum())

# 查看有缺失值的行
missing_rows = df[df.isnull().any(axis=1)]
print(f"存在缺失值的行数: {len(missing_rows)}")

如果数据中有缺失值,用前值填充或直接删除:

# 方法1:删除缺失行
df_clean = df.dropna()

# 方法2:用前值填充
df_clean = df.fillna(method='ffill')

print(f"清洗前: {len(df)} 行, 清洗后: {len(df_clean)} 行")

3.2 转换日期格式

# 将日期列转换为datetime类型,方便后续按时间筛选
df_clean['日期'] = pd.to_datetime(df_clean['日期'])

# 按日期升序排序
df_clean = df_clean.sort_values('日期').reset_index(drop=True)

print(f"数据时间范围: {df_clean['日期'].min()}{df_clean['日期'].max()}")

3.3 识别异常值

# 用IQR方法识别单日涨跌幅异常
Q1 = df_clean['涨跌幅'].quantile(0.25)
Q3 = df_clean['涨跌幅'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 3 * IQR  # 用3倍IQR,更宽松
upper_bound = Q3 + 3 * IQR

outliers = df_clean[(df_clean['涨跌幅']  upper_bound)]

print(f"异常涨跌幅阈值: [{lower_bound:.2f}%, {upper_bound:.2f}%]")
print(f"异常值数量: {len(outliers)}")
if len(outliers) > 0:
    print(outliers[['日期', '涨跌幅']])

四、核心指标计算

4.1 日收益率与累计收益率

# 计算单日收益率(Close to Close)
df_clean['日收益率'] = df_clean['收盘'].pct_change() * 100

# 计算累计收益率(买入持有策略)
df_clean['累计收益率'] = (1 + df_clean['日收益率'] / 100).cumprod() - 1
df_clean['累计收益率'] = df_clean['累计收益率'] * 100

print(f"最高单日涨幅: {df_clean['日收益率'].max():.2f}%")
print(f"最高单日跌幅: {df_clean['日收益率'].min():.2f}%")
print(f"区间累计收益率: {df_clean['累计收益率'].iloc[-1]:.2f}%")

4.2 移动平均线(MA5 / MA20 / MA60)

# 计算简单移动平均
df_clean['MA5'] = df_clean['收盘'].rolling(window=5).mean()
df_clean['MA20'] = df_clean['收盘'].rolling(window=20).mean()
df_clean['MA60'] = df_clean['收盘'].rolling(window=60).mean()

# 查看最新数据
print(df_clean[['日期', '收盘', 'MA5', 'MA20', 'MA60']].tail())

4.3 波动率(Volatility)

# 计算20日年化波动率
df_clean['日波动率'] = df_clean['日收益率'].rolling(window=20).std()
df_clean['年化波动率'] = df_clean['日波动率'] * (252 ** 0.5)  # 年化

print(f"最新年化波动率: {df_clean['年化波动率'].iloc[-1]:.2f}%")
print(f"平均年化波动率: {df_clean['年化波动率'].mean():.2f}%")

4.4 成交量异常检测(量比)

# 计算量比:当日成交量 / 过去20日平均成交量
df_clean['量比'] = df_clean['成交量'] / df_clean['成交量'].rolling(window=20).mean()

# 放量标准:量比 > 2
surge_days = df_clean[df_clean['量比'] > 2]
print(f"放量日(量比>2): {len(surge_days)} 天")
if len(surge_days) > 0:
    print(surge_days[['日期', '成交量', '涨跌幅', '量比']].tail())

五、可视化实战

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

fig, axes = plt.subplots(3, 1, figsize=(14, 10),
                         gridspec_kw={'height_ratios': [3, 1, 1]})

# 图1:股价 + 移动平均线
ax1 = axes[0]
ax1.plot(df_clean['日期'], df_clean['收盘'], label='收盘价', linewidth=1.5)
ax1.plot(df_clean['日期'], df_clean['MA5'], label='MA5', alpha=0.7, linewidth=1)
ax1.plot(df_clean['日期'], df_clean['MA20'], label='MA20', alpha=0.7, linewidth=1)
ax1.plot(df_clean['日期'], df_clean['MA60'], label='MA60', alpha=0.7, linewidth=1)
ax1.set_title('寒武纪(688256)股价走势与移动平均线', fontsize=14)
ax1.legend(loc='upper left')
ax1.grid(True, alpha=0.3)

# 图2:成交量柱状图
ax2 = axes[1]
colors = ['red' if c >= 0 else 'green'
          for c in df_clean['涨跌幅'].fillna(0)]
ax2.bar(df_clean['日期'], df_clean['成交量'] / 1e8, color=colors, alpha=0.7)
ax2.set_title('成交量(亿元)', fontsize=12)
ax2.grid(True, alpha=0.3)

# 图3:累计收益率
ax3 = axes[2]
ax3.fill_between(df_clean['日期'], df_clean['累计收益率'],
                 where=df_clean['累计收益率'] >= 0,
                 color='red', alpha=0.3)
ax3.fill_between(df_clean['日期'], df_clean['累计收益率'],
                 where=df_clean['累计收益率'] < 0,
                 color='green', alpha=0.3)
ax3.axhline(y=0, color='black', linewidth=0.5)
ax3.plot(df_clean['日期'], df_clean['累计收益率'], color='blue', linewidth=1)
ax3.set_title('累计收益率(%)', fontsize=12)
ax3.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('hanwu Trend.png', dpi=150)
plt.show()
print("图表已保存为 hanwu_trend.png")

六、完整分析脚本

以下是今天的实战完整代码,将上述所有步骤整合在一起:

import pandas as pd
import matplotlib.pyplot as plt
import akshare as ak

# ========== 1. 获取数据 ==========
df = ak.stock_zh_a_hist(symbol="688256", period="daily",
                         start_date="20250508", end_date="20260508",
                         adjust="qfq")

# ========== 2. 数据清洗 ==========
df['日期'] = pd.to_datetime(df['日期'])
df = df.sort_values('日期').reset_index(drop=True)
df = df.dropna()  # 删除缺失值

# ========== 3. 指标计算 ==========
df['日收益率'] = df['收盘'].pct_change() * 100
df['累计收益率'] = (1 + df['日收益率'] / 100).cumprod() - 1
df['累计收益率'] = df['累计收益率'] * 100
df['MA5'] = df['收盘'].rolling(window=5).mean()
df['MA20'] = df['收盘'].rolling(window=20).mean()
df['MA60'] = df['收盘'].rolling(window=60).mean()
df['量比'] = df['成交量'] / df['成交量'].rolling(window=20).mean()

# ========== 4. 输出关键数据 ==========
latest = df.iloc[-1]
print(f"=== 寒武纪(688256) 最新行情 ===")
print(f"日期: {latest['日期'].strftime('%Y-%m-%d')}")
print(f"收盘价: {latest['收盘']:.2f} 元")
print(f"单日涨幅: {latest['涨跌幅']:.2f}%")
print(f"量比: {latest['量比']:.2f}")
print(f"20日均线: {latest['MA20']:.2f}")
print(f"区间累计收益: {latest['累计收益率']:.2f}%")

七、总结

本文覆盖了pandas金融数据分析的核心流程:

  • 数据获取:使用AKShare免费接口获取真实行情数据

  • 数据清洗:缺失值处理、日期格式转换、异常值识别

  • 指标计算:日收益率、累计收益率、移动平均线、波动率、量比

  • 可视化:股价走势、成交量、累计收益三图联动

学会了这些基础,你就能分析任意一只A股或港股的走势。船长建议你用这个脚本跑一跑自己关注的股票,感受数据说话的力量。


【数据来源】AKShare免费行情接口 | 【时间】2026年5月

作者:CaptainTalk 数据分析系列