利用tushare pro根据财务指标选股

本文介绍了一种基于中证500指数成分股的量化选股策略,通过排除特定板块、停牌股票,并综合考虑财务指标来筛选出潜力股。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

选股策略:
1、以中证500为股票池;
2、按照权重从大到小排列获取后三百只股票;
3、过滤掉创业板及科创板的股票
4、过滤掉当天停牌的股票
5、 基础科目及衍生类:获取每只股票的finaexp_of_gr(财务费用/营业总收入)、current_exint(无息流动负债)、netdebt(净债务)。以上数据偏向小值。
6、 每股指标因子 undist_profit_ps(每股未分配利润)、q_eps(每股收益)、surplus_rese_ps(每股盈余公积)。以上数据取大值。
7、 价值因子:ar_turn(应收账款周转率)、cogs_of_sales(销售成本率)、debt_to_eqt(产权比率),其上数据取小值。
8、获取每只股票以上九个数据,3倍中位数去极值。
9、(5)中三个都利用1分位数分类,分位内的获得1分。(6)中三个都以四分位数进行区分,4分位内的获得1分。(7)中三个都利用1分位数分类,分位内的获得1分。
10、利用得分降序排列取前十只。

import tushare as ts
import pandas as pd
import numpy as np
import datetime
from dateutil.relativedelta import relativedelta
from time import sleep

# 日期处理
today = datetime.datetime.today().strftime('%Y%m%d')    #获取今天的年月日

lastday = datetime.datetime.today() - datetime.timedelta(days=1)  #获取前一天日期
lastday = lastday.strftime('%Y%m%d')

last_year = datetime.datetime.today() - relativedelta(months=12)   #获取前一年的日期
last_year = last_year.strftime('%Y%m%d')   # 转换成STR

Lastweek = datetime.datetime.today() - datetime.timedelta(days=7)   #获取前一周的日期
Lastweek = Lastweek.strftime('%Y%m%d')    # 转换成STR

last_mon = datetime.datetime.today() - relativedelta(months=1)   #获取前一月的日期
last_mon = last_mon.strftime('%Y%m%d')   # 转换成STR

ts.set_token('you token')
pro=ts.pro_api()

# 1 以中证500位股票池
df = pro.index_weight(index_code = '000905.SH', start_date = last_mon, end_date = today) 

#按照权重降序排序
df = df.sort_values(by = 'weight',ascending = False).reset_index()       

# 2 获取权重最轻的后300只股票
df = df.tail(300)

# 3、过滤掉创业板及科创板的股票
cy = df[df.con_code.str.contains('^30')]  # 利用正则表达式匹配以30开头的所有股票

cy_list = cy['con_code'].values.tolist()  # 将30开头的股票代码导出成一个列表
for i in cy_list:
df = df.drop(index=(df.loc[(df['con_code'] == i)].index))  # 获取这一列中等于该股票代码的索引并将其删除

# 3剔除出科创板的股票
kc = df[df.con_code.str.contains('^68')]     # 利用正则表达式匹配以68开头的所有股票

kc_list = kc['con_code'].values.tolist()     # 将68开头的股票代码导出成一个列表
for j in kc_list:
     # 获取这一列中等于该股票代码的索引并将其删除
	df = df.drop(index=(df.loc[(df['con_code'] == j)].index)) 

# 4删除掉停牌数据
tp_df = pro.suspend_d(suspend_type = 'S', trade_date = '20201211')

tp_list = tp_df['ts_code'].values.tolist()
for tp in tp_list:
	df = df.drop(index=(df.loc[(df['con_code'] == tp)].index))

# 获取过滤后的股票代码导出成一个列表
hs300_list = df[['con_code'][0]].tolist()
# 创建一个空的DataFrame
all_dataframe = pd.DataFrame()

for stock in hs300_list:
    
#  获取财务数据
'''
5、 基础科目及衍生类:获取每只股票的:
finaexp_of_gr(财务费用/营业总收入)、current_exint(无息流动负债)、netdebt(净债务)。以上数据偏向小值。
6、 每股指标因子:
undist_profit_ps(每股未分配利润)、q_eps(每股收益)、surplus_rese_ps(每股盈余公积)。以上数据取大值。
7、 价值因子:
ar_turn(应收账款周转率)、cogs_of_sales(销售成本率)、debt_to_eqt(产权比率),其上数据取小值。
'''

df1 = pro.fina_indicator(ts_code = stock,start_date= last_year, end_date=today,\
fields='ts_code,end_date,finaexp_of_gr,current_exint,netdebt,undist_profit_ps,q_eps,surplus_rese_ps,ar_turn,cogs_of_sales,debt_to_eqt')
# 一段时间内可能会有多个财务报表取头部第一个代表取最近的一个报表
df1 = df1.head(1)   
# 每只股票最近的财务报表添加到DataFrame
all_dataframe = all_dataframe.append(df1)
# 受到每分钟访问频次限制,每查询一次休息1秒钟
sleep(1)  

# 复位索引
all_dataframe = all_dataframe.reset_index()  

# 删除原索引
all_dataframe = all_dataframe.drop(columns = ['index']) 
print(all_dataframe)

