3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化投资中,大盘股(市值前10%)的成交额占全市场的比例是衡量市场风格切换(大盘股抱团 vs 小盘股活跃)以及市场流动性分配的重要指标。通过绘制该指标的历史分位数图,可以清晰地识别当前市场情绪所处的历史位置。
以下是在 JoinQuant(聚宽)研究环境中实现该功能的完整 Python 步骤和源码:
get_all_securities 获取历史某交易日上市的全部 A 股,再通过 get_fundamentals 或 get_valuation 获取这些股票的市值(market_cap)。get_price 获取所有 A 股在对应日期的成交额(money)。matplotlib 绘制走势图与参考线。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()
get_all_securities(['stock'], date=date):动态获取历史某一天上市的股票,有效避免幸存者偏差(剔除未上市或已退市股票)。get_fundamentals(query(valuation.code, valuation.market_cap), date=date_str):获取指定日期的市值表数据,用于对全市场股票进行大盘股/小盘股的划分。get_price(..., fields=['money']):获取个股的成交额(单位:元)。np.percentile:用于计算历史序列的百分位数,帮助量化当前占比在历史中所处的位置。