加载中...

金融数据可视化:从基础图表到高级仪表盘

数据可视化是金融分析中的重要环节。好的图表不仅能直观展示数据,还能帮助发现隐藏的规律和异常。

常用可视化库对比

优势适用场景
Matplotlib高度可定制、静态图表报告、论文
Plotly交互式、美观Web展示、探索性分析
mplfinance专门的金融图表库K线图、技术分析

基础设置

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import mplfinance as mpf

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 设置样式
plt.style.use('seaborn-v0_8-darkgrid')

1. K线图(蜡烛图)

使用 mplfinance

def plot_candlestick_mpf(data, title="K线图"):
    ma_lines = mpf.make_addplot(data[['MA5', 'MA20']], 
                                panel=0, 
                                width=0.8)
    
    mpf.plot(
        data,
        type='candle',
        style='charles',
        title=title,
        ylabel='价格',
        volume=True,
        addplot=ma_lines,
        figsize=(12, 8),
        savefig='kline.png'
    )

使用 Plotly(交互式)

def plot_candlestick_plotly(data, title="交互式K线图"):
    fig = make_subplots(
        rows=2, cols=1,
        shared_xaxes=True,
        vertical_spacing=0.03,
        row_heights=[0.7, 0.3],
        subplot_titles=(title, '成交量')
    )
    
    fig.add_trace(
        go.Candlestick(
            x=data.index,
            open=data['open'],
            high=data['high'],
            low=data['low'],
            close=data['close'],
            name='K线'
        ),
        row=1, col=1
    )
    
    fig.add_trace(
        go.Scatter(
            x=data.index,
            y=data['MA5'],
            name='MA5',
            line=dict(color='orange', width=1)
        ),
        row=1, col=1
    )
    
    fig.add_trace(
        go.Scatter(
            x=data.index,
            y=data['MA20'],
            name='MA20',
            line=dict(color='blue', width=1)
        ),
        row=1, col=1
    )
    
    colors = ['red' if row['close'] > row['open'] else 'green' 
              for _, row in data.iterrows()]
    
    fig.add_trace(
        go.Bar(
            x=data.index,
            y=data['volume'],
            name='成交量',
            marker_color=colors
        ),
        row=2, col=1
    )
    
    fig.update_layout(
        height=800,
        xaxis_rangeslider_visible=False,
        hovermode='x unified'
    )
    
    fig.show()

2. 技术指标图表

MACD 指标

def plot_macd(data):
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), 
                                    sharex=True,
                                    gridspec_kw={'height_ratios': [2, 1]})
    
    ax1.plot(data.index, data['close'], label='收盘价', linewidth=1.5)
    ax1.set_ylabel('价格')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    ax2.plot(data.index, data['MACD'], label='MACD', linewidth=1.5)
    ax2.plot(data.index, data['Signal'], label='Signal', linewidth=1.5)
    
    colors = ['red' if val > 0 else 'green' for val in data['MACD_Hist']]
    ax2.bar(data.index, data['MACD_Hist'], 
            label='MACD Histogram', color=colors, alpha=0.3)
    
    ax2.set_xlabel('日期')
    ax2.set_ylabel('MACD')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    ax2.axhline(y=0, color='black', linestyle='--', linewidth=0.5)
    
    plt.tight_layout()
    plt.show()

布林带

def plot_bollinger_bands(data):
    plt.figure(figsize=(12, 6))
    
    plt.plot(data.index, data['close'], label='收盘价', 
             color='black', linewidth=1.5)
    
    plt.plot(data.index, data['BB_upper'], label='上轨', 
             color='red', linestyle='--', linewidth=1)
    plt.plot(data.index, data['BB_middle'], label='中轨', 
             color='blue', linestyle='--', linewidth=1)
    plt.plot(data.index, data['BB_lower'], label='下轨', 
             color='green', linestyle='--', linewidth=1)
    
    plt.fill_between(data.index, data['BB_upper'], data['BB_lower'], 
                     alpha=0.1, color='gray')
    
    plt.xlabel('日期')
    plt.ylabel('价格')
    plt.title('布林带指标')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()

3. 收益分析图表

收益分布直方图

def plot_returns_distribution(returns):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
    
    ax1.hist(returns, bins=50, alpha=0.7, color='steelblue', edgecolor='black')
    ax1.axvline(returns.mean(), color='red', linestyle='--', 
                label=f'均值: {returns.mean():.4f}')
    ax1.axvline(returns.median(), color='green', linestyle='--', 
                label=f'中位数: {returns.median():.4f}')
    ax1.set_xlabel('收益率')
    ax1.set_ylabel('频数')
    ax1.set_title('收益率分布')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    from scipy import stats
    stats.probplot(returns, dist="norm", plot=ax2)
    ax2.set_title('Q-Q 图')
    ax2.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

累计收益曲线