# 更改列名
all_dataframe = all_dataframe.rename(columns={'ts_code':'股票代码','end_date': '结束日期','surplus_rese_ps':'每股盈余公积','undist_profit_ps':'每股未分配利润', 'ar_turn':'应收账款周转率',\
'current_exint':'无息流动负债','netdebt':'净债务','cogs_of_sales':'销售成本率','finaexp_of_gr':'财务费用/营业总收入','debt_to_eqt':'产权比率','q_eps':'每股收益'}) 

# 监控是否修改成功
print(all_dataframe)

# 把有空值的行删除
all_dataframe = all_dataframe.dropna(axis=0, how='any')
all_dataframe

# 获取每只股票以上九个数据,3倍中位数去极值
def _3mad(nums):
    mad = np.median(nums)
    up = mad + 3 * mad
    down = mad - 3 * mad
    nums = np.where(nums > up,up,nums)
    nums = np.where(nums < down,down,nums)
return nums

# 利用去极值方法对每列数据进行处理
all_dataframe['每股收益'] = _3mad(all_dataframe[['每股收益'][0]])
all_dataframe['每股盈余公积'] = _3mad(all_dataframe[['每股盈余公积'][0]])
all_dataframe['每股未分配利润'] = _3mad(all_dataframe[['每股未分配利润'][0]])

all_dataframe['应收账款周转率'] = _3mad(all_dataframe[['应收账款周转率'][0]])
all_dataframe['无息流动负债'] = _3mad(all_dataframe[['无息流动负债'][0]])
all_dataframe['净债务'] = _3mad(all_dataframe[['净债务'][0]])
all_dataframe['销售成本率'] = _3mad(all_dataframe[['销售成本率'][0]])

all_dataframe['财务费用/营业总收入'] = _3mad(all_dataframe[['财务费用/营业总收入'][0]])
all_dataframe['产权比率'] = _3mad(all_dataframe[['产权比率'][0]])

# 求分位数获取每只股票(财务费用/营业总收入)、(无息流动负债)、(净债务)的百分之20的分位数
cwfy_20 = np.percentile(all_dataframe[['财务费用/营业总收入'][0]], 20)
wxfz_20 = np.percentile(all_dataframe[['无息流动负债'][0]], 20)
jzw_20 = np.percentile(all_dataframe[['净债务'][0]], 20)

#每股指标因子(每股未分配利润)、(每股收益)、(每股盈余公积)求百分之80的分位数
wflr_80 = np.percentile(all_dataframe[['每股未分配利润'][0]], 80)
shy_80 = np.percentile(all_dataframe[['每股收益'][0]], 80)
yygj_80 = np.percentile(all_dataframe[['每股盈余公积'][0]], 80)

#价值因子:(应收账款周转率)、(销售成本率)、(产权比率),百分之20的分位数
yszkzzl_20 = np.percentile(all_dataframe[['应收账款周转率'][0]], 20)
xshchb_20 = np.percentile(all_dataframe[['销售成本率'][0]], 20)
chquanbl_20 = np.percentile(all_dataframe[['产权比率'][0]], 20)

# 将每列数据转换成一个列表
cwfy_list = list(all_dataframe[['财务费用/营业总收入'][0]])
wxfz_list = list(all_dataframe[['无息流动负债'][0]])
jzw_list  = list(all_dataframe[['净债务'][0]])
wflr_list  = list(all_dataframe[['每股未分配利润'][0]])
shy_list  = list(all_dataframe[['每股收益'][0]])
yygj_list  = list(all_dataframe[['每股盈余公积'][0]])
yszkzzl_list  = list(all_dataframe[['应收账款周转率'][0]])
xshchb_list  = list(all_dataframe[['销售成本率'][0]])
chquanbl_list  = list(all_dataframe[['产权比率'][0]])

# 遍历所有列表并与分位数比较一次判断是否加分
score = []
for i in range(len(all_dataframe)):
    n = 0
    if cwfy_list[i] < cwfy_20: n = n + 1
    if wxfz_list[i] < wxfz_20: n = n + 1
    if jzw_list[i]  < jzw_20:  n = n + 1
        
    if wflr_list[i] > wflr_80: n = n + 1
    if shy_list[i] > shy_80: n = n + 1
    if yygj_list[i]  > yygj_80:  n = n + 1        
        
    if yszkzzl_list[i] < yszkzzl_20: n = n + 1
    if xshchb_list[i] < xshchb_20: n = n + 1
    if chquanbl_list[i]  < chquanbl_20:  n = n + 1        
    score.append(n)
# 将得分添加到DataFrame中
all_dataframe['得分'] = score
# 将股票得分按照降序排列获取前十个
stocks = all_dataframe.sort_values(by = '得分',ascending = False).head(10)
# 将所筛选的十只股票的代码导出成列表
buy_list = list(stocks[['股票代码'][0]])
print(buy_list)

输出结果为:
[‘603556.SH’, ‘002867.SZ’,‘002440.SZ’,‘002038.SZ’,‘002818.SZ’,‘600566.SH’,‘600557.SH’,‘002233.SZ’,‘600062.SH’,‘002957.SZ’]

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhaojieming1990

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值