跳到主要内容

公司财务与股价关系的研究分析

前述 #

通过IQSSS项目,目前有了一些发现。公司的股价和业绩息息相关,但并非业绩好的公司股价一定会上涨,而是要结合一些其他的指标。比如销售净利率、权益乘数、总资产周转率等。

观察了几个案例,发现如果一家公司的基本面有以下几点表现,那么其股价会大概率增长:

  1. 连续3年(至少3年)ROE实现稳定增长,并且在下一年的1季报中,业绩明显增加。
  2. 影响ROE增长的主要因素是销售净利率,其次是总资产周转率,权益乘数影响程度越低越好。
  3. 同业比较中,销售净利率和总资产周转率排名靠前。(没有太大关系)
  4. 市盈率低于行业平均水平,股息率最好高于行业平均水平。

如何理解第1条中的稳定。我期望公司的业绩表现,不会在某一年突飞猛进,而第二年虽有上涨,但相比前一年差很多。在之后的程序中可以这样定义:$$差值的平均数 / 最小值 <= 1.5$$

研究分析 #

ROE #

下面会根据第1条,将ROE连续3年实现增长的股票筛选出来。之后会进行第2次的过滤,将ROE增长不平稳的股票剔除。

# 获取roe数据
get_roe_data_sql = """
select ts_code,
       end_date_1,
       end_date_2,
       real_roe,
       profit_dedt,
       net_profit_margin,
       assets_to_eqt,
       assets_turn
from MR_DATA.m_dupont_analysis
"""
data_df = get_data(get_roe_data_sql)
data_df.sample(8)

ts_code end_date_1 end_date_2 real_roe profit_dedt net_profit_margin assets_to_eqt assets_turn
74442 002910.SZ 2020 年报 0.0072597931031880 3216161.7600 0.01412973 1.9352 0.2655
2322 000046.SZ 2016 二季报 0.0466280733413040 736946933.7300 0.07788008 6.5793 0.0910
151896 600726.SH 2007 三季报 0.0154970120240390 50669846.0900 0.02116310 2.7131 0.2699
122853 600167.SH 2011 二季报 0.0719605877624172 55633248.4600 0.23596364 2.3051 0.1323
75781 002966.SZ 2020 一季报 0.0295405487651648 781248000.0000 0.31073344 13.0229 0.0073
58130 002492.SZ 2017 年报 0.0496988066527680 50093093.9100 0.26505510 1.2878 0.1456
106309 300726.SZ 2018 三季报 0.1192661102848482 174034499.5900 0.37941747 1.0499 0.2994
4800 000403.SZ 2008 一季报 0.9994165376143712 1710818.2200 2.09571496 4.9316 0.0967
# 寻找连续3年roe持续增长的股票有哪些

# 定义结尾年份
end_year = 2018
# 定义统计的年数
years_number = 3
def  roe_filter(end_year, year_number):
    
    # 准备一个股票池
    symbols_filtered_1 = []
    symbols_filtered_1_bigger_10 = []


    # 获取年报数据
    data_df_annals = data_df[data_df['end_date_2'] == '年报']
    for name, grouper in data_df_annals.groupby(by='ts_code'):
        # 对数据按照年份逆序排序
        grouper.sort_values(by='end_date_1', ascending=False, inplace=True)
        # 重新定义index
        grouper.index = grouper['end_date_1']
        grouper['end_date_1'] = grouper['end_date_1'].astype(int)
        grouper['real_roe'] = grouper['real_roe'].astype(float)

        # 添加1条件:企业是否在历史上roe没有出现过负数
    #    # 考虑到可能由于公司改名的问题,会误删掉好公司,所以此处注释掉
        if grouper['real_roe'].min() > 0:
            roe_list = grouper[grouper['end_date_1'] <= end_year]['real_roe'].iloc[:years_number]
            if len(roe_list) == years_number:
                # 第1层过滤,寻找连续x年roe增长的企业
                if all(x>y for x, y in zip(roe_list, roe_list[1:])):
                    # 第2层过滤,寻找roe平稳增长的企业
                    diff_values_roe = abs(roe_list.diff().dropna())
                    # 如果差值的平均数 / 最小值  <= 1.5,说明roe平稳增长
                    if np.min(diff_values_roe) != 0 and np.average(diff_values_roe) / np.min(diff_values_roe) <= 1.5:
                        if roe_list[0] - roe_list[-1] >= 0.1:
                            symbols_filtered_1_bigger_10.append(name)
                        else:
                            symbols_filtered_1.append(name)
    print("以{}年为结尾,连续{}年ROE实现平稳增长的企业共发现{}家,其中这{}年中ROE涨幅至少为10%的企业共有{}家。".format(end_year,
                                                                               years_number, 
                                                                               len(symbols_filtered_1)+len(symbols_filtered_1_bigger_10),
                                                                               years_number,
                                                                               len(symbols_filtered_1_bigger_10)))
    return symbols_filtered_1, symbols_filtered_1_bigger_10
