一般情况下,我们会通过历史数据估算上市公司的年平均收益率。如何计算公司的年平均收益率呢?这里可能存在多种算法。一种属于基本面分析,就是通过财务报表里的净利润等其他指标计算公司账面上的年平均收益率。另一种,就是通过上市公司股价的期望来反映散户投资该证券将获取的年平均收益率。今天我们讲解如何通过公司股价来计算公司的年平均收益率。因为,大多数散户都希望自己投资的证券获得收益来自股价上涨。
在计算公司的年平均收益率时,也有不同的计算方式。一种是采用单利计算,一种是采用复利计算。
若采用单利计算,则公式如下:
AvgEarningRate = (ClosePrice/OpenPrice) /N -1
若采用复利计算,则公司如下:
AvgEarningRate =
-1
其中,AvgEarningRate是N年的年平均收益率,N为年数,OpenPrice为N年首个交易日的开盘价,ClosePrice为N年最后一个交易日的收盘价。注意:一般开盘价和收盘价都是前复权或后复权的数据。
接下来,我将通过python调用baostock的日K线数据实现2022-2025年的3年中各个证券的年均收益率。其中,计算方式按照复利计算,价格进行了向前复权处理。具体代码如下:
import baostock as bs
import pandas as pd
import matplotlib.pyplot as plt
import math
def get_closeprice(code):
#### 获取沪深A股历史K线数据 ####
# 使用正确的API方法 query_history_k_data_plus
rs_open = bs.query_history_k_data_plus(code, "open",
start_date='2022-10-31',
end_date='2022-10-31',
frequency="d",
adjustflag="1")
data_list = []
while (rs_open.error_code == '0') & rs_open.next():
# 获取一条记录,将记录合并在一起
data_list.append(rs_open.get_row_data())
# 检查是否有数据
if not data_list:
return None
result_open = pd.DataFrame(data_list, columns=rs_open.fields)
result_open.index = [code] # 设置索引
rs_close = bs.query_history_k_data_plus(code, "close",
start_date='2025-10-31',
end_date='2025-10-31',
frequency="d",
adjustflag="1")
data_list = []
while (rs_close.error_code == '0') & rs_close.next():
# 获取一条记录,将记录合并在一起
data_list.append(rs_close.get_row_data())
# 检查是否有数据
if not data_list:
return None
result_close = pd.DataFrame(data_list, columns=rs_close.fields)
result_close.index = [code] # 设置索引
result = result_open.join(result_close)
return result
def compute_Avg_EarningRate():
# 登陆系统
lg = bs.login()
# 显示登陆返回信息
print('login respond error_code:' + lg.error_code)
print('login respond error_msg:' + lg.error_msg)
# 获取全部证券基本资料
rs = bs.query_stock_basic()
result_list = [] # 使用列表收集数据
count = 0
while (rs.error_code == '0') & rs.next():
# 获取一条记录
code = rs.get_row_data()[0]
print(f"Processing {code}...")
df = get_closeprice(code)
if df is not None:
result_list.append(df)
count += 1
# 可选:限制数量用于测试
# if count >= 100:
# break
# 使用concat替代已弃用的append方法
if result_list:
result = pd.concat(result_list, axis=0)
else:
print("No data collected!")
bs.logout()
return
# 数据清洗和转换
result = result[result['open'] != '']
result['open'] = result['open'].astype(float)
result['close'] = result['close'].astype(float)
# 计算平均收益率(3年期年化收益率)
result['avgEarningRate'] = (result['close'] / result['open']).apply(
lambda x: math.pow(x, 1 / 3) - 1 if x > 0 else 0
)
result = result.sort_values(by=['avgEarningRate'], ascending=False)
result.to_csv("D:\\Avg_Earning_Rate_data.csv", encoding="gbk", index=True)
# 绘制前10名
plt.figure(figsize=(12, 6))
top_10 = result.head(10)
plt.bar(range(len(top_10)), top_10['avgEarningRate'])
plt.title('Top 10 Avg Earning Rate (2022-2025)')
plt.xlabel('Stocks')
plt.ylabel('Annualized Return Rate')
plt.xticks(range(len(top_10)), top_10.index, rotation=45)
plt.tight_layout()
plt.show()
print(f"Processed {len(result)} stocks successfully!")
# 登出系统
bs.logout()
if __name__ == '__main__':
compute_Avg_EarningRate()
其中,我给出了前10名证券的分布图,具体如下:

在输出文件“Avg_Earning_Rate_data.csv”存储了输出的结果,包含了证券代码,3年中的首个交易日的开盘价和3年中的最后交易日的收盘价(计算方式按照复利计算,价格进行了向前复权处理)。如下表:
| open | close | avgEarningRate | |
|---|---|---|---|
| sz.302132 | 10.26 | 510.2272898 | 2.67738 |
| sz.300502 | 149.1964668 | 4112.721319 | 2.02081 |
| sz.300476 | 63.25143996 | 1450.892352 | 1.84132 |
| sz.300308 | 138.0068634 | 3119.801784 | 1.82754 |
| sh.688256 | 64.4 | 1375 | 1.7742 |
| sz.300972 | 11.36232344 | 180.5264985 | 1.5139 |
| sz.300779 | 15.0880152 | 220.5872791 | 1.4452 |
| sh.603516 | 25.21008768 | 363.0777447 | 1.432998 |
| sh.688256 | 64.4 | 1375 | 1.7742 |
| sz.300972 | 11.36232344 | 180.5264985 | 1.5139 |
| sz.300779 | 15.0880152 | 220.5872791 | 1.4452 |
| sh.603516 | 25.21008768 | 363.0777447 | 1.432998 |
由结果可知,中航成飞,证券代码: 302132.SZ,它的年均收益率最高,超过了1。

