4. 数据可视化基础:使用Matplotlib和Seaborn绘制汇率走势图、移动平均线、波动率图
数据可视化,说白了就是让数字开口说话。我做了这么多年量化,最深的体会是:一张好图胜过千行回测结果。尤其是汇率数据,时间序列天生就适合用图形来理解趋势、波动和异常。
这一章,我们聚焦三个核心图表:汇率走势图、移动平均线、波动率图。我会用Matplotlib和Seaborn这两个Python库,带你从零开始画出专业级的金融图表。
4.1 准备工作:导入库与数据
先别急着画图,把工具备齐。我个人习惯用pandas读数据,matplotlib做基础绘图,seaborn美化样式。你想想看,如果每次都要手动调颜色、改字体,那得多累?Seaborn就是来解放你的。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体,防止乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 读取汇率数据(假设已有CSV文件)
df = pd.read_csv('eur_usd.csv', parse_dates=['date'], index_col='date')
print(df.head())
嗯,这里要注意:parse_dates参数一定要加,否则日期会被当成字符串。我曾经因为这个坑,画出来的图横轴全是乱序的数字,排查了半天才发现是日期没解析。
4.2 绘制汇率走势图
走势图是最基础的,也是最重要的。它能让你一眼看出汇率的整体趋势——是涨是跌,有没有明显的顶部或底部。
plt.figure(figsize=(12, 6))
plt.plot(df.index, df['close'], color='#2E86AB', linewidth=1.5)
plt.title('EUR/USD 汇率走势图', fontsize=16, fontweight='bold')
plt.xlabel('日期')
plt.ylabel('汇率')
plt.grid(True, alpha=0.3)
plt.show()
画出来之后,你会发现汇率数据其实很“毛躁”。单看这根线,你很难判断长期趋势。这时候就需要移动平均线出场了。
sns.set_style('darkgrid'),背景带网格,看起来更专业。
4.3 叠加移动平均线
移动平均线(MA)是平滑价格波动的利器。说白了,就是把过去N天的收盘价取个平均值,画成一条更平滑的线。常用的有20日均线(短期)和60日均线(中期)。
我在项目中遇到过一个问题:直接用rolling()计算MA,前N-1天会变成NaN。如果你不处理,画出来的线开头会断掉。我的做法是:要么从第N天开始画,要么用min_periods参数。
# 计算移动平均线
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA60'] = df['close'].rolling(window=60).mean()
# 绘制
plt.figure(figsize=(12, 6))
plt.plot(df.index, df['close'], label='收盘价', color='#2E86AB', alpha=0.6)
plt.plot(df.index, df['MA20'], label='20日均线', color='#E67E22', linewidth=2)
plt.plot(df.index, df['MA60'], label='60日均线', color='#C0392B', linewidth=2)
plt.title('EUR/USD 汇率与移动平均线', fontsize=16)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
你想想看,当短期均线(MA20)上穿长期均线(MA60)时,俗称“金叉”,往往是买入信号。反之“死叉”则是卖出信号。当然,这只是基础,实战中还要结合其他指标。
4.4 绘制波动率图
波动率,说白了就是汇率“跳得有多厉害”。高波动率意味着风险大,但也可能带来高收益。量化里常用滚动标准差来衡量波动率。
我一般用20天的滚动标准差,因为一个月大概有20个交易日,这个窗口比较合理。
# 计算日收益率
df['return'] = df['close'].pct_change()
# 计算20天滚动波动率(标准差)
df['volatility'] = df['return'].rolling(window=20).std() * np.sqrt(252) # 年化
# 绘制波动率图
plt.figure(figsize=(12, 6))
plt.fill_between(df.index, df['volatility'], color='#E74C3C', alpha=0.3)
plt.plot(df.index, df['volatility'], color='#C0392B', linewidth=1.5)
plt.title('EUR/USD 年化波动率(20日滚动)', fontsize=16)
plt.xlabel('日期')
plt.ylabel('年化波动率')
plt.grid(True, alpha=0.3)
plt.show()
这里有个细节:np.sqrt(252)是把日波动率年化。为什么是252?因为一年大约有252个交易日。如果你用日数据,就要乘这个系数。我曾经见过有人直接用日标准差当波动率,结果回测出来的风险指标全错了。
4.5 用Seaborn美化图表
Matplotlib画出来的图功能强大,但颜值嘛...嗯,你懂的。Seaborn可以一键美化,让图表看起来像金融杂志上的那种。
sns.set_style('whitegrid')
sns.set_palette('husl')
plt.figure(figsize=(12, 6))
sns.lineplot(data=df, x=df.index, y='close', label='收盘价')
sns.lineplot(data=df, x=df.index, y='MA20', label='20日均线')
sns.lineplot(data=df, x=df.index, y='MA60', label='60日均线')
plt.title('EUR/USD 汇率走势(Seaborn风格)', fontsize=16)
plt.legend()
plt.show()
你看,代码更简洁了,颜色也自动配好了。我个人习惯在正式报告里用Seaborn,在快速调试时用Matplotlib。
4.6 本章知识体系
下面这张图,帮你理清本章的核心逻辑:从原始数据到三种关键图表,每一步都有对应的技术和注意事项。
4.7 组合图表:一图看全貌
有时候,我们需要把走势、均线、波动率放在一张图里,方便对比。我常用的方式是:上面画价格和均线,下面画波动率,共享X轴。
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8), sharex=True)
# 上子图:价格与均线
ax1.plot(df.index, df['close'], label='收盘价', color='#2E86AB', alpha=0.7)
ax1.plot(df.index, df['MA20'], label='MA20', color='#E67E22')
ax1.plot(df.index, df['MA60'], label='MA60', color='#C0392B')
ax1.set_title('EUR/USD 汇率与移动平均线', fontsize=14)
ax1.legend()
ax1.grid(True, alpha=0.3)
# 下子图:波动率
ax2.fill_between(df.index, df['volatility'], color='#E74C3C', alpha=0.3)
ax2.plot(df.index, df['volatility'], color='#C0392B', linewidth=1.5)
ax2.set_title('年化波动率(20日滚动)', fontsize=14)
ax2.set_xlabel('日期')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
你看,这样一对比,就能发现:波动率飙升的时候,往往是汇率剧烈波动的时候。比如2020年3月疫情爆发,波动率瞬间冲高,汇率也出现了大幅跳空。
- 走势图看方向,移动平均线看趋势,波动率图看风险
- Matplotlib负责底层控制,Seaborn负责颜值提升
- 年化波动率记得乘 sqrt(252),否则数值会偏小
- 组合图表能让你一眼看透价格与风险的关系
好了,这一章的内容就到这里。画图是量化分析的基本功,别嫌简单。你想想看,如果连走势都画不清楚,后面怎么建模型、怎么调参数?动手试试吧,把代码跑一遍,你会发现自己也能画出金融级别的图表。