请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  数理科学 帖子:3354134 新帖:36

《用6个财务指标轻松选出好公司》中部分基本面选股指标的

爱德华发表于:5 月 10 日 06:11回复(1)

“趋势交易的奶爸”,近期其分享的《用6个财务指标轻松选出好公司》等系列文章对部分基本面指标进行了介绍,但暂未说明其具体的计算实现方式。为学习Python和JQ平台编程,个人尝试利用JQ研究模块对其中部分指标进行了实现,详情见下。作为初学者,疏漏错误在所难免,还望方家指正。

(《用6个财务指标轻松选出好公司》参见:

部分基本面选股指标的计算¶

指标来源:微信公众号“奶爸后花园”《用6个财务指标轻松选出好公司》等系列文章。

1.季度指标,包括:ROE、毛利率、营业收入增长率、总资产周转率、现金收入比,分别计算当前季度指标值、过去8个季度平均值、过去8个季度达标率(N个报告期指标值超过阈值的比例),以及行业排名值(最低排名值为0,最高排名值为1)。
2.年度指标,包括:人均创收、人均创利,计算指定年度指标值和行业排名值。
3.防踩雷类指标,包括:商誉净资产比,计算当前指标值。
4.按证监会行业,逐行业对所有A股进行计算,形成汇总表:
证券代码  指标1达标比例 指标1达标比例行业排名 指标1均值 指标1均值行业排名 ……
5.结果存为csv文件,可供进一步分析使用。

version : 01.01
1.add_rank函数改为使用Series.rank()
2.指标列名改为中文
import datetime as dtimport randomimport numpy as npimport pandas as pdfrom pandas import Series, DataFrameimport talib as tlbimport matplotlib.pyplot as pltfrom jqdata import gtaimport randomimport jsonimport pdbfrom sqlalchemy import desc
############################################################################Utilities###########################################################################def now_to_statDate():'''将当前时间转为statDate('2017q2')    '''now = dt.datetime.now()year = now.yearmonth = now.monthif month >=1 and month <=3:quarter = 'q1'elif month >= 4 and month <= 6:quarter = 'q2'elif month >= 7 and month <= 9:quarter = 'q3'else:quarter = 'q4'return str(year) + quarterdef get_prev_statDate(statDate):'''传入一个statDate(如'2017q2'),返回上一个季度对应statDate    '''year = int(statDate[:4])quarter = int(statDate[5])if quarter == 1:prev_year = year - 1prev_quarter = 4else:prev_year = yearprev_quarter = quarter - 1return str(prev_year)+'q'+str(prev_quarter)#end def
###########################################################################计算指标的函数#将在calc_UTTR_and_*G中调用##########################################################################def calc_CRR(sec_list, statDate):'''计算现金收入比 Cash to Revenue Ratio    现金收入比 = 销售商品、提供劳务收到的现金 / 营业收入        输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:         index: 证券代码        columns: 现金收入比    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]q = query(indicator.code,indicator.goods_sale_and_service_to_revenue.label('现金收入比'),).filter(indicator.code.in_(sec_list),)df = get_fundamentals(q, statDate=statDate)df.set_index('code', inplace=True)return df#end defdef calc_ROE(sec_list, statDate):'''计算净资产收益率(ROE)       输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:        index:证券代码        columns: ROE    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]q = query(indicator.code,indicator.roe.label('ROE'),).filter(indicator.code.in_(sec_list),)df = get_fundamentals(q, statDate=statDate)df.set_index('code', inplace=True)return df#end defdef calc_TATR(sec_list, statDate):'''计算总资产周转率(Total Assets Turnover Ratio)       输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:        index:证券代码        columns: 总资产周转率    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]#期初资产总额begin_quarter = str(int(statDate[:4]) - 1) + 'q4'q = query(balance.code,balance.statDate.label('begin_date'),balance.total_assets.label('begin_assets'),).filter(balance.code.in_(sec_list),)begin_df = get_fundamentals(q, statDate=begin_quarter)begin_df.set_index('code', inplace=True)#期末资产总额、营业收入q = query(balance.code,balance.statDate.label('end_date'),balance.total_assets.label('end_assets'),income.operating_revenue,).filter(balance.code.in_(sec_list),)end_df = get_fundamentals(q, statDate=statDate)end_df.set_index('code', inplace=True)#总资产周转率 = 营业收入÷平均资产总额#其中:平均资产总额 =(期初资产总额+期末资产总额)÷2ret_df = begin_df.join(end_df, how='inner')ret_df['总资产周转率'] = ret_df['operating_revenue'] / ((ret_df['begin_assets'] + ret_df['end_assets']) / 2)
   return ret_df.loc[:, ['总资产周转率']]#end defdef calc_IR(sec_list, statDate):'''季度营业收入增长率(inc_revenue_year_on_year)       输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:        index:证券代码        columns: 营业收入增长率    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]q = query(indicator.code,indicator.inc_revenue_year_on_year.label('营业收入增长率'),).filter(indicator.code.in_(sec_list),)df = get_fundamentals(q, statDate=statDate)df.set_index('code', inplace=True)return df#end defdef calc_GPM(sec_list, statDate):'''计算季度销售毛利率(gross_profit_margin)       输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:        index:证券代码        columns: 毛利率    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]q = query(indicator.code,indicator.gross_profit_margin.label('毛利率'),).filter(indicator.code.in_(sec_list),)df = get_fundamentals(q, statDate=statDate)df.set_index('code', inplace=True)return df#end def
#%xdel calc_TATR
#calc_GPM(['601318.XSHG', '000651.XSHE'], '2017q3')
###########################################################################计算指标达标比例和指标均值的函数##########################################################################
def calc_UTTR_and_*G(sec_list, statDate,  ind_func, ind_thres,  qt_num=8, min_qt_num=4):'''计算指标达标率和平均值:    1.UTTR(Up To Threshold Ratio):最近N个季度中指标值超过阈值的比例    2.*G:最近N个季度指标+*1值的平均值        输入:        sec_list:证券代码列表        statDate:财报统计的季度或者年份,见get_fundamentals()        ind_func:计算指标的函数,返回以证券代码为index、第0列为指标值的DataFrame        ind_thres:指标阈值        qt_num:考察最近qt_num个季度率数据(如没有qt_num期季报,则能取多少取多少)        min_qt_num:至少要有min_qt_num个季度的数据,否则返回NAN    输出:一个DataFrame:        index:证券代码        columns: 季度指标值(最近一个有数据的季度)  均值 达标率       '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]ind_dict = dict()  # sec_id : [本季度增长率,前1季度增长率, 前2季度增长率……]#获取最近qt_num个季度增长率数据(保险起见尝试获取qt_num+2个季度数据)for i in range(qt_num+2):#获取一个季度的指标值df = ind_func(sec_list, statDate)ind_name = df.columns[0]#记录指标值for sec_id in df.index:ind_v = float(df[ind_name][sec_id])if sec_id not in ind_dict:ind_dict[sec_id] = [ind_v]else:ind_dict[sec_id].append(ind_v)#获取上一个季度的statDatestatDate = get_prev_statDate(statDate)#计算并记录结果    ret_df = pd.DataFrame(index=ind_dict.keys(), 
                          columns=[ind_name, 
                                   ind_name+'_均值', ind_name+'_达标率'])for sec_id, ind_list in ind_dict.items():#获取非nan值ind_array = np.array(ind_list)ind_array = ind_array[~np.isnan(ind_array)]if len(ind_array) > 0:ret_df[ind_name][sec_id] = ind_array[0]  # 最近一期季报指标值else:ret_df[ind_name][sec_id] = np.NaNif len(ind_array) < min_qt_num:  # 取到的数据太少,返回np.NaN            ret_df[ind_name+'_达标率'][sec_id] = np.NaNret_df[ind_name+'_均值'][sec_id] = np.NaNelse:if len(ind_array) > qt_num:  # 取到的数据多于qt_num个,则只取qt_num个ind_array = ind_array[:qt_num]ret_df[ind_name+'_达标率'][sec_id] = \count_nonzero(ind_array>ind_thres) / len(ind_array)ret_df[ind_name+'_均值'][sec_id] = np.nanmean(ind_array)return ret_df#end def
#%xdel calc_UTTR_and_*G
#temp_df = calc_UTTR_and_*G(['600000', '600010','600011'], '2017q3', calc_CRR, 100)
#temp_df
############################################################################其他指标计算函数(不适用calc_UTTR_and_*G计算的指标)###########################################################################
def get_staff_num(sec_list, statDate=None):'''获得企业员工人数。        输入:        sec_list:证券代码列表        statDate:财报年份,如'2016'            输出:一个dict:        键:证券代码        值:员工人数    '''if statDate is None:year = dt.datetime.now().yearelse:year = int(statDate)years = [str(year), str(year-1), str(year-2)]  #最近3年    years = [year+'-12-31' for year in years]  #转为GTA表中ENDDATEsymbols = [normalize_code(sec)[:6] for sec in sec_list]  # GTA SYMBOLq = query(gta.STK_MANAGE_STRUCTURE.SYMBOL,gta.STK_MANAGE_STRUCTURE.ENDDATE,  # 报告期gta.STK_MANAGE_STRUCTURE.STAFFNUMBER,  # 员工人数).filter(gta.STK_MANAGE_STRUCTURE.SYMBOL.in_(symbols),gta.STK_MANAGE_STRUCTURE.ENDDATE.in_(years),  #尝试取最近3年年报,防止数据过多).order_by(desc(gta.STK_MANAGE_STRUCTURE.ENDDATE),   #最近的年报数据放在前面)sn_df = gta.run_query(q).dropna()sn_dict = dict()found_num = 0#从前往后记录员工人数#sn_df已按时间排序,某只股票第一次出现时的STAFFNUMBER是就是最新的数据for i in sn_df.index:  sec = normalize_code(sn_df.loc[i, 'SYMBOL'])stf_num = int(float(sn_df.loc[i, 'STAFFNUMBER']))if sec not in sn_dict:sn_dict[sec] = stf_numfound_num += 1#else: 后面如还有其他更早年份的数据,不再记录if found_num == len(sec_list):  #已为sec_list中所有股票找到员工人数breakreturn sn_dict#end def
#%xdel get_staff_num
#get_staff_num(['600000', '600010', '002662'], '2014')
def calc_RP_PP(sec_list, statDate):'''计算人均创收和人均创利(Revenue per Person, Profit per Person)       输入:        sec_list:证券代码列表        statDate:财报统计年份(只能按年度计算),如'2016'    返回:一个DataFrame:        index:证券代码        columns:RP, PP  # 人均营业收入(元/人),人均净利润(元/人)    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]
 #获取营业收入和净利润q = query(income.code,income.operating_revenue,income.net_profit,).filter(income.code.in_(sec_list),)ret_df = get_fundamentals(q, statDate=statDate)ret_df.set_index('code', inplace=True)ret_df.columns = ['人均创收', '人均创利']#获取企业员工人数sn_dict = get_staff_num(sec_list, statDate=statDate)#计算人均创收和人均创利for i in range(len(ret_df)):sec_id = ret_df.index[i]if sec_id in sn_dict:stf_num = sn_dict[sec_id]  #该股票对应企业的员工人数ret_df['人均创收'][sec_id] = int(ret_df['人均创收'][sec_id] / stf_num)ret_df['人均创利'][sec_id] = int(ret_df['人均创利'][sec_id] / stf_num)else:ret_df['人均创收'][sec_id] = np.NaNret_df['人均创利'][sec_id] = np.NaN     
    return ret_df#end def
#%xdel calc_RP_PP
#calc_RP_PP(['600000', '600010'], '2016')
def calc_GWE(sec_list, statDate=None):'''计算商誉净资产比(商誉 / 归属于母公司股东权益)       输入:        sec_list:证券代码列表        statDate:财报统计的季度,见get_fundamentals()    返回:一个DataFrame:        index:证券代码        columns: 商誉净资产比    '''#证券代码格式转换sec_list = [normalize_code(sec) for sec in sec_list]q = query(balance.code,balance.good_will,balance.equities_parent_company_owners,).filter(balance.code.in_(sec_list),)df = get_fundamentals(q, statDate=statDate).fillna(0)df['商誉净资产比'] = df['good_will'] / df['equities_parent_company_owners']df.set_index('code', inplace=True)return df.loc[:, ['商誉净资产比']]#end def
#%xdel calc_GWE
#calc_GWE(['300058', '600010'])
###########################################################################计算指标的行业排名##########################################################################def add_rank(ind_df):'''为ind_df中的每个指标列添加一个排名列        输入:        ind_df:一个DataFrame:            index:证券代码            columns:指标1 指标2 ...     返回:一个DataFrame:        index:证券代码        columns:指标1  行业排名值 指标2 行业排名值 ...    '''ret_df = ind_df.copy()sec_num = len(ind_df)for col_name in ind_df.columns:#计算指标行业排名#最小排名值调整为0,最大排名值调整为1#nan值不参与排名s = ret_df[col_name].dropna()s_rank = (s.rank(method='min') - 1) / (len(s) - 1)#添加排名列rank_col_index = ret_df.columns.get_loc(col_name) + 1  #添加到指标列后面rank_col_name = col_name + '_行业排名'ret_df.insert(rank_col_index, rank_col_name,s_rank)return ret_df#end def
#%xdel add_rank
############################################################################计算全部股票的指标数据(指标值、UTTR、*G、行业排名分位数),按证监会行业进行计算###########################################################################def process_all_by_industry(industry_list, calc_params_list, statDate=None,extra_date='2016' 
                           ):'''依次对每个行业的股票进行处理,然后合并成一张全表        输入:        industry_list:行业代码列表        calc_params_list:计算各指标所需参数,用于calc_UTTR_and_*G函数:                        [[ind_func, ind_thres, qt_num, min_qt_num]]        statDate:季度指标的计算时期(如'2017q3'),如为None则使用当前季度。                  用于calc_UTTR_and_*G。        extra_date:年度指标的计算时期(如'2016')。           输出:一个DataFrame:        index:证券代码        columns:指标1 指标1_UTTR 指标1_*G 指标1_rank 指标1_UTTR_rank 指标1_*G_rank ...        '''if statDate is None:statDate = now_to_statDate()ret_df = pd.DataFrame()#处理每个行业for industry in industry_list:sec_list = get_industry_stocks(industry, date=None)industry_df = pd.DataFrame(index=sec_list)#获取股票中文名称name_map = map(lambda code : get_security_info(code).display_name, 
                       industry_df.index)        industry_df['名称'] = list(name_map)#1. 用calc_UTTR_and_*G处理的指标for calc_params in calc_params_list:#计算该行业股票的某种指标的相关数据temp_df = calc_UTTR_and_*G(sec_list, statDate, *calc_params)#增加行业排名数据temp_df = add_rank(temp_df)#合并所有指标数据industry_df = pd.concat([industry_df, temp_df], axis=1)#2.不适用calc_UTTR_and_*G的指标#人均创收、人均创利temp_df = calc_RP_PP(sec_list, extra_date)temp_df = add_rank(temp_df)industry_df = pd.concat([industry_df, temp_df], axis=1)#3.防踩雷类指标,只取最新值,不计算行业排名分位数#商誉净资产比temp_df = calc_GWE(sec_list)industry_df = pd.concat([industry_df, temp_df], axis=1)
            #合并所有行业ret_df = pd.concat([ret_df, industry_df])return ret_df#end def
