from IPython.core.display import display
from jqdata import *
import pandas as pd
import warnings
import pyecharts.globals as g
from pyecharts.charts import *
from pyecharts import options as opts
import datetime as dt
import ipywidgets as widgets
import IPython.display as dspl
from functools import lru_cache
# 获取股票的行业代码
def stock_industry(stocks_list=list(get_all_securities().index), industries_type="sw_l3"):
stocks_industry_dict = get_industry(stocks_list)
stocks_industry_df = pd.DataFrame(stocks_industry_dict).T[[industries_type]]
stocks_industry_df[industries_type] = stocks_industry_df[industries_type].dropna().apply(
lambda x: x['industry_name'])
df_category = stocks_industry_df[[industries_type]].dropna().reset_index()
df_category.columns = ['code', 'category']
return df_category
#所有股票的概念列表
@lru_cache(maxsize=128, typed=False)
def stock_concepts():
"""所有股票的概念列表"""
q = query(jy.LC_ConceptList.ConceptCode, jy.LC_ConceptList.ConceptName)
dict_concept = jy.run_query(q).set_index('ConceptCode')['ConceptName'].to_dict()
stocks = jy.run_query(query(jy.SecuMain.InnerCode, jy.SecuMain.SecuCode).filter(jy.SecuMain.SecuCategory == 1,
jy.SecuMain.SecuMarket.in_(
[83, 90]),
jy.SecuMain.ListedState.in_(
[1])))
s_code = stocks.set_index("InnerCode")['SecuCode']
dfs = []
min_id = 9953668143482
while len(dfs) < 30 and min_id > 0:
q = query(
jy.LC_COConcept
).filter(jy.LC_COConcept.IndiState == 1, jy.LC_COConcept.ID < min_id).order_by(jy.LC_COConcept.ID.desc())
df = jy.run_query(q)
min_id = df.ID.min()
if len(df) > 0:
dfs.append(df)
else:
break
df = pd.concat(dfs, ignore_index=True)
sc = df.groupby('InnerCode').apply(
lambda dx: ",".join([dict_concept[code] for code in dx.ConceptCode.unique()]))
df_concept = pd.DataFrame({"concept": sc, 'code': s_code})
df_concept['symbol'] = df_concept.code.map(normalize_code, na_action='ignore')
s_concept = df_concept.dropna().set_index('symbol')['concept']
df = pd.DataFrame(s_concept.str.split(',').tolist(), index=s_concept.index).stack()
df = df.reset_index([0, 'symbol'])
df.columns = ['code', 'category']
return df
# 股票价格是否在N日均线上方
def score_by_bias(stock_list=list(get_all_securities().index), ma_len=20, end_date=dt.datetime.now(), count=510):
"""
:param stock_list:
:param ma_len:
:param end_date:
:param count:
:return: index,2020-05-01
000001.XSHE, 1
"""
close = get_price(stock_list, end_date=end_date, count=count + ma_len + 1, fields=['close'])['close']
ma = close.rolling(ma_len).mean()
return (close > ma).astype(int).iloc[-count:].T
def score_by_return(stock_list=list(get_all_securities().index), return_days=1, return_filter=0.099,
end_date=dt.datetime.now(), count=510):
"""
:param stock_list: 股票代码
:param return_days: 收益率统计周期
:param return_filter: 收益率阈值过滤
:param end_date: 截止日期
:param count: 查看的周期
:return:
"""
close = get_price(stock_list, end_date=end_date, count=count + return_days, fields=['close'], panel=True)[
'close']
df_return = (close / close.shift(return_days) - 1).iloc[return_days:]
df_filter = (df_return > return_filter).astype(int)
df_filter.index = df_return.index.strftime('%Y-%m-%d')
return df_filter.T
#涨停统计
def zhangting(end_date,count,filter_longtou=False):
#filter_longtou 为True 只显示成为过某日最高板的股票
df_stock=get_all_securities()
old_stock=df_stock['start_date']<(end_date-dt.timedelta(days=count+180)).date()
not_st=~(df_stock['display_name'].str.contains('ST')|(df_stock['display_name'].str.contains('退')))
select_stock=df_stock[not_st&old_stock]
names=df_stock['display_name'].to_dict()
panel=get_price(list(select_stock.index),end_date=end_date,count=count,fields=['close','pre_close','high_limit'],panel=True)
close=panel['close']
pre_close=panel['pre_close']
high_limit=panel['high_limit']
#涨停标记1
df_zhangting=((close>=high_limit)&(close>pre_close)).astype(int)
# 过滤出现过涨停的股票
df_has_zhangting=df_zhangting.loc[:,(df_zhangting>0).any()]
# 股票代码换成股票名称
df_has_zhangting.columns=[names[col] for col in df_has_zhangting.columns]
# 统计股票连板数
np_sum=df_has_zhangting.values
for row in range(0,np_sum.shape[0]):
for col in range(0,np_sum.shape[1]):
if np_sum[row,col]>0 and (row==0 or np_sum[row-1,col]==0):
np_sum[row,col]=1
elif np_sum[row,col]>0 and row>0 and np_sum[row-1,col]>0:
np_sum[row,col]=np_sum[row-1,col]+1
df_sum=pd.DataFrame(data=np_sum,index=df_has_zhangting.index,columns=df_has_zhangting.columns)
#转换成 日期,股票,连板数的格式,只保留涨停板数据
df_zhangting_record=df_sum.reset_index().melt(id_vars='index')
df_zhangting_record=df_zhangting_record.fillna(0)
df_zhangting_record=df_zhangting_record[(df_zhangting_record['value']>0)]
df_zhangting_record.columns=['date','category','score']
df_zhangting_record['date']=df_zhangting_record['date'].dt.strftime('%Y-%m-%d')
#计算每天最高板
df_date_max=df_zhangting_record[['date','score']].groupby('date').max()
df1=df_zhangting_record.merge(df_date_max,left_on='date',right_index=True)
#相对每天最高板的比例*100 作为rank 字段,最高板显示红色
df1['rank']=(df1['score_x']/df1['score_y']*100).astype(int)
#只保留每日最高版出现过的龙头股
if filter_longtou==True:
df2=df1[df1['category'].isin(list(df1[df1['score_x']==df1['score_y']].category.unique()))]
else:
df2=df1
#添加一列最高板数据
df_date_highest=df2[['date','score_x']].groupby('date').max()
df_date_highest['category']='*最高板'
df_date_highest['score_y']=df_date_highest['score_x']
df_date_highest['rank']=100
df_date_highest=df_date_highest.reset_index()
return pd.concat([df2[['category','date','score_x','rank','score_y']],df_date_highest[['category','date','score_x','rank','score_y']]])
# 分类热度统计,默认实现聚宽支持的行业分类,还有聚源数据的概念分类
class Category:
def __init__(self):
warnings.filterwarnings('ignore')
g.WarningType.ShowWarning = False
# 数据格式 dat,cat,value,score
def plot_category_hot(self,df, title):
"""
:param df: 数据格式 category,date,score,rank
:param title: series name
:return: pyecharts Bar3D 图
"""
return Bar3D(init_opts=opts.InitOpts(width="100%", height="800px")) \
.add(
series_name=title,
shading="lambert",
data=df.values.tolist(),
xaxis3d_opts=opts.Axis3DOpts(type_="category", data=sorted(list(df['category'].unique()))),
yaxis3d_opts=opts.Axis3DOpts(type_="category", data=sorted(list(df['date'].unique()))),
zaxis3d_opts=opts.Axis3DOpts(type_="value"),
).set_global_opts(
visualmap_opts=opts.VisualMapOpts(
max_=100,
dimension=3,
range_color=[
"#313695",
"#4575b4",
"#74add1",
"#abd9e9",
"#e0f3f8",
"#ffffbf",
"#fee090",
"#fdae61",
"#f46d43",
"#d73027",
"#a50026"
]
)
).render_notebook()
def category_score(self,df_score, df_category=None, count=30, daily_top_filter=20):
"""
:param df_score: 格式 code,2015-01-01,2015-01-02...
:param df_category: 格式 code,category
:param count: 查看最近周期(热度在这个周期的排行)
:param daily_top_filter: 只保留每天的top多少,按score排行
:return:
"""
code_category_dict = df_category.groupby('code').apply(lambda dx: list(dx['category'].unique())).to_dict()
dats = df_score.columns
# 统计分类得分
dat_cat_dict = {} # {'2020-05-01':{'光伏概念':30,'连板':50}}
for i in range(0, len(dats)):
codes = list(df_score[df_score[dats[i]] > 0].index)
s_score = df_score[dats[i]]
category_count_dict = {}
for code in codes:
if code in code_category_dict:
categories = code_category_dict[code]
for category in categories:
if category not in category_count_dict:
category_count_dict[category] = float(s_score[code])
else:
category_count_dict[category] = float(category_count_dict[category]) + float(s_score[code])
dat_cat_dict[dats[i]] = category_count_dict
# df_category_score 格式 index 2020-05-01
# 光伏概念 5
df_category_score = pd.DataFrame.from_dict(dat_cat_dict, orient='index').fillna(0).tail(count).T
# 每日概念得分排行100分制
df_category_score_rank = (df_category_score.rank(pct=True, axis='columns', method='min') * 100).astype(int)
# 计算每天的得分排名,转换成 category,date,rank 保留排行前N
df_category_daily_rank = df_category_score.rank(ascending=False, method='first').astype(int)
df_category_daily_rank_melt = df_category_daily_rank.reset_index().melt(id_vars=['index'])
df_daily_tops = df_category_daily_rank_melt[df_category_daily_rank_melt['value'] <= daily_top_filter]
# 两次左连接,保留topN得分的,每日分类热度数据
df_cat_melt = df_category_score.reset_index().melt(id_vars=['index'])
df_cat_rank_melt = df_category_score_rank.reset_index().melt(id_vars=['index'])
df_top_score = df_daily_tops.merge(df_cat_melt, left_on=['index', 'variable'], right_on=['index', 'variable'],
how='left')
df_final = df_top_score.merge(df_cat_rank_melt, left_on=['index', 'variable'], right_on=['index', 'variable'],
how='left')
df_final.columns = ['category', 'date', 'order', 'score', 'rank']
return df_final[['category', 'date', 'score', 'rank', 'order']]
def display_filter_category(self,df,title):
category_list = list(df['category'].unique())
select = widgets.SelectMultiple(
options=['全部'] + category_list,
rows=10,
value=['全部'],
disabled=False
)
dates=sorted(list(df['date'].unique()))
options = [(i[-5:].replace("-",""), i) for i in dates]
slider=widgets.SelectionRangeSlider(
options=options,
index=(0, len(dates)-1),
description='日期',
disabled=False
)
btn = widgets.Button(
description='应用',
)
out = widgets.Output()
box = widgets.VBox([widgets.HBox([slider,select,btn]), out])
display(box)
def on_value_change(change):
categories = df[(df['date']>=slider.value[0])&(df['date']<=slider.value[1])]['category'].unique()
select.options=['全部']+list(categories)
select.value=['全部']
slider.observe(on_value_change, names='value')
@out.capture()
def button_click(e):
cats = list(select.value)
dfs = df[(df['date']>=slider.value[0])&(df['date']<=slider.value[1])]
if "全部" not in cats:
dfs = df[df['category'].isin(cats)]
dspl.clear_output('wait')
display(self.plot_category_hot(dfs, title))
btn.on_click(button_click)