跳转至


课程  因子投资  机器学习  Python  Poetry  ppw  tools  programming  Numpy  Pandas  pandas  算法  hdbscan  聚类  选股  Algo  minimum  numpy  algo  FFT  模式识别  配对交易  GBDT  LightGBM  XGBoost  statistics  CDF  KS-Test  monte-carlo  VaR  回测  过拟合  algorithms  machine learning  strategy  python  sklearn  pdf  概率  数学  面试题  量化交易  策略分类  风险管理  Info  interview  career  xgboost  PCA  wavelet  时序事件归因  SHAP  Figures  Behavioral Economics  graduate  arma  garch  人物  职场  Quantopian  figure  Banz  金融行业  买方  卖方  story  量化传奇  rsi  zigzag  穹顶压力  因子  ESG  因子策略  投资  策略  pe  ORB  Xgboost  Alligator  Indicator  factor  alpha101  alpha  技术指标  wave  quant  algorithm  pearson  spearman  tushare  因子分析  Alphalens  涨停板  herd-behaviour  momentum  因子评估  review  SMC  聪明钱  trade  history  indicators  zscore  波动率  强化学习  顶背离  freshman  resources  others  AI  DeepSeek  network  量子计算  金融交易  IBM  weekly  LLT  backtest  backtrader  研报  papers  UBL  quantlib  jupyter-notebook  scikit-learn  pypinyin  qmt  xtquant  blog  static-site  duckdb  工具  colors  free resources  barra  world quant  Alpha  openbb  数据  risk-management  llm  prompt  CANSLIM  Augment  arsenal  copilot  vscode  code  量化数据存储  hdf5  h5py  cursor  augment  trae  Jupyter  jupysql  pyarrow  parquet  数据源  quantstats  实盘  clickhouse  notebook  redis  remote-agent  AI-tools  Moonshot  回测,研报,tushare 

factor&strategy »

涨到溢出!PEPE告诉我,大盘还能涨几多?


这两天涨得喜气洋洋的,不过,对东财的程序小哥哥来说,可能还得加班了,因为涨得太好,程序溢出了:

这是什么情况?

温故而知新

在2024年9月,我们曾发表《节前迎来揪心一幕!谁来告诉我,A股现在有没有低估?》一文。在那篇文章中,我们使用了akshare获取了上证指数的市盈率数据,并通过分位数和趋势分析,探讨了当时A股市场的估值情况。

当时我们的结论是:

如果仅从分位数统计来看,当下的A股是低估的。但如果考虑到市盈率总体上一直处在上升的趋势,以及最近一年来PE与指数涨跌的背离情况,判断A股是否已经低估还存有疑问,应该纳入更多维度进行判断。

现在是2025年8月,差不多快一年了。从成交量来看,市场似乎进入了狂飙期。我们去年使用过的技巧,是否还能用来预测未来的走势呢?

还是让数据说话。

使用 Tushare 获取指数市盈率

Tushare上周给我们放了一个假。不过,还好现在已经恢复了。要获取指数的市盈率,我们需要用到函数index_dailybasic。

1
2
3
4
5
6
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime

pro = pro_api()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def get_index_pe_close(ts_code='000001.SH', start_date='20100101', end_date='20250825'):
    # 获取指数PE数据
    df_pe = pro.index_dailybasic(ts_code=ts_code, 
                                start_date=start_date, 
                                end_date=end_date, 
                                fields='trade_date,pe_ttm')
    df_pe.rename(columns={'trade_date': 'date', 'pe_ttm': 'pe'}, inplace=True)
    df_pe['date'] = pd.to_datetime(df_pe['date'])
    df_pe.set_index('date', inplace=True)

    # 获取指数收盘价数据
    df_price = pro.index_daily(ts_code=ts_code,
                              start_date=start_date,
                              end_date=end_date,
                              fields='trade_date,close')
    df_price.rename(columns={'trade_date': 'date'}, inplace=True)
    df_price['date'] = pd.to_datetime(df_price['date'])
    df_price.set_index('date', inplace=True)

    # 合并数据
    df = df_pe.merge(df_price, left_index=True, right_index=True, how='inner')

    # 排序
    df.sort_index(inplace=True)

    # 移除PE为空的记录
    df = df.dropna(subset=['pe'])

    return df