def plot_cumulative_returns(strategy_returns, benchmark_returns=None):
    plt.figure(figsize=(12, 6))
    
    cumulative_strategy = (1 + strategy_returns).cumprod()
    plt.plot(cumulative_strategy.index, cumulative_strategy, 
             label='策略收益', linewidth=2)
    
    if benchmark_returns is not None:
        cumulative_benchmark = (1 + benchmark_returns).cumprod()
        plt.plot(cumulative_benchmark.index, cumulative_benchmark, 
                 label='基准收益', linewidth=2, alpha=0.7)
    
    plt.xlabel('日期')
    plt.ylabel('累计收益(倍数)')
    plt.title('策略累计收益曲线')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()

回撤曲线

def plot_drawdown(returns):
    cumulative = (1 + returns).cumprod()
    running_max = cumulative.expanding().max()
    drawdown = (cumulative - running_max) / running_max
    
    plt.figure(figsize=(12, 6))
    plt.fill_between(drawdown.index, drawdown, 0, 
                     alpha=0.3, color='red', label='回撤')
    plt.plot(drawdown.index, drawdown, color='darkred', linewidth=1.5)
    
    max_dd_date = drawdown.idxmin()
    max_dd_value = drawdown.min()
    plt.plot(max_dd_date, max_dd_value, 'ro', markersize=10)
    plt.annotate(f'最大回撤: {max_dd_value:.2%}',
                xy=(max_dd_date, max_dd_value),
                xytext=(10, 20), textcoords='offset points',
                bbox=dict(boxstyle='round', fc='yellow', alpha=0.5),
                arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
    
    plt.xlabel('日期')
    plt.ylabel('回撤')
    plt.title('策略回撤曲线')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()

4. 相关性分析

相关性热力图

def plot_correlation_heatmap(data):
    import seaborn as sns
    
    corr_matrix = data.corr()
    
    plt.figure(figsize=(10, 8))
    sns.heatmap(corr_matrix, 
                annot=True,
                cmap='coolwarm',
                center=0,
                square=True,
                linewidths=0.5,
                cbar_kws={"shrink": 0.8})
    
    plt.title('资产相关性热力图')
    plt.tight_layout()
    plt.show()

5. 综合仪表盘

def create_dashboard(data, returns):
    fig = plt.figure(figsize=(16, 10))
    gs = fig.add_gridspec(3, 2, hspace=0.3, wspace=0.3)
    
    ax1 = fig.add_subplot(gs[0, :])
    ax1.plot(data.index, data['close'])
    ax1.set_title('价格走势', fontsize=14, fontweight='bold')
    ax1.set_ylabel('价格')
    ax1.grid(True, alpha=0.3)
    
    ax2 = fig.add_subplot(gs[1, 0])
    ax2.bar(data.index, data['volume'], alpha=0.5)
    ax2.set_title('成交量', fontsize=12, fontweight='bold')
    ax2.set_ylabel('成交量')
    ax2.grid(True, alpha=0.3)
    
    ax3 = fig.add_subplot(gs[1, 1])
    ax3.hist(returns, bins=30, alpha=0.7, edgecolor='black')
    ax3.set_title('收益率分布', fontsize=12, fontweight='bold')
    ax3.set_xlabel('收益率')
    ax3.grid(True, alpha=0.3)
    
    ax4 = fig.add_subplot(gs[2, 0])
    cumulative = (1 + returns).cumprod()
    ax4.plot(cumulative.index, cumulative)
    ax4.set_title('累计收益', fontsize=12, fontweight='bold')
    ax4.set_ylabel('累计收益(倍)')
    ax4.grid(True, alpha=0.3)
    
    ax5 = fig.add_subplot(gs[2, 1])
    running_max = cumulative.expanding().max()
    drawdown = (cumulative - running_max) / running_max
    ax5.fill_between(drawdown.index, drawdown, 0, alpha=0.3, color='red')
    ax5.set_title('回撤曲线', fontsize=12, fontweight='bold')
    ax5.set_ylabel('回撤')
    ax5.grid(True, alpha=0.3)
    
    plt.show()

可视化最佳实践

  1. 选择合适的图表类型

    • 趋势分析:折线图
    • 分布分析:直方图、箱线图
    • 比较分析:柱状图
    • 相关性:散点图、热力图
  2. 注意颜色搭配

    • 使用色盲友好的配色方案
    • 红涨绿跌符合国内习惯
  3. 添加必要的标注

    • 关键点位标注
    • 统计指标显示
    • 图例说明清晰
  4. 保持简洁

    • 避免图表过于复杂
    • 突出重点信息
    • 适当留白

总结

掌握金融数据可视化能力可以:

  • 快速发现数据中的模式和异常
  • 更好地展示分析结果
  • 辅助决策制定

建议根据不同场景选择合适的可视化工具和图表类型。

下一篇将介绍如何使用 Dash 创建交互式金融分析应用。

Author
Tong
© 2025 by Tong 本文基于 CC BY-NC-SA 4.0 许可 CC 协议 必须注明创作者 仅允许将作品用于非商业用途 改编作品必须遵循相同条款进行共享 最后更新:2025/11/12