自学教程 学编程从这里开始

Pandas 股票数据分析

本文使用 Pandas 做股票行情数据清洗、指标计算、回测前置分析,包含行情读取、均线、MACD、RSI、布林带、收益率、滚动波动率、相关性、可视化,适合A股/美股日线数据,延续整套教程风格。
前置依赖

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

一、示例数据说明

一般股票日线字段标准:date, open, high, low, close, volume(日期、开盘、最高、最低、收盘、成交量)

你可以用 tushare / akshare 获取真实A股数据;下面先构造模拟行情用于演示。

# 构造模拟日线数据
np.random.seed(42)
dates = pd.date_range(start="2025-01-01", end="2025-06-30", freq="D")
n = len(dates)
base_price = 10
close = base_price + np.cumsum(np.random.randn(n)*0.2)
df = pd.DataFrame({
    "date": dates,
    "close": close,
    "open": close + np.random.randn(n)*0.15,
    "high": close + np.abs(np.random.randn(n)*0.3),
    "low": close - np.abs(np.random.randn(n)*0.3),
    "volume": np.random.randint(100000, 500000, size=n)
})
# 日期设为索引,时序分析必备
df = df.set_index("date")
df = df.sort_index()

真实数据获取示例(akshare)

# pip install akshare
# import akshare as ak
# df = ak.stock_zh_a_hist(symbol="600036", period="daily", start_date="20250101", end_date="20250630")
# df = df[["date","open","high","low","close","volume"]].set_index("date")

二、基础收益率计算

# 单日涨跌幅(简单收益率)
df["pct_change"] = df["close"].pct_change()
# 对数收益率(金融统计常用,可累加)
df["log_return"] = np.log(df["close"] / df["close"].shift(1))

# 累计净值
df["net_value"] = (1 + df["pct_change"]).cumprod()
  • pct_change():后值 / 前值 -1,就是日常看到的涨跌幅
  • 对数收益率:适合做统计、波动率、相关性

三、移动平均线 MA(均线)

# 5日、10日、20日、60日均线
df["ma5"]  = df["close"].rolling(window=5).mean()
df["ma10"] = df["close"].rolling(window=10).mean()
df["ma20"] = df["close"].rolling(window=20).mean()
df["ma60"] = df["close"].rolling(window=60).mean()

# 金叉死叉标记:5日均线上穿10日均线=金叉
df["golden_cross"] = np.where(
    (df["ma5"] > df["ma10"]) & (df["ma5"].shift(1) <= df["ma10"].shift(1)),
    1, 0
)
df["death_cross"] = np.where(
    (df["ma5"] < df["ma10"]) & (df["ma5"].shift(1) >= df["ma10"].shift(1)),
    1, 0
)

四、布林带 BOLL

布林带 = 中轨(MA20) + 上下轨(±2倍标准差)

df["boll_mid"] = df["close"].rolling(20).mean()
df["boll_std"] = df["close"].rolling(20).std()
df["boll_upper"] = df["boll_mid"] + 2 * df["boll_std"]
df["boll_lower"] = df["boll_mid"] - 2 * df["boll_std"]
  • 价格上轨上方:超买
  • 价格下轨下方:超卖

五、RSI 相对强弱指标

def calc_rsi(series, period=14):
    delta = series.diff()
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)
    avg_gain = gain.rolling(window=period).mean()
    avg_loss = loss.rolling(window=period).mean()
    rs = avg_gain / avg_loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

df["rsi14"] = calc_rsi(df["close"], 14)
  • RSI >70:超买
  • RSI <30:超卖

六、MACD 指标

def calc_macd(series, fast=12, slow=26, signal=9):
    ema_fast = series.ewm(span=fast, adjust=False).mean()
    ema_slow = series.ewm(span=slow, adjust=False).mean()
    dif = ema_fast - ema_slow
    dea = dif.ewm(span=signal, adjust=False).mean()
    macd_bar = (dif - dea) * 2
    return dif, dea, macd_bar

