SPL 量化系列实践:计算行业财务指标

行业财务指标非常多,本文只是抛砖引玉,以四个常用的行业财务指标为例介绍SPL计算财务指标的方法,其他财务指标可以用类似的方法计算出来。

1. 行业毛利润率

行业毛利润率=(营业收入-营业成本)/营业收入

其中:

营业收入=行业所有上市公司营业收入之和

营业成本=行业所有上市公司营业成本之和

上市公司的营业收入、营业成本都可以在利润表中查到。

2. 行业净利润率

行业净利润率=净利润/营业总收入

其中:

净利润=行业所有上市公司净利润之和

营业总收入=行业所有上市公司营业总收入之和

上市公司的净利润、营业总收入都可以在利润表中查到。

3. 营业收入含金量

营业收入含金量=销售商品、提供劳务收到的现金/营业收入

其中:

销售商品、提供劳务收到的现金=行业所有上市公司销售商品、提供劳务收到的现金之和

营业收入=行业所有上市公司营业收入之和

上市公司的销售商品、提供劳务收到的现金可以在现金流量表中查到。

4. 应收款项占营业收入比重

应收款项占营业收入比重=应收账款/营业收入

其中:

应收账款=行业所有上市公司应收账款之和

营业收入=行业所有上市公司营业收入之和

上市公司的应收账款可以在资产负债表中查到。

SPL代码


A

1

=file("all_stock_info.csv").import@tc(ts_code,industry,name)

2

=A1.select(ts_code.split(".")(2)!="BJ")

3

=file("IncomeStatement/income_statement.csv").cursor@tc()

4

=A3.select(end_date%10000==1231&&end_date\10000>2013&&total_revenue&&total_cogs&&ts_code.split(".")(2)!="BJ").fetch@x()

5

=A4.group(ts_code,end_date).(~.maxp(f_ann_date)).sort(ts_code,end_date)

6

=file("BalanceSheet/balance_sheet.csv").cursor@tc()

7

=A6.select(end_date%10000==1231&&end_date\10000>2013&&ts_code.split(".")(2)!="BJ").fetch@x()

8

=A7.group(ts_code,end_date).(~.maxp(f_ann_date)).sort(ts_code,end_date)

9

=file("CashFlowStatement/cash_flow.csv").cursor@tc()

10

=A9.select(end_date%10000==1231&&end_date\10000>2013&&ts_code.split(".")(2)!="BJ").fetch@x()

11

=A10.group(ts_code,end_date).(~.maxp(f_ann_date)).sort(ts_code,end_date)

12

=A5.join(ts_code,A2:ts_code,industry)

13

=join@m(A12:income,[ts_code,end_date];A8:balance,[ts_code,end_date];A11:cash,[ts_code,end_date])

14

=A13.group([income.industry,income.end_date])

15

=A14.new(income.industry,income.end_date,(icm=~.(income),icm.len()):comp_num,(rvn=icm.sum(if(revenue,revenue,total_revenue)),cos=icm.sum(if(oper_cost,oper_cost,total_cogs)),1-cos/rvn):gross_margin,(nicm=icm.sum(n_income),total_rvn=icm.sum(total_revenue),nicm/total_rvn):nprofit_margin,(csh=~.(cash),sale_cash=csh.sum(c_fr_sale_sg),sale_cash/rvn):rvn_gold,(blc=~.(balance),acc_rcv=blc.sum(accounts_receiv),acc_rcv)/rvn:acc_rcv_rate)

16

=A15.group(industry)

17

=A16.select(~.count(gross_margin>0.4)/~.len()>0.8)

18

=A16.select(~.count(nprofit_margin>0.15)/~.len()>0.8)

19

=A16.select(~.count(rvn_gold<1)/~.len()>0.8)

20

=A16.select((~.count(acc_rcv_rate<0.05&&acc_rcv_rate)/~.len()>0.8))

A1A2:读取股票信息数据并取沪深交易所数据。

..

A3:游标读取利润表数据

A4:取近十年(2014~2023年)的沪深交易所中营业总收入和营业总成本不是null的年报数据。

因为利润表是所有上市公司每个季度的利润表,有些表还有备份,所以数据量较大,而我们只需要最近十年的沪深交易所上市公司的年报数据,全量数据都读进内存有点浪费内存,所以使用SPL的游标来读取数据。

A5:取各公司每年最新的年报数据

..

A6~A8A9~A11:和A3~A5类似,区别是取资产负债表数据和现金流量表数据。

资产负债表数据如下:

..

现金流量表数据如下:

..

A12:根据ts_code关联利润表和股票信息表,增加行业列。

..

A13:关联三张财务报表

..

A14:按行业和报告期分组

..

A15:计算行业财务指标

..

A16:按行业分组

A17:筛选80%的年份毛利润率都大于40%的行业和公司

..

A18:筛选80%的年份净利润率都大于15%的行业和公司

..

A19:筛选80%的年份营业收入都小于1的行业和公司

..

A20:筛选80%的年份应收账款占营业收入比重都小于5%的行业和公司

..

SPL的连接运算是经过精心设计的,它既可以关联后增加指定列,比如A12的运算,在利润表后增加行业名,还可以同时解析多个关联关系,比如A13中同时连接利润表、资产负债表和现金流量表,因为三张表都有序,使用@m选项会自动用归并法关联,提高关联效率。

另外,能够灵活的进行连接运算,离不开SPL对结构化数据的深刻理解,比如A13的结果本质上是个序表,但是每一列的成员又都是记录,这样使后续的财务指标计算变得简单明了,而这些是SQLPython等语言所不能的,由此可见,SPL无愧于“量化神器”的名号。