symbols_filtered_1, symbols_filtered_1_bigger_10 = roe_filter(end_year, years_number)

以2018年为结尾,连续3年ROE实现平稳增长的企业共发现213家,其中这3年中ROE涨幅至少为10%的企业共有54家。

经过2次过滤,现在已经得到一批ROE连续稳定增长的股票。

接下来需要在这些股票中找到下一年1季报中业绩大幅上涨的股票。

def profit_filter(symbols_filtered_1_bigger_10):

    # 准备第2个股票池
    symbols_filtered_2 = []
    symbols_3_quarter = []
    # 获取已筛选出的企业的下一年一季报数据
    # data_df_first_quarter = data_df[(data_df['end_date_2'] == '一季报') & (data_df['ts_code'].isin(symbols_filtered_1+symbols_filtered_1_bigger_15))]
    data_df_first_quarter = data_df[(data_df['end_date_2'] == '一季报') & (data_df['ts_code'].isin(symbols_filtered_1_bigger_10))]

    for name, grouper in data_df_first_quarter.groupby(by='ts_code'):
        # 对数据按照年份逆序排序
        grouper.sort_values(by='end_date_1', ascending=False, inplace=True)
        # 重新定义index
        grouper.index = grouper['end_date_1']
        grouper['end_date_1'] = grouper['end_date_1'].astype(int)
        grouper['profit_dedt'] = grouper['profit_dedt'].astype(float)

        profit_dedt_list = grouper[grouper['end_date_1'] <= end_year+1]['profit_dedt'].iloc[:2]

        if len(profit_dedt_list) == 2:
            # 如果1季度扣非净利润同比增加80%以上,说明公司运营良好
            if (profit_dedt_list[0] - profit_dedt_list[1]) / profit_dedt_list[1] >= 0.8:

                symbols_filtered_2.append(name)
    print("经过进一步的筛选,发现在下一年的1季报中,扣非净利润同比增长至少80%的股票有{}支".format(len(symbols_filtered_2)))
    return symbols_filtered_2
symbols_filtered_2 = profit_filter(symbols_filtered_1_bigger_10)

经过进一步的筛选,发现在下一年的1季报中,扣非净利润同比增长至少80%的股票有9支

symbols_filtered_2
['300122.SZ',
 '300428.SZ',
 '300770.SZ',
 '600025.SH',
 '600031.SH',
 '600673.SH',
 '600801.SH',
 '601100.SH',
 '688196.SH']

ROE贡献度 #

利用因素分析法,观察这些公司业绩中,销售净利率、权益乘数、总资产周转率这3个因素哪个贡献最大。