df["dif"], df["dea"], df["macd_bar"] = calc_macd(df["close"])
  • DIF上穿DEA:MACD金叉
  • DIF下穿DEA:MACD死叉

七、波动率、最大回撤(风险指标)

# 20日滚动波动率(年化,交易日按250)
df["vol_20d"] = df["log_return"].rolling(20).std() * np.sqrt(250)

# 最大回撤
cummax = df["net_value"].cummax()
df["drawdown"] = df["net_value"] / cummax - 1
max_drawdown = df["drawdown"].min()
print(f"最大回撤:{max_drawdown:.2%}")

八、多标的相关性(多股票对比)

如果有多只股票 close 合并到一张表,可以直接算相关系数矩阵

# 示例:df_multi 每一列是一只股票的收盘价
# corr = df_multi.pct_change().corr()
# sns.heatmap(corr, annot=True, cmap="coolwarm")

九、绘图:K线辅助图(均线、布林带)

简易价格+均线图(K线需要 mplfinance,下面是pandas原生绘图)

plt.figure(figsize=(12,6))
plt.plot(df["close"], label="收盘价", color="#222222")
plt.plot(df["ma5"], label="MA5", color="#f44336")
plt.plot(df["ma20"], label="MA20", color="#2196f3")
plt.plot(df["boll_upper"], label="BOLL上轨", ls="--", color="#999999")
plt.plot(df["boll_lower"], label="BOLL下轨", ls="--", color="#999999")
plt.title("股价、均线与布林带")
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

K线图:

mplfinance 专业K线(扩展)

# pip install mplfinance
# import mplfinance as mpf
# mpf.plot(df, type="candle", mav=(5,20), volume=True, show_nontrading=False)

十、简单策略回测模板(金叉买入、死叉卖出)

# 初始化仓位
df["pos"] = 0
df.loc[df["golden_cross"] == 1, "pos"] = 1
df.loc[df["death_cross"] == 1, "pos"] = 0
# 仓位向前填充(持仓保持)
df["pos"] = df["pos"].replace(0, np.nan).ffill().fillna(0)

# 策略收益 = 持仓 * 当日收益率
df["strategy_return"] = df["pos"].shift(1) * df["pct_change"]
df["strategy_net"] = (1 + df["strategy_return"]).cumprod()

# 对比基准净值
plt.figure(figsize=(10,5))
plt.plot(df["net_value"], label="持有基准")
plt.plot(df["strategy_net"], label="均线策略")
plt.legend()
plt.title("策略净值对比")
plt.show()

⚠️ 简化模型,未考虑手续费、滑点、涨跌停、T+1规则,仅用于学习Pandas指标计算。

十一、常用指标速查表

指标Pandas核心函数
涨跌幅pct_change()
对数收益np.log(close / close.shift(1))
均线MArolling().mean()
布林带rolling().mean() + rolling().std()
RSI滚动涨跌均值
MACDewm().mean() 指数移动平均
滚动波动率rolling().std()
最大回撤cummax()
累计净值cumprod()

十二、实战避坑清单

  1. 交易日过滤:原始数据包含周末节假日,要先剔除空行情行
  2. shift 时序对齐:信号是当天收盘产生,次日才能交易,仓位要 shift(1)
  3. EWM 指数均线 adjust=False 是金融标准写法,不要省略
  4. 复权!A股必须用前复权价格计算指标,不复权会因为分红除权造成指标失真
  5. 滚动窗口 rolling 前面N行是NaN,回测时注意跳过
  6. 不要用未来函数:指标计算不能用到未来数据
  7. 多标的合并时,注意日期对齐,缺失行情用 reindex 补全

十三、拓展方向

  • 用 merge_asof 匹配基本面、公告、财报数据
  • 分行业分组、行业中性超额收益
  • 因子IC、IR、单因子分析
  • 对接Backtrader、VectorBT做专业回测
标签:

0 条笔记