🚀 AI 一键生成 joinquant 策略代码
立即体验

JoinQuant 平台如何计算大盘股成交额占比并绘制历史分位数走势图?

joinquant | 发布时间: 2026/8/10
以下内容由 EasyQuant 生成。

问题描述

JoinQuant 如何绘制大盘股成交额占全市场比例的历史分位图?
在聚宽中,如何按市值分组计算大盘前10%股票占全市场成交额的比例,并绘制带历史分位数参考线的走势图?

解决方案

在量化投资中,大盘股(市值前10%)的成交额占全市场的比例是衡量市场风格切换(大盘股抱团 vs 小盘股活跃)以及市场流动性分配的重要指标。通过绘制该指标的历史分位数图,可以清晰地识别当前市场情绪所处的历史位置。

以下是在 JoinQuant(聚宽)研究环境中实现该功能的完整 Python 步骤和源码:

1. 核心设计思路

  1. 获取股票池与市值数据:使用 get_all_securities 获取历史某交易日上市的全部 A 股,再通过 get_fundamentalsget_valuation 获取这些股票的市值(market_cap)。
  2. 市值排序与分组:将股票按市值从大到小排序,筛选出前 10% 的股票定义为“大盘股”。
  3. 获取成交额数据:使用 get_price 获取所有 A 股在对应日期的成交额(money)。
  4. 计算占比:计算大盘股的成交额总和占全市场总成交额的比例。
  5. 计算历史分位数并绘图:对时间序列数据计算 20%、50%、80% 等分位数,并使用 matplotlib 绘制走势图与参考线。

2. 完整 Python 源码(可在聚宽研究环境中直接运行)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from jqdata import *

# 1. 设置参数
start_date = '2023-01-01'
end_date = '2023-12-31'

# 获取统计区间内的所有交易日
trade_days = get_trade_days(start_date=start_date, end_date=end_date)

ratio_list = []
dates = []

print("开始计算每日大盘股成交额占比...")
# 2. 循环计算每日占比
for date in trade_days:
    date_str = date.strftime('%Y-%m-%d')
    
    # 获取当天在市的 A 股列表
    stocks = list(get_all_securities(['stock'], date=date).index)
    
    # 获取市值数据
    q = query(valuation.code, valuation.market_cap).filter(valuation.code.in_(stocks))
    df_valuation = get_fundamentals(q, date=date_str)
    
    if df_valuation.empty:
        continue
        
    # 按市值降序排列
    df_valuation = df_valuation.sort_values(by='market_cap', ascending=False)
    
    # 筛选前 10% 的大盘股
    top_10_percent_count = int(len(df_valuation) * 0.1)
    large_cap_stocks = list(df_valuation['code'].iloc[:top_10_percent_count])
    
    # 获取当天所有股票的成交额 (money)
    # 使用 get_price 获取单日数据
    df_price = get_price(stocks, start_date=date_str, end_date=date_str, frequency='daily', fields=['money'], panel=False)
    
    if df_price.empty:
        continue
        
    # 计算全市场总成交额和大盘股总成交额
    total_market_money = df_price['money'].sum()
    large_cap_money = df_price[df_price['code'].isin(large_cap_stocks)]['money'].sum()
    
    if total_market_money > 0:
        ratio = large_cap_money / total_market_money
        ratio_list.append(ratio)
        dates.append(date)

# 3. 构建时间序列 DataFrame
df_ratio = pd.DataFrame({'ratio': ratio_list}, index=dates)

# 4. 计算历史分位数
p20 = np.percentile(df_ratio['ratio'], 20)
p50 = np.percentile(df_ratio['ratio'], 50)
p80 = np.percentile(df_ratio['ratio'], 80)
current_ratio = df_ratio['ratio'].iloc[-1]
current_quantile = (df_ratio['ratio'] < current_ratio).mean() * 100

# 5. 绘制走势图与分位数参考线
plt.figure(figsize=(12, 6))
plt.plot(df_ratio.index, df_ratio['ratio'], label='Large-Cap Vol Ratio (Top 10% MC)', color='#1f77b4', linewidth=1.5)

# 绘制分位数水平线
plt.axhline(y=p80, color='r', linestyle='--', alpha=0.7, label=f'80% Quantile ({p80:.2%})')
plt.axhline(y=p50, color='g', linestyle='--', alpha=0.7, label=f'50% Quantile ({p50:.2%})')
plt.axhline(y=p20, color='b', linestyle='--', alpha=0.7, label=f'20% Quantile ({p20:.2%})')

# 标注最新值
plt.scatter(df_ratio.index[-1], current_ratio, color='black', zorder=5)
plt.annotate(f'Latest: {current_ratio:.2%}\nQuantile: {current_quantile:.1f}%',
             xy=(df_ratio.index[-1], current_ratio),
             xytext=(-80, 10), textcoords='offset points', 
             arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=.2'))

plt.title('Historical Quantile of Large-Cap (Top 10% Market Cap) Volume Ratio', fontsize=14)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Volume Ratio', fontsize=12)
plt.legend(loc='upper left')
plt.grid(True, alpha=0.3)
plt.show()

3. 关键 API 说明

  • get_all_securities(['stock'], date=date):动态获取历史某一天上市的股票,有效避免幸存者偏差(剔除未上市或已退市股票)。
  • get_fundamentals(query(valuation.code, valuation.market_cap), date=date_str):获取指定日期的市值表数据,用于对全市场股票进行大盘股/小盘股的划分。
  • get_price(..., fields=['money']):获取个股的成交额(单位:元)。
  • np.percentile:用于计算历史序列的百分位数,帮助量化当前占比在历史中所处的位置。