檢驗pe_ratio的值¶
緣由¶
經常看到策略里需要用到pe,pb等基本面指標來進行選股, 可是如何才能得到一個合理的正確的pe呢?
別忘了, 這里涉及到一堆的資料需要收集: 包括4個連續的季報的eps, 還有最後一個季報的發布日期, 還有一個我們查詢估值表里的pe時的交易日期/查詢日期以及原始的收盤價等數據. 因為公司發布的季報的日期通常都會遲後於要查詢的日期一個月甚至5個月以上, 所以必須謹慎對待.
好在聚寬的數據庫里直接提供了該數據的查詢. 但是我想依據它的算法求證一下數據的可信度.
計算公式¶
- 估值表里的pe_ratio列, 應該就是通常說的pe_ttm. 十二個月的滾動市盈率.
依據聚寬API文檔里的計算公式, 應該是這樣的:
市盈率(PE,TTM)=(股票在指定交易日期的收盤價 * 截止當日公司總股本)/歸屬於母公司股東的淨利潤TTM。
變換一下:
PE_TTM = 指定交易日的收盤價(非複權的原始價格) / (該指定交易日之前的連續的4個單季度的eps之和)
今天就專注於談談pe_ttm版本的pe¶
ttm的字面含義: trailing twelve month, 十二個月滾動市盈率. 我們實際上是用以前的滾動的4個季度的財務指標以及查詢日當前價來計算該市盈率估值的. 另外還有: 動態市盈率和靜態市盈率, 市盈率I和市盈率II等多種版本.
代碼如下:¶
'''求出查詢日之前的連續的4個季度, 返回季度列表
'''
def get_statDate(date = '2019-08-24'):
# 年
year = int(date[:4])
# 月日
month_and_day = date[5:10]
# 季度列表
if month_and_day < '05-01':
statDate_list = [str(year-2) + "q4", str(year-1) + "q1", str(year-1) + "q2", str(year-1) + "q3"]
elif month_and_day >= '05-01' and month_and_day < '09-01':
statDate_list = [str(year-1) + "q2", str(year-1) + "q3", str(year-1) + "q4", str(year) + "q1"]
elif month_and_day >= '09-01' and month_and_day < '11-01':
statDate_list = [str(year-1) + "q3", str(year-1) + "q4", str(year) + "q1", str(year) + "q2"]
elif month_and_day >= '11-01':
statDate_list = [str(year-1) + "q4", str(year) + "q1", str(year) + "q2", str(year) + "q3"]
print ('\ndate={}, statDate={}'.format(date, statDate_list))
return statDate_list
''' 依據公式自己求出eps_ttm, 然後與聚寬的查詢結果對比, 然後打印結果
'''
codes = ['000069.XSHE']
date = '2019-08-24'
def validate_pe(codes=codes, date=date, ):
'''
'''
statDate = get_statDate(date)
q = query(
valuation.code,
income.basic_eps,
indicator.eps,
indicator.pubDate,
).filter(
valuation.code.in_(codes)
).order_by(
valuation.code.asc()
)
for sdate in statDate:
jbm_df = get_fundamentals(q,statDate=sdate,) # 基本面df
print(jbm_df)
eps_list = [get_fundamentals(q,statDate=sdate,).eps.values[0] for sdate in statDate]
now_p2 = get_price(codes[0], end_date=date, fq=None)['close'][-1]
now_p3 = get_price(codes[0], end_date=date, fq='post')['close'][-1]
now_p = get_price(codes[0], end_date=date, fq='pre')['close'][-1]
print('前複權價格, 原始成交價, 後複權價格分別是: {}, {}, {}'.format(now_p, now_p2, now_p3))
pe_ttm = now_p2 / sum(eps_list)
jbm_df = get_fundamentals(
query(
valuation.code,
valuation.pe_ratio,
).filter(
valuation.code.in_(codes)
),
date=date)
res = [round(pe_ttm,3), round(jbm_df.pe_ratio.values[0], 3)]
res.append(res[0] - res[1])
res = '代碼={}, 日期={}, TTM_PE(12個月滾動市盈率)={}, 直接讀取的pe_ratio={}, 相差= {}'.format(
codes[0], date, *res)
return res
拿4個不同的日期為示例, 檢驗一下:¶
print(validate_pe(codes, '2018-01-24'))
print(validate_pe(codes, '2017-01-24'))
print(validate_pe(codes, '2015-08-22'))
print(validate_pe(codes, '2015-01-24'))
8.8/(.124+.2697+.071+.1235)
結論:¶
4個時間點, 有三個對的上, 有一個對不上而且還差別不小. 讓人不敢認同呀. 有錯誤的地方, 敬請斧正. 歡迎探討.
date=2015-08-20, statDate=['2014q2', '2014q3', '2014q4', '2015q1']
code basic_eps eps pubDate
0 000069.XSHE 0.1711 0.1715 2014-08-26
code basic_eps eps pubDate
0 000069.XSHE 0.124 0.124 2014-10-22
code basic_eps eps pubDate
0 000069.XSHE 0.2696 0.2697 2015-03-21
code basic_eps eps pubDate
0 000069.XSHE 0.071 0.071 2015-04-21
前複權價格, 原始成交價, 後複權價格分別是: 8.36, 9.34, 363.3
代碼=000069.XSHE, 日期=2015-08-20, TTM_PE(12個月滾動市盈率)=14.681, 直接讀取的pe_ratio=15.884, 相差= -1.20300000012
date=2015-09-22, statDate=['2014q3', '2014q4', '2015q1', '2015q2']
code basic_eps eps pubDate
0 000069.XSHE 0.124 0.124 2014-10-22
code basic_eps eps pubDate
0 000069.XSHE 0.2696 0.2697 2015-03-21
code basic_eps eps pubDate
0 000069.XSHE 0.071 0.071 2015-04-21
code basic_eps eps pubDate
0 000069.XSHE 0.1235 0.1235 2015-08-20
前複權價格, 原始成交價, 後複權價格分別是: 6.76, 7.55, 293.67
代碼=000069.XSHE, 日期=2015-09-22, TTM_PE(12個月滾動市盈率)=12.836, 直接讀取的pe_ratio=12.84, 相差= -0.0039999999995
7.55/(.124+.2697+.071+.1235)
a.