今天给大家分享一个集数据采集、处理、分析、可视化、接口调用等技术点于一体的项目。1、我来说说一件事。早就想做一个基金监控机器人,可以查看自己关心的基金的各种指标的涨跌幅,及时止损或获利。今天先打个基础,引导大家实现一个基金查询机器人,主要可以查询基金指定日期时间段的数据,查看基金当前净值走势图,后续会增加新的功能之后。2.动手动手做Brain2.1环境准备Linux、Mac、Windows都可以。Python3.7及以上相关第三方包:pandas(数据处理)、requests(爬取数据)、re(文本内容分析)、akshare(基金股票数据采集)、matplotlib(数据可视化)、dataframe-image(dataframe表格)转成图片)最近整理了一套编程学习资料分享给大家,全是干货,包括教程视频、电子书、源码笔记、学习路线图、实战项目、面试题等,关注gzh【Python编程学习圈】免费领取,回复关键词【学习资料】即可,抓紧时间!2.2获取指定时间段的基金数据基金数据可以从一些金融相关的网站获取,如天天基金网、新浪基金网等,可以编写爬虫程序获取网站数据,也可以使用现成的制作获取数据的工具包,比如之前介绍过的tushare、akshare等库。这里同时介绍以下两种方法:2.2.1回看akshare获取基金数据目前akshare不支持获取指定日期范围内的基金净值数据,但可以获取基金历史净值数据一次调用函数fund_em_open_fund_info获取基金历史数据。然后根据日期选择时间段进行分析。importakshareasakfund_data=ak.fund_em_open_fund_info(fund='005827',indicator='unitnetvaluetrend')print(fund_data)2.2.2自己调用现成的数据接口akshare本质上也是从一些金融相关的网站,我们也可以自己写代码获取。通过浏览器可以快速搜索到基金数据界面,该界面来自东方财富日报基金网。f'http://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&code={code}&page={page}&sdate={start_date}&edate={end_date}&per={per}'code-基金代码page-基金数据页码start_date-数据开始日期end_date-数据结束日期per-每页显示的数据量,最多40条根据指定的参数,浏览器会返回指定的参数,一段js赋值代码,包括基金数据(content)、总记录数(records)、总页数(pages)、当前页码(curpage)。格式很规则,我们可以直接通过正则化提取数据,'''获取单页资金数据'''defget_html(code,start_date,end_date,page=1,per=40):url=f'http://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&code={code}&page={page}&sdate={start_date}&edate={end_date}&per={per}'#print(url)rsp=请求.get(url)html=rsp.textreturnhtml从返回的数据中可以发现基金数据部分是一段被table标签包裹的html代码,那么我们可以直接使用pandas的read_html来解析数据。#从html中解析数??据表部分,解析成dfdefparses_table(html):#获取基金数据表pattern='content:"
",'table=re.search(pattern,html).group(1)table=''fund_data=pd.read_html(table)[0]returnfund_data前面提到基金数据接口返回的数据可以向上显示到每页40篇文章,所以为了得到所有的数据,我们可能需要遍历每一页,那么我们还需要通过正则化得到总页数,然后遍历并调用get_html和parses_table函数来解析出所有的数据。#获取指定日期内累计净值等数据defget_fund_data(code,start_date,end_date):first_page=get_html(code,start_date,end_date)#获取总页数pattern='pages:(.*),'pages=re.search(pattern,first_page).group(1)#转换为int数据try:pages=int(pages)exceptExceptionase:r=f'【错误信息】{e}'#print(r)#returnrstoreFunddatadatadatadata数据格式方便合并fund_df_list=[]#页页所有ii(PAGES):IFI==0:Fund_data=PARSES_TABLE(First_page)else:Page_html=getml(CEDEML,CEDEML,CED,end_date,page=i+1)fund_data=parses_table(page_html)fund_df_list.append(fund_data)#将每个页面的数据合并在一起fund_df=pd.concat(fund_df_list)_以上两种方法都可以得到基金的净值returntofund最终我选择了akshare方式获取数据,设置定时任务,每天三点更新我关心的funds的所有数据,存储在本地,并且以后想查询的时候直接读取本地文件查询。定时任务:每天凌晨3点获取所有关注资金的历史数据,并保存在本地#定时任务:每天凌晨3点获取所有关注资金的历史数据,并将其存储在本地defget_all():try:#自己从文件Listoffundcodestowatchwithopen('./FD/funds.txt')asf:funds=[i.strip()foriinf.readlines()]#逐一遍历fund更新数据infunds:fundd_f=ak.fund_em_open_fund_info(fund,indicator='unitnetvaluetrend')fund_df=fund_df.sort_values(by=['net值日期'],ascending=False)fund_df.to_csv(f"./FD/DATA/F{fund}_data.csv",index=False)#print(f"./FD/DATA/F{fund}_data.csv")time.sleep(random.randint(1,5))return'Funddataupdatecomplete'exceptExceptionase:r=f"【错误信息】{e}"returnr获取基金净值数据指定日期范围内的指定基金#获取指定日期范围内指定基金的净值数据defget_fund_data(fund,start_d,end_d):fund_df=pd.read_csv(f'./FD/DATA/{fund}_data.csv')result_df=fund_df.query(f"'{start_d}'<=净值日期<='{end_d}'")returnresult_df2.3返回数据展示方法暂时简单,设置规则如下:1)如果数据量小于等于30,则返回原始数据图数据图就是将获取的数据直接转换成图片发送给用户。这里我们使用第三方包dataframe-image,使用起来非常简单。pip安装好后,直接调用export函数即可快速将datafrmae数据转为图片。#将dtaframe表转换为图像defdf_to_img(fund_df,fund,start_d,end_d):iffund_df.shape[0]<=1:dfi.export(fund_df,f'./FD/IMG/{fund}_{start_d}_{end_d}_data.png')return#格式化表格突出显示最大值和最小值fund_df=fund_df.style.highlight_max(subset=['unitnetvalue'],color='red')\.highlight_min(subset=['单位净值'],color='green')\.format({'日增长率':'{:}%'})dfi.export(fund_df,f'./FD/IMG/{fund}_{start_d}_{end_d}_data.png')为了让图片数据更好看,我们还使用了df.style来设置数据表格样式(最大单位净值,最小值突出显示和添加到每日增长率的百分号)。2)如果数据量大于30,则返回原始数据趋势图。原始的数据趋势图是将数据可视化,然后返回给用户。这里我们选择绘制数据的趋势(trend)图,使用matplotlib来绘制。#绘制基金份额净值走势图defdraw_fund_line(fund_df,fund,start_d,end_d):plt.rcParams['figure.figsize']=(8.0,4.0)#设置figure_size大小plt.rcParams['savefig.dpi']=300#保存图片分辨率#不显示右上边框ax=plt.gca()ax.spines['right'].set_color('none')ax.spines['top'].set_color('none')#设置坐标网格plt.grid(axis="y",color='gray')#计算最大最小坐标并在图中标注fund_max=fund_df.loc[fund_df['unitnetvalue'].idxmax()]fund_min=fund_df.loc[fund_df['单位净值'].idxmin()]ax.annotate(f'({fund_max[0]},{fund_max[1]})',xy=(fund_max[0],fund_max[1]),color='red')ax.annotate(f'({fund_min[0]},{fund_min[1]})',xy=(fund_min[0],fund_min[1]),color='green')#绘图plt.plot(fund_df['净值日期'],fund_df['单位净值'],color="c")plt.title('基金单位净值valuechart')plt.xticks(rotation=30)plt.xlabel('EquityDate')plt.ylabel('UnitEquity')plt.savefig(f'./FD/IMG/{fund}_{start_d}_{end_d}_data.png')这里用的是折线图,里面有图片样式的一些设置,比如:大小,边框,最大/最小value标签,不过还是不太美观,后续会继续优化。调用完成#返回数据defresponse_data(fund,start_d,end_d):#本地检查查询结果是否已经存在imgs=os.listdir('./FD/IMG/')iff'{fund}_{start_d}_{end_d}_data.png'inimgs:returnf'./FD/IMG/{fund}_{start_d}_{end_d}_data.png'#获取数据fund_df=get_fund_data(fund,start_d,end_d)#如果data如果金额小于等于30,返回原始数据图iffund_df.shape[0]<=30:df_to_img(fund_df,fund,start_d,end_d)else:#否则,返回数据趋势图fund_df=fund_df.sort_values(by=['权益日'])draw_fund_line(fund_df,fund,start_d,end_d)returnf'./FD/IMG/{fund}_{start_d}_{end_d}_data.png'2.4对接钉钉机器人设置守护进程当前项目对接机器人有两种类型:钉钉群机器人和企业机器人。相关配置方法限于篇幅这里不再介绍。钉钉群机器人主要用于每天自动上报基金数据更新,后期也可以加入基金涨跌幅检测。企业机器人主要用于基金数据查询的自动回复功能,也可扩展为主动向用户发送消息。2.5最终效果图指定查询查看某基金某时间段内的基金净值数据。(30以内的数据,以表格显示;30以上的,以趋势图显示)\\查询格式:F基金代码起止日期,如:F0058272021-12-032022-02-10净值以及一只基金近10天的日涨幅数据+走势图\\查询格式:F基金代码,如:F005827近10天只有两个交易日。不算太小,一百行代码。目前资金监控机器人比较简单,甚至没有监控功能(目前只支持数据查询和更新),但基础非常稳定和深厚,后期添加其他功能会简单方便很多。欢迎在评论区留言,说说你想给这个bot增加什么功能。