factor_analysis_df = factor_analysis(symbols_filtered_2)
2018年年报中,300122.SZ的ROE值较去年变化的值为25.58%
营业净利率变动的影响程度为-2.44%,贡献比例为-9.54%
权益乘数变动的影响程度为2.53%,贡献比例为9.89%
总资产周转率变动的影响程度为25.50%,贡献比例为99.69%
通过因素分析法,各因素的影响程度由大到小依次为:总资产周转率 --> 权益乘数 --> 营业净利率
300122.SZ在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,300428.SZ的ROE值较去年变化的值为8.19%
营业净利率变动的影响程度为-5.52%,贡献比例为-67.40%
权益乘数变动的影响程度为8.42%,贡献比例为102.81%
总资产周转率变动的影响程度为5.29%,贡献比例为64.59%
通过因素分析法,各因素的影响程度由大到小依次为:权益乘数 --> 总资产周转率 --> 营业净利率
300428.SZ在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,300770.SZ的ROE值较去年变化的值为9.76%
营业净利率变动的影响程度为6.56%,贡献比例为67.21%
权益乘数变动的影响程度为0.80%,贡献比例为8.20%
总资产周转率变动的影响程度为2.40%,贡献比例为24.59%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
300770.SZ在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,600025.SH的ROE值较去年变化的值为7.35%
营业净利率变动的影响程度为6.55%,贡献比例为89.12%
权益乘数变动的影响程度为-1.27%,贡献比例为-17.28%
总资产周转率变动的影响程度为2.07%,贡献比例为28.16%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
600025.SH在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,600031.SH的ROE值较去年变化的值为13.47%
营业净利率变动的影响程度为7.75%,贡献比例为57.54%
权益乘数变动的影响程度为0.45%,贡献比例为3.34%
总资产周转率变动的影响程度为5.27%,贡献比例为39.12%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
600031.SH在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,600673.SH的ROE值较去年变化的值为7.85%
营业净利率变动的影响程度为10.14%,贡献比例为129.17%
权益乘数变动的影响程度为-5.12%,贡献比例为-65.22%
总资产周转率变动的影响程度为2.83%,贡献比例为36.05%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
600673.SH在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,600801.SH的ROE值较去年变化的值为14.74%
营业净利率变动的影响程度为17.03%,贡献比例为115.54%
权益乘数变动的影响程度为-7.61%,贡献比例为-51.63%
总资产周转率变动的影响程度为5.33%,贡献比例为36.16%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
600801.SH在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2018年年报中,601100.SH的ROE值较去年变化的值为9.15%
营业净利率变动的影响程度为4.89%,贡献比例为53.44%
权益乘数变动的影响程度为-0.00%,贡献比例为-0.00%
总资产周转率变动的影响程度为4.26%,贡献比例为46.56%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
601100.SH在2019年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------

通过查看其未来200个交易日的股价走势,发现除了600673未来一段时期股价下跌(怀疑其是庄家股,因为成交量一直很低),其余7支都有很大幅度的上涨。其中300122、600031、601100在未来都有好几倍的涨幅。


按照上面这个思路,不妨再观察一组数据,看看我的猜想是否正确。

我们将2016年设置为起始年份,观察未来3年ROE明显上涨并且再2019年1季报中业绩表现很好的公司。


# 定义结尾年份
end_year = 2019
# 定义统计的年数
years_number = 3

