1、策略简介
选股系列前面几篇已经使用过个股的RPS指标,相对于个股RPS,概念板块RPS侧重于某些时期整个行业或板块可能因为宏观经济趋势、政府政策或技术变革等因素而受益。
与集中在个别股票上的投资相比,投资于一个整体表现良好的行业或板块可以提供更好的风险分散。从市场心理角度,板块动能反映了大部分投资者的共同看法,从而创建了自我实现的预言。
或者也可以结合其他选股指标,叠加板块RPS来过滤。(后期会有文章)
概念板块筛选逻辑:
20日、10日、5日的RPS均大于临界值,且当日各级别的RPS大于RPS移动均线。具体实现过程见代码。
2、选股过程
有很多朋友在后台问如何获取量价数据,我们过去的文章中有提到爬虫方法:
《自定义爬虫函数展示,3分钟可更新全部数据》
这里结合akshare一起来实现本文的选股过程
import akshare as ak
import requests
import pandas as pd
import datetime
today=datetime.datetime.today().strftime('%Y%m%d')
begin_day=(datetime.datetime.today()+datetime.timedelta(days=-80)).strftime('%Y%m%d')
board_name=ak.stock_board_concept_name_em()
delname=['昨日连板_含一字','昨日涨停_含一字']
board_name=board_name[~board_name['板块名称'].isin(delname)].reset_index(drop=True)
def stock_board_concept_hist_em(symbol,period,start_date,end_date,adjust):
'''
东方财富网-沪深板块-概念板块-历史行情
https://quote.eastmoney.com/bk/90.BK0715.html
:param symbol: 板块名称
:type symbol: str
:type period: 周期; choice of {'daily', 'weekly', 'monthly'}
:param period: 板块名称
:param start_date: 开始时间
:type start_date: str
:param end_date: 结束时间
:type end_date: str
:param adjust: choice of {'': 不复权, 'qfq': 前复权, 'hfq': 后复权}
:type adjust: str
:return: 历史行情
:rtype: pandas.DataFrame
'''
period_map = {
'daily': '101',
'weekly': '102',
'monthly': '103',
}
stock_board_code = board_name[
board_name['板块名称'] == symbol
]['板块代码'].values[0]
adjust_map = {'': '0', 'qfq': '1', 'hfq': '2'}
url = 'http://91.push2his.eastmoney.com/api/qt/stock/kline/get'
params = {
'secid': f'90.{stock_board_code}',
'ut': 'fa5fd1943c7b386f172d6893dbfba10b',
'fields1': 'f1,f2,f3,f4,f5,f6',
'fields2': 'f51,f53',
'klt': period_map[period],
'fqt': adjust_map[adjust],
'beg': start_date,
'end': end_date,
'smplmt': '10000',
'lmt': '1000000',
'_': '1626079488673',
}
r = requests.get(url, params=params)
data_json = r.json()
temp_df = pd.DataFrame([item.split(',') for item in data_json['data']['klines']])
temp_df.columns = [
'日期',
'收盘',
]
temp_df = temp_df[
[
'日期',
'收盘',
]
]
temp_df['收盘'] = pd.to_numeric(temp_df['收盘'], errors='coerce')
return temp_df
board_daily=stock_board_concept_hist_em(
symbol=list(board_name['板块名称'])[0],
period= 'daily',
start_date =begin_day,
adjust='',
end_date =today)
board_daily=board_daily.rename(columns={'收盘':list(board_name['板块名称'])[0]})
for name in list(board_name['板块名称'])[1:]:
board_daily_temp=stock_board_concept_hist_em(
symbol=name,
period= 'daily',
start_date = begin_day,
adjust='',
end_date = today)
board_daily=pd.merge(board_daily,board_daily_temp,how='outer').rename(columns={'收盘':name})
# 将日期列设置为索引
board_daily.set_index('日期', inplace=True)
def calculate_RPS(df, days):
# 计算百分比变化
return_rate = df.pct_change(days)
# 在每个日期为概念/股票排序,并转化为百分比形式的排名
rps = return_rate.rank(axis=1, pct=True).multiply(100)
return rps
df_rps10 = calculate_RPS(board_daily, 10)
df_rps20 = calculate_RPS(board_daily, 20)
df_rps5 = calculate_RPS(board_daily, 5)
# 计算移动平均值
ma_rps10 = df_rps10.rolling(window=10).mean()
ma_rps20 = df_rps20.rolling(window=20).mean()
ma_rps5 = df_rps5.rolling(window=5).mean()
# 使用条件进行筛选
condition_a = df_rps10 > ma_rps10
condition_b = df_rps20 > ma_rps20
condition_d = df_rps5 > ma_rps5
selected_board = (df_rps10 > 80) & (df_rps20 > 75) & (df_rps5 > 85) & condition_a & condition_b & condition_d
3、筛选结果
selected_board的结果:
True代表当日该概念板块满足RPS条件
来看看今天(2023年8月16日)的板块筛选结果:
cols_true = selected_board.loc['2023-08-16'][selected_board.loc['2023-08-16']].index.tolist()
['券商概念',
'抗原检测',
'ST股',
'毛发医疗',
'精准医疗',
'痘病毒防治',
'辅助生殖',
'蒙脱石散',
'婴童概念',
'病毒防治',
'养老概念',
'流感',
'宠物经济',
'化妆品概念',
'健康中国',
'青蒿素',
'肝素概念',
'超级真菌',
'肝炎概念',
'幽门螺杆菌概念',
'注射器概念',
'医疗美容',
'中药概念',
'地塞米松',
'熊去氧胆酸']
进一步看看'券商概念'板块成分股的近期业绩走势
stock_list=list(ak.stock_board_concept_cons_em(cols_true[0])['代码'])
stock_daily=ak.stock_zh_a_daily(
symbol= 'sz'+stock_list[0],
start_date= begin_day,
end_date = today,
adjust='qfq'
)[['date','close']].rename(columns={'close':stock_list[0]})
for code in stock_list[1:]:
try:
stock_daily_temp=ak.stock_zh_a_daily(
symbol= 'sh'+code,
start_date= begin_day,
end_date = today,
adjust='qfq'
)[['date','close']].rename(columns={'close':code})
except:
stock_daily_temp=ak.stock_zh_a_daily(
symbol= 'sz'+code,
start_date= begin_day,
end_date = today,
adjust='qfq'
)[['date','close']].rename(columns={'close':code})
stock_daily=pd.merge(stock_daily,stock_daily_temp)
stock_daily.set_index('date').divide(stock_daily.set_index('date').iloc[0]).plot(legend=False,figsize=(10, 5))
其他板块大家可以自行关注后期走势