目录
罗杰‧金(Roger E. King)是美国知名的价值型基金经理人,曾任职太阳保险服务公司(Sun Insurance Services)的资深副总裁兼投资长及葛夫科资本管理公司(GULFCO Investment Management)的资深副总裁,1981年创立国王投资顾问公司(King Investment Advisors Inc.),至2001年,投资经历长达30年。
原本国王投资顾问公司只管理机构投资者的资金与个人退休基金,1996年底才发行第一档股票共同基金-源头特别价值基金(Fountainhead Special Value Fund),1997年即一鸣惊人,获得36.65%的投资报酬率,1999年投资报酬率达133.44%,2000年虽股市表现不佳,但基金绩效只损失15.71%,至2001年5月止,3年平均报酬率达18.22%,超越同期S&P500指数表现12.92个百分点,因此获得晨星公司(Morningstar Co.)基金评等5颗星的评价,投资绩效表现非常优异。
他自行研发一种称为『企业评价方法(Business Valuation Approach)』的选股策略,以由下而上(bottom up)的选股方式为主,分为三种价值评估方式:
(一)私有市场评价(Private-market Valuation,Liquidation or acquired in a cash transaction);
(二)历史评价(Historical Valuation);
(三)优越的盈余成长(Superior Earning Growth,Buy growth at a reduced price:GARP)
三种方法所选出的公司皆可为投资标的,再以财务强度及内部人进出等指标进行筛选;虽然罗杰‧金被市场定位为价值型投资者,但他强调并不排斥买进具有投资价值的成长股,他在接受媒体专访时曾表示『投资成功的秘诀在于买到便宜的价格(The secret of success is to buy at an inexpensive price),本次介绍的是第二种选股方法「历史评价」。
选股程序及标准:以七年历史资料为期,计算以下指标的状况,判断目前股价上涨空间(Potential Upside)及下档风险(Potential Downside)。
历史最高本益比平均及最低本益比平均。
历史最高股价净值比平均及最低股价净值比平均。
历史最高股价现金流量比平均及最低股价现金流量比平均。
历史最高股价营收比平均及最低股价营收比平均。
坚强的财务状况。
内部人进出的状况。
从上面指标选择的项目可以看到,罗杰‧金先找出每年的当年度本益比最大值与最小值,然后分别取平均值,计算出选股时点本益比的上下限;接著纳入股价净值比、现金流量、营收等基本面常见指标,以相同的方式计算出各指标与股价间比例的上下限。借由多个基本面指标设算出的股价的上下档目标价,并且以目前股价较接近上档目标价或下档目标价,来判断是否该买入此股票。
⬇️ 因应时空背景的转换,我们对上列条件进行了调整与修正⬇️
选股程序及标准:选定历史资料使用年数为7年。
历史本益比上档目标价=最近7个年度最高本益比平均值x最近一季每股盈余。
历史本益比下档目标价=最近7个年度最低本益比平均值x最近一季每股盈余。
历史股价净值比上档目标价=最近7个年度最高股价净值比平均值x最近一季每股净值。
历史股价净值比下档目标价=最近7个年度最低股价净值比平均值x最近一季每股净值。
历史股价现金流量比上档目标价=最近7个年度最高股价现金流量比平均值x最近四季每股现金流量。
历史股价现金流量比下档目标价=最近7个年度最低股价现金流量比平均值x最近四季每股现金流量。
历史股价营收比上档目标价=最近7个年度最高股价营收比平均值x最近12个月每股营收总额。
历史股价营收比下档目标价=最近7个年度最低股价营收比平均值x最近12个月每股营收总额。
以下四个选股标准,即是计算当前股价,是否较接近该指标所算出的下档目标价,较接近者就代表价格偏移长期行情的中间值,值得买入。
历史本益比报酬/风险值=[(历史本益比上档目标价-目前股价)/目前股价]/ [(目前股价-历史本益比下档目标价)/目前股价]>1。
历史股价净值比报酬/风险值=[(历史股价净值比上档目标价-目前股价)/目前股价]/ [ (目前股价-历史股价净值比下档目标价)/目前股价]>1。
历史股价现金流量比报酬/风险值=[(历史股价现金流量比上档目标价-目前股价)/目前股价]/ [ (目前股价-历史股价现金流量比下档目标价)/目前股价]>1。
历史股价营收比报酬/风险值=[(历史股价营收比上档目标价-目前股价)/目前股价]/[ (目前股价-历史股价营收比下档目标价)/目前股价]>1。
以上4项指标,符合1项即为选股标的。再以下面条件过滤筛选:
剃除选股时间点近一季负债比率大于65%的公司。
按照罗杰金的选股标准「历史本益比报酬/风险值」,其实计算的就是股价距离下档目标价的距离,是否比距离上档目标价来的短,也就是股价目前按照长期均势的本益比来看,是否偏低,若是,就可以买进。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn')
import tejapi
tejapi.ApiConfig.api_key = 'your_key'
tejapi.ApiConfig.ignoretz = True
# 获取上市普通股代码 #
stk_info = tejapi.get('TWN/ANPRCSTD',
paginate=True,
chinese_column_name=True
)
stk_nums = stk_info[(stk_info['上市别']=='TSE') & (stk_info['证券种类名称']=='普通股')]['证券码'].to_list()
# 捞取财务资料 #
zz = pd.DataFrame()
for code in stk_nums:
zz = zz.append(
tejapi.get('TWN/AIM1A',
coid=code,
paginate=True,
chinese_column_name=True,
opts= {'pivot':True,'columns':['coid','mdate','200D','R535','R505','R303','R304','MV']}).reset_index(drop=True)
).reset_index(drop=True)
print(code)
Tips : 如何搜寻想要的栏位代号,输入关键字,并运行下方程式码,即可找出相对应的栏位代号~
# IFRS财务会计科目说明档 #
acc = tejapi.get(‘TWN/AIACC’,paginate=True)
# 搜寻栏位代码 #
key_word = '输入关键字'
acc[acc[‘cname’].str.find(key_word)!=-1]
2010年12月底的本益比(PE), 股价净值比(PB), 股价现金流量(PC)和股价营收比(PS),由财报在发布上有落后的情况,因此上述指标的运算皆使用2010-3-31至2011-3-31的股价资料进行计算。
下方程式码功能为计算个年度本益比(PE), 股价净值比(PB), 股价现金流量(PC)和股价营收比(PS)之最高和最低值。
PS. 由于资料量较大,程式运行时间也较久大约30~40分钟
results = pd.DataFrame()
#coid = str(1101)
for coid in data['公司代码'].unique():
stock = tejapi.get('TWN/APRCD1',coid = coid, chinese_column_name = True)
for year in data['year'].unique():
condition = (data['year']==year) & (data['公司代码']== coid)
if (data[condition].size !=0):
indicator_start = data['indicator_start'][condition].to_list()[0]
stk_start = data['start'][condition].to_list()[0]
stk_end = data['end'][condition].to_list()[0]
# 抓取财报季度前一年的资料 #
selected = stock[(stock['年月日'] > indicator_start) & (stock['年月日'] < stk_start)].reset_index(drop=True)
back_test = stock[(stock['年月日'] >= stk_start) & (stock['年月日'] < stk_end)].reset_index(drop=True)
if (selected.size!=0) and (back_test.size!=0):
# 计算个年度最高与最低 本益比、股价净值比、股价现金流量比和股价营收比 #
price = selected['收盘价(元)'].tail(1).to_list()[0]
stk_start_price = back_test['收盘价(元)'].head(1).to_list()[0]
## 本益比 ##
EPS = data['常续性EPS'][condition].to_list()[0]
PE = selected['收盘价(元)']/EPS
PE_max = PE.max()
PE_min = PE.min()
## 股价净值比 ##
BV = data['每股净值(F)-TSE公告数'][condition].to_list()[0]
PB = selected['收盘价(元)']/BV
PB_max = PB.max()
PB_min = PB.min()
## 股价现金流量比 ##
CFP = data['每股现金流量'][condition].to_list()[0]
PC = selected['收盘价(元)']/CFP
PC_max = PC.max()
PC_min = PC.min()
## 股价营收比 ##
SP = data['每股营业额'][condition].to_list()[0]
PS = selected['收盘价(元)']/SP
PS_max = PS.max()
PS_min = PS.min()
# 汇整 #
result = pd.DataFrame({
'year':year,
'公司代码':coid,
'stk_start':stk_start,
'stk_end':stk_end,
'stk_start_price':stk_start_price,
'PE_max':PE_max,'PE_min':PE_min,
'PB_max':PB_max,'PB_min':PB_min,
'PC_max':PC_max,'PC_min':PC_min,
'PS_max':PS_max,'PS_min':PS_min
},index=[0])
results = results.append(result).reset_index(drop=True)
print(coid)
根据上面得到的结果针对本益比(PE), 股价净值比(PB), 股价现金流量(PC)和股价营收比(PS)进行7年移动平均计算,并将当期的EPS、每股净值、每股现金流量和每股营收合并,即可得出当前的最高目标价和最低目标价。最后再进一步求算出风险报酬比。
mean_7 = results.groupby(by=['公司代码']).rolling(7).mean()[['PE_max','PE_min','PB_max','PB_min','PC_max','PC_min','PS_max','PS_min']]
mean_7 = mean_7.reset_index(drop=True)
mean_7['year'],mean_7['公司代码'],mean_7['stk_start_price'] = results['year'], results['公司代码'],results['stk_start_price']
# 合并 #
mean_7 = pd.merge(mean_7.dropna(),data,on=['公司代码','year'])
# 去除市值小于中位数者 #
mean_7 = mean_7[(mean_7['季底普通股市值']>mean_7['mv_median'])].reset_index(drop=True)
筛选条件
历史本益比报酬/风险值=[(历史本益比上档目标价-目前股价)/目前股价]/ [(目前股价-历史本益比下档目标价)/目前股价]>1。
历史股价净值比报酬/风险值=[(历史股价净值比上档目标价-目前股价)/目前股价]/ [ (目前股价-历史股价净值比下档目标价)/目前股价]>1。
历史股价现金流量比报酬/风险值=[(历史股价现金流量比上档目标价-目前股价)/目前股价]/ [ (目前股价-历史股价现金流量比下档目标价)/目前股价]>1。
历史股价营收比报酬/风险值=[(历史股价营收比上档目标价-目前股价)/目前股价]/[ (目前股价-历史股价营收比下档目标价)/目前股价]>1。
以上4项指标,符合1项即为选股标的。再以下面条件过滤筛选:
剃除选股时间点近一季负债比率大于65%的公司。
# 目标价计算 #
## 本益比 ##
mean_7['PE_TP_upper'] = mean_7['PE_max']*mean_7['常续性EPS']
mean_7['PE_TP_bottom'] = mean_7['PE_min']*mean_7['常续性EPS']
mean_7['PE_ret_risk'] = (mean_7['PE_TP_upper']-mean_7['stk_start_price'])/(mean_7['stk_start_price']-mean_7['PE_TP_bottom'])
## 股价净值比 ##
mean_7['PB_TP_upper'] = mean_7['PB_max']*mean_7['每股净值(F)-TSE公告数']
mean_7['PB_TP_bottom'] = mean_7['PB_min']*mean_7['每股净值(F)-TSE公告数']
mean_7['PB_ret_risk'] = (mean_7['PB_TP_upper']-mean_7['stk_start_price'])/(mean_7['stk_start_price']-mean_7['PB_TP_bottom'])
## 股价现金流量比 ##
mean_7['PC_TP_upper'] = mean_7['PC_max']*mean_7['每股现金流量']
mean_7['PC_TP_bottom'] = mean_7['PC_min']*mean_7['每股现金流量']
mean_7['PC_ret_risk'] = (mean_7['PC_TP_upper']-mean_7['stk_start_price'])/(mean_7['stk_start_price']-mean_7['PC_TP_bottom'])
## 本益比 ##
mean_7['PS_TP_upper'] = mean_7['PS_max']*mean_7['每股营业额']
mean_7['PS_TP_bottom'] = mean_7['PS_min']*mean_7['每股营业额']
mean_7['PS_ret_risk'] = (mean_7['PS_TP_upper']-mean_7['stk_start_price'])/(mean_7['stk_start_price']-mean_7['PS_TP_bottom'])
# 评分 #
mean_7.loc[:,'score'] = 0
mean_7['score'] = np.where(mean_7['PE_ret_risk'] > 1, 1+mean_7['score'], mean_7['score'])
mean_7['score'] = np.where(mean_7['PB_ret_risk'] > 1, 1+mean_7['score'], mean_7['score'])
mean_7['score'] = np.where(mean_7['PC_ret_risk'] > 1, 1+mean_7['score'], mean_7['score'])
mean_7['score'] = np.where(mean_7['PS_ret_risk'] > 1, 1+mean_7['score'], mean_7['score'])
%%time
return_=pd.DataFrame()
for year in range(2011,2020):
pf = mean_7[(mean_7['year']==year) & (mean_7['负债比率'] < 65) & (mean_7['score']>=1)]#.sort_values(by = 'score', ascending = False).reset_index(drop=True)
## 将买进日期设在季底+90日 ##
buy_date = mean_7['start'][mean_7['year']==year].head(1).to_list()[0]
sell_date = mean_7['end'][mean_7['year']==year].head(1).to_list()[0]
ret = pd.DataFrame()
pf_H = pf['公司代码'].to_list()
print('投资组合共有{}档股票'.format(len(pf_H)))
## 自 tejapi捞取日报酬资料,日期设定为 buy_date(不含)至 sell_date(含) ##
print('getting data')
stk_data = tejapi.get('TWN/APRCD2',
coid = pf_H,
paginate = True,
mdate={'gt':buy_date,'lt':sell_date},
chinese_column_name=True)
# 计算报酬率 #
print('calculating return')
pf_ret = stk_data.groupby(by = '年月日').mean()['日报酬率 %']
pf_ret = pf_ret.reset_index(drop=True)
# ret[ranking[i]] = pf_ret
ret['portfolio'] = pf_ret
# i+=1
## 捞取台湾加权指数的日报酬率,日期设定为 buy_date(不含)至 sell_date(不含) ##
twse = tejapi.get('TWN/APRCD2',coid ='Y9999' ,paginate = True,mdate={'gt':buy_date,'lt':sell_date},chinese_column_name=True)
bm_return = twse.groupby('年月日').mean()['日报酬率 %'].reset_index(drop=True)
ret['twse_return'] = bm_return
ret['Date'] = twse['年月日']
return_ = return_.append(ret).reset_index(drop=True)
print(return_)
cum_ret = return_[['portfolio','twse_return']].astype(float).apply(lambda x:x*0.01+1).cumprod().reset_index(drop=True)
cum_ret['Date'] = return_['Date']
cum_ret
cum_ret.plot(x='Date',figsize=(10,6))
# 绩效报表 #
yearly_mean_ret = (((cum_ret[['portfolio','twse_return']].tail(1)**(1/len(cum_ret)))**252-1)*100).reset_index(drop=True)
yearly_std = cum_ret[['portfolio','twse_return']].std()*(252**(0.5))
Rf = 1
sp_ratio = (yearly_mean_ret-Rf)/yearly_std
roll_max = cum_ret[['portfolio','twse_return']].cummax()
draw_down = (cum_ret[['portfolio','twse_return']]-roll_max)/roll_max
MDD = draw_down.min()*100
performace_report = pd.DataFrame({
'portfolio':[yearly_mean_ret['portfolio'].values[0],
yearly_std['portfolio'],
sp_ratio['portfolio'].values[0],
MDD['portfolio']],
'twse_return':[yearly_mean_ret['twse_return'].values[0],
yearly_std['twse_return'],
sp_ratio['twse_return'].values[0],
MDD['twse_return']]}
,index= ['年化报酬','年化波动度','夏普指标','最大回档'])
performace_report
pf2020 = mean_7[(mean_7['year']==2020) & (mean_7['负债比率'] < 65) & (mean_7['score']>=1)]['公司代码'].to_list()
stk_info[['证券码','证券名称']][stk_info['证券码'].isin(pf2020)].reset_index(drop=True)
由报酬率来看,我们的投资组合确实胜过大盘指数,但将风险纳入考虑之后,可以看出台湾加权指数分别在波动度、夏普指标和最大回档皆胜过我们的投资组合😢😢。
这次的罗杰.金的策略在报酬上只有险胜大盘指数一点,是不是相当意外阿~不过,会出现这样的结果也不必太过惊讶,毕竟投资领域上并无一个长期稳定的圣杯,所有的条件都应该随著时间进行动态调整 👍👍
重要的是我们如何从这些过往的投资大师身上汲取经验和刺激想法,最后经过自己的一番练化,去芜存菁,建构出适合自己的投资策略😄,
我们将在下期继续分享三一资产管理公司的投资策略,敬请期待!!
最后,如果喜欢本篇文章的内容请帮我们点击下方图示👏 ,给予我们更多支持与鼓励,有任何的问题都欢迎在下方留言/来信,我们会尽快回复大家👍👍
想要一个"稳定""品质高""资料长度长"的资料源该怎么办呢?TEJ API就是你最好的选择!!