#%xdel process_all_by_industry
############################################################################ main###########################################################################
#证监会行业代码列表HY_ZJH = ['A01','A02','A03','A04','A05','B06','B07','B08','B09','B11',  'C13','C14','C15','C17','C18','C19','C20','C21','C22','C23',  'C24','C25','C26','C27','C28','C29','C30','C31','C32','C33',  'C34','C35','C36','C37','C38','C39','*0','*1','*2','D44',  'D45','D46','E47','E48','E50','F51','F52','G53','G54','G55',  'G56','G58','G59','H61','H62','I63','I64','I65','J66','J67',  'J68','J69','K70','L71','L72','M73','M74','N77','N78','P82',  'Q83','R85','R86','R87','S90']
#各指标计算参数列表,用于calc_UTTR_and_*G调用。参数包括:#  指标计算函数(需预先实现),阈值(用于计算达标率),#  季报期数(缺省为8),最小季报期数(缺省为4)indicator_params = [[calc_ROE, 15],[calc_GPM, 20],[calc_CRR, 99],[calc_TATR,99],[calc_IR, 15],        ]
t_df = process_all_by_industry(HY_ZJH, indicator_params)
len(t_df)
3461
t_df.loc['002662.XSHE']
名称                       京威股份
ROE                    1.2704
ROE_行业排名             0.362069
ROE_均值               2.725388
ROE_均值_行业排名         0.5483871
ROE_达标率                     0
ROE_达标率_行业排名                0
毛利率                    26.365
毛利率_行业排名            0.6637931
毛利率_均值               29.25005
毛利率_均值_行业排名         0.7849462
毛利率_达标率                     1
毛利率_达标率_行业排名        0.6129032
现金收入比                100.0468
现金收入比_行业排名          0.6551724
现金收入比_均值              98.9316
现金收入比_均值_行业排名       0.6989247
现金收入比_达标率                 0.5
现金收入比_达标率_行业排名      0.6451613
总资产周转率              0.1388717
总资产周转率_行业排名         0.4020619
总资产周转率_均值           0.1576029
总资产周转率_均值_行业排名      0.4204545
总资产周转率_达标率                  0
总资产周转率_达标率_行业排名             0
营业收入增长率               11.0573
营业收入增长率_行业排名         0.387931
营业收入增长率_均值           25.54958
营业收入增长率_均值_行业排名     0.6344086
营业收入增长率_达标率              0.75
营业收入增长率_达标率_行业排名    0.7419355
人均创收                   481473
人均创收_行业排名           0.1752577
人均创利                    64695
人均创利_行业排名           0.5257732
商誉净资产比              0.2172216
Name: 002662.XSHE, dtype: object
#记录数据文件file_name = %pwdfile_name += '/基本面指标.csv't_df.to_csv(file_name, float_format='%.2f')

全部回复

0/140

达人推荐

量化课程

    移动端课程