symbols_filtered_1, symbols_filtered_1_bigger_10 = roe_filter(end_year, years_number)
symbols_filtered_2 = profit_filter(symbols_filtered_1_bigger_10)
print(symbols_filtered_2)
factor_analysis_df = factor_analysis(symbols_filtered_2)
以2019年为结尾,连续3年ROE实现平稳增长的企业共发现200家,其中这3年中ROE涨幅至少为10%的企业共有47家。
经过进一步的筛选,发现在下一年的1季报中,扣非净利润同比增长至少80%的股票有7支
['002208.SZ', '002353.SZ', '002399.SZ', '002982.SZ', '002993.SZ', '300559.SZ', '688189.SH']
2019年年报中,002208.SZ的ROE值较去年变化的值为7.59%
营业净利率变动的影响程度为3.70%,贡献比例为48.75%
权益乘数变动的影响程度为-0.12%,贡献比例为-1.58%
总资产周转率变动的影响程度为4.02%,贡献比例为52.96%
通过因素分析法,各因素的影响程度由大到小依次为:总资产周转率 --> 营业净利率 --> 权益乘数
002208.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,002353.SZ的ROE值较去年变化的值为8.26%
营业净利率变动的影响程度为3.55%,贡献比例为42.98%
权益乘数变动的影响程度为2.24%,贡献比例为27.12%
总资产周转率变动的影响程度为2.47%,贡献比例为29.90%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
002353.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,002399.SZ的ROE值较去年变化的值为5.09%
营业净利率变动的影响程度为8.05%,贡献比例为158.15%
权益乘数变动的影响程度为-1.19%,贡献比例为-23.38%
总资产周转率变动的影响程度为-1.78%,贡献比例为-34.97%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 权益乘数 --> 总资产周转率
002399.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,002982.SZ的ROE值较去年变化的值为10.14%
营业净利率变动的影响程度为12.07%,贡献比例为119.03%
权益乘数变动的影响程度为-3.95%,贡献比例为-38.95%
总资产周转率变动的影响程度为2.03%,贡献比例为20.02%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
002982.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,002993.SZ的ROE值较去年变化的值为8.43%
营业净利率变动的影响程度为9.55%,贡献比例为113.29%
权益乘数变动的影响程度为-1.15%,贡献比例为-13.64%
总资产周转率变动的影响程度为0.03%,贡献比例为0.36%
通过因素分析法,各因素的影响程度由大到小依次为:营业净利率 --> 总资产周转率 --> 权益乘数
002993.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,300559.SZ的ROE值较去年变化的值为5.06%
营业净利率变动的影响程度为1.80%,贡献比例为35.57%
权益乘数变动的影响程度为-0.02%,贡献比例为-0.40%
总资产周转率变动的影响程度为3.28%,贡献比例为64.82%
通过因素分析法,各因素的影响程度由大到小依次为:总资产周转率 --> 营业净利率 --> 权益乘数
300559.SZ在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------
2019年年报中,688189.SH的ROE值较去年变化的值为4.30%
营业净利率变动的影响程度为1.98%,贡献比例为46.05%
权益乘数变动的影响程度为-3.48%,贡献比例为-80.93%
总资产周转率变动的影响程度为5.81%,贡献比例为135.12%
通过因素分析法,各因素的影响程度由大到小依次为:总资产周转率 --> 营业净利率 --> 权益乘数
688189.SH在2020年1季报发出后的股价走势如下:
-------------------------------------------------------------------------------------------------------------------------------

通过对以上几组数据的分析,发现大部分选出来的企业的股价在未来一段时间都会有很大程度的上涨。但是仍然有个别公司与期望的走势背道而驰,所以需要进一步的分析、筛选。

通过对所选出来的股票按照ROE增长值的大小排序,我们发现ROE增长值排名靠前的企业,其股价在未来的走势更加向好。值得注意的一点是,这些企业在影响ROE增长的因素中,权益乘数的影响程度一定要非常小,最好为负,如果权益乘数的影响程度最大,那么就过滤掉这家企业。

举例000951。2020年年报中ROE增长了很多,但是60%的贡献来自于权益乘数,也就是说明这家企业的负债程度变大,而导致ROE增加。当然在这篇文档中并没有清晰分析出企业的哪些行为导致了负债程度变大,我会在另一篇文章中分析这些企业的现金流量,应该能够进一步佐证这些企业的股价走势。

总结 #