得到 pe 数据之后,让我们先来看一下直观走势:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 绘制PE走势图
fig, ax = plt.subplots(figsize=(12,6))

color = "tab:red"
ax.plot(df.index, df["pe"], label="PE", color=color)
ax.set_xlabel("Year")
ax.set_ylabel("PE", color=color)
ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

df = get_index_pe_close(start_date="20100101")

# 添加分位数线
for i in range(1, 4):
    quantile = df["pe"].quantile(i/4)
    ax.axhline(quantile, color='gray', linestyle='--', label=f"{i/4:02.0%}")

plt.title("SSE Index PE Ratio (via Tushare)")
plt.legend(loc="upper left")
plt.grid(True)
plt.show()

数据表明,如果我们忽略2015年那段癫狂的历史(场外融资加杠杆),那么现在的 PE 水平已经是相当高了。

到底有多高呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def show_pe_quantile(df):
    # 计算当前PE分位数
    current_pe = df['pe'].iloc[-1]
    rank = df['pe'].rank().iloc[-1]
    percentile = rank / len(df)
    print(f"当前PE分位: {percentile:.2%}")

show_pe_quantile(df)

df = df[df.index > '2016-01-01']
show_pe_quantile(df)

如果从2013年起(tushare 似乎没有更早的数据了)开始算,那么当前PE分位数为95.18%;如果从2016年1月起算,那么当前 PE 分位数则已达到98.81%,很快就要满分了。作为指数来讲,确实是有点高了。

当前的 PE 值,是多少天以来的最高值呢?通过 pandas 可以很容易计算出来:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def find_days_since_max_pe(df):
    """计算当前的PE是过去多少天以来的最大值"""
    if df.empty or len(df) < 2:
        return None

    # 获取当前PE值
    current_pe = df['pe'].iloc[-1]

    # 找到当前PE值在历史数据中的最大值位置
    max_pe_idx = df['pe'].idxmax()

    # 计算距离最大值日期的天数
    current_date = df.index[-1]
    days_since_max = (current_date - max_pe_idx).days

    return days_since_max, max_pe_idx

find_days_since_max_pe(df)

答案是,现在的 PE 值是2018年1月24日以来的最大值,也就是创了7年来的新高。

假设指数能稳住,那么能让 PE 回到安全区的惟一答案,就是要靠企业利润增长了。如果指数就停在这个位置,要让 PE 回到安全区,需要企业利润增加多少呢?

我们通过下面的方法来计算:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def required_earnings_growth(df, target_percentile=0.75, target_index=None):
    """计算使PE分位数降到目标值所需的盈利增长百分比"""
    if df.empty:
        return None

    # 获取当前PE值和当前指数点位
    current_pe = df['pe'].iloc[-1]
    current_index = df['close'].iloc[-1]

    # 如果指定了目标指数点位,则计算在该点位下的目标PE值;否则使用数据框中目标分位数对应的PE值
    if target_index is not None:
        # 根据PE = Price / Earnings,计算目标指数点位下的PE值
        # 假设盈利不变,目标PE = target_index / (current_index / current_pe)
        # 即 target_pe = target_index * current_pe / current_index
        current_pe = target_index * current_pe / current_index


    # 计算目标PE值(目标分位数对应的PE)
    target_pe = df['pe'].quantile(target_percentile)

    # 如果当前PE已经低于目标PE,则不需要盈利增长
    if current_pe <= target_pe:
        return 0.0

    # 计算所需盈利增长百分比
    # PE = Price / Earnings => Earnings = Price / PE
    # 要使PE从current_pe降到target_pe,需要:
    # (Price / target_pe) / (Price / current_pe) - 1 = current_pe / target_pe - 1
    required_growth = (current_pe / target_pe) - 1

    return required_growth

required_earnings_growth(df)

通过计算可知,在现有的指数上,如果要让 PE 回到75%分位以下,那么企业利润需要增加10.2%。如果要让 PE 回到84.13%分位(即一个标准差)以下,那么企业盈利需要增长5.5%。根据企业的年利润增长水平,我们大致可以估算出这需要多少年。当然,这要求企业的年利润增长水平必须是正的。

如果我们希望指数能上涨到4000点,PE 还要回到一个标准差以下,那么企业利润必须增长8.68%以上。

情况就是这么个情况。总之,我们已经进入了『无人区』,没有数据可以利用了。

本文代码可以匡醍研究平台运行和下载。