再次总结一下选股的规则:

  1. 企业连续3年(至少3年)ROE实现稳定增长。
  2. 这3年(至少3年)的ROE增长速度迅猛。
  3. 下一年的一季报中,扣非净利润同比这一年增长至少为80%(如果选出来的股票太少,可以适当调整)
  4. 对所选出来的股票按照ROE变化的值进行排序,优先选择ROE变化程度最大的。
  5. 按照因素分析法,分析哪个因素对ROE的增长贡献最大,排除权益乘数贡献最大的企业。
  6. 选出来的股票要持续追踪,中报和三季报的数据依然很重要。如果中报的扣非净利润几乎与去年年报的扣非净利润持平,那么继续持有当前企业的股票。

我一直以为我之前的交易行为是一种投资,阅读《聪明的投资者》之后竟觉得之前几年的“投资”是多么的愚蠢。2018年3月份,我开始设计开发属于自己的一套智能量化选股系统,我给这个项目起名为IQSSS。一直到现在,我的微信中每天都会收到来自这套系统发送的交易提醒信息。有时我觉得它们很起作用,有时又觉得它们是我开发出来的一堆废物。现在看来,它们确实是一堆废物,因为在我开发出的好几种策略中,都是根据技术指标对其进行分析。这其实就像猜硬币的正反面,毫无规律。正如巴菲特所言,没有人能够预测市场未来是什么样子。所以我渐渐放弃了那些我开发出来的策略,虽然每天还在接受它们发来的消息。

不过这些废物有太多的利用之处,毕竟是我花费了好几年的心血一点点累计下来的。通过在2021年4月份阅读了一些有关价值投资的书籍,我很快就将书中的思想转换成自己的,并将它们写成计算机程序实现了出来。我相信这些程序在未来会在我选股时提供很大的帮助。


# 今天是2021年11月5日,三季报已出。
# 下面的sql是为了寻找出18-20年连续3年roe持续增长,并且截至11月3日市盈率 < 四级市场均值 / 2 的股票。

find_good_stocks_sql = """
select t1.ts_code,
       group_concat((t1.real_roe) order by t1.real_roe asc)   as roe_str1,
       group_concat((t1.real_roe) order by t1.end_date_1 asc) as roe_str2
from m_dupont_analysis t1
where end_date_1 in (2018, 2019, 2020)
  and end_date_2 = '年报'
  and substr(t1.ts_code, 1, 6) in (
    SELECT stock_code
    from s_stock_indicator
    where static_pe < level_4_static_pe / 2
      and static_pe != 0
)
group by 1
having roe_str1 = roe_str2
"""
df_good_stocks = get_data(find_good_stocks_sql)
## 进一步筛选出roe稳定并且最后两年的roe增幅至少为10%的股票

for i, row in df_good_stocks.iterrows():
    roe_list = pd.Series(row['roe_str1'].split(',')).astype(float)
    
    diff_values_roe = abs(roe_list.diff().dropna())
    # 如果差值的平均数 / 最小值  <= 1.5,说明roe平稳增长
    if np.min(diff_values_roe) != 0 and np.average(diff_values_roe) / np.min(diff_values_roe) <= 1.5:
        if roe_list.values[-1] - roe_list.values[-2] >= 0.1:
            print(row[['ts_code']])
ts_code    002124.SZ
Name: 20, dtype: object
ts_code    002131.SZ
Name: 22, dtype: object
ts_code    002157.SZ
Name: 23, dtype: object
ts_code    002487.SZ
Name: 37, dtype: object
ts_code    002605.SZ
Name: 47, dtype: object
ts_code    300030.SZ
Name: 56, dtype: object
ts_code    300690.SZ
Name: 76, dtype: object

通过回看了以上几只股票,发现大金重工(002487)涨势迅猛,3个月内涨了5倍。

可以看出,在2021年一季报出来后通过以上方法筛选出的32支股票中有漏网之鱼。

可以这样:照常筛选,但是要在7、8月份,进行市盈率的跟踪。虽然一季报表现可能不符合要求,但是如果二季报并没大碍,如果此时的市盈率依然很低,并且整个行业都在上涨。那么可以持仓买入。