要點:
?1筒狠、數(shù)據(jù)的分析與爬取
2舔庶、pyecharts繪圖
數(shù) 據(jù) 源
數(shù)據(jù)來源我們選擇新浪財經(jīng)基金板塊:https://finance.sina.com.cn/fund/
我們隨便選一個基金抛蚁,就選第一個吧:660001,農(nóng)銀行業(yè)成長混合A
老辦法惕橙,監(jiān)控Network
通過分析瞧甩,我們發(fā)現(xiàn)了三個request:
今日的實時數(shù)據(jù)從下面的連接返回
返回信息格式如下
var t1fu_660001=({"yes":"2.6775","detail":"09:30,2.6822,09:31,...,15:03,2.7189"});
歷史數(shù)據(jù)從下面的連接返回
https://finance.sina.com.cn/fund/api/xh5Fund/nav/660001.js
返回信息格式如下
xh5Fund({"data":"20200220,2.6775,3.2775,4.15436,82.38,81.8,56.24#
20200219,2.6223,3.2223,4.06871,84.26,81.19,55.47#...#20080804,1,1,1,,,","symbol":"660001","fhday":"20091123,20100426","fhvalue":"0.4,0.2","fhchaifen":"0,0"})
數(shù)據(jù)順序為:日期、單位凈值弥鹦、累積凈值肚逸、歷史回報、排位百分比彬坏、排位百分比朦促、排位百分比
查詢時間下的基金綜合數(shù)據(jù)
https://hq.sinajs.cn/list=fu_660001
返回信息
var hq_str_fu_660001="農(nóng)銀行業(yè)成長混合A
,15:04:00,2.6722,2.6223,3.2223,0.0262,1.9029,2020-02-20";
爬取并解析數(shù)據(jù)
了解了以上信息,我們就可以用requests獲得返回的數(shù)據(jù)栓始。
我們可以先定義header务冕,假裝是瀏覽器訪問網(wǎng)站
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 SLBrowser/10.0.3929.400",
}
實時數(shù)據(jù)的解析
解析返回的實時數(shù)據(jù)字符串,按照 左括號 ( 與右括號 ) 拆分幻赚,將提取出的大括號{}中的數(shù)據(jù)利用ast.literal_eval轉(zhuǎn)換為字典禀忆。yes對應(yīng)的字符串直接轉(zhuǎn)換為float,detail對應(yīng)的字符串按照 逗號 坯屿, 拆分油湖,每兩個數(shù)據(jù)一組,第一個為“時間”保持字符串即可领跛,第二個為“實時數(shù)據(jù)”轉(zhuǎn)換為float乏德。將解析好的數(shù)據(jù)再次打包為字典即可備用。
歷史數(shù)據(jù)的解析
歷史數(shù)據(jù)的解析吠昭,與實時數(shù)據(jù)基本相似喊括,也是先通過對左右括號的拆分,提取出需要的字典字符串?dāng)?shù)據(jù)矢棚,而后利用ast.literal_eval將字符串轉(zhuǎn)為字典郑什。字典的data中是每日數(shù)據(jù),這里用 # 號拆分歷史每日數(shù)據(jù)字符串蒲肋,再將每一天的數(shù)據(jù)字符串用 逗號, 拆分蘑拯,依照數(shù)據(jù)順序轉(zhuǎn)換為float打包為最終字典即可钝满。
定義抓取數(shù)據(jù)函數(shù)代碼,返回 實時數(shù)據(jù)字典 與 每日數(shù)據(jù)字典
# -*- coding:utf-8 -*-
import requests
import re
import ast
header = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 SLBrowser/10.0.3929.400",
}
today_url_format = "https://app.xincai.com/fund/api/jsonp.json/var%20t1fu_{}=/XinCaiFundService.getFundYuCeNav?symbol={}&___qn=3"
both_url_format = "https://finance.sina.com.cn/fund/api/xh5Fund/nav/{}.js"
name_url_format = "https://hq.sinajs.cn/list=fu_{}"
def catchData(code):
today_url = today_url_format.format(code,code)
both_url = both_url_format.format(code)
name_url = name_url_format.format(code)
#獲得當(dāng)天數(shù)據(jù),步長為分鐘
today_response = requests.get(today_url,headers=header)
today_str = re.split("[()]",today_response.text)[1]#通過()拆分字符串
today_dict_one = ast.literal_eval(today_str)#初步生成字典
minute_list_strs = today_dict_one['detail'].split(',')#拆分字典中detail的字符串
minute_dict = {}
for i in range(0,len(minute_list_strs),2):
minute_dict[minute_list_strs[i]] = float(minute_list_strs[i+1])
today_dict = {"yes":float(today_dict_one["yes"]),"detail":minute_dict}
#獲得全部數(shù)據(jù)申窘,步長為天
both_response = requests.get(both_url,headers=header)
both_str = re.split("[()]",both_response.text)[1]
both_dict_one = ast.literal_eval(both_str)
day_list_strs = both_dict_one['data'].split('#')
day_list = {}
for i in range(len(day_list_strs)):
str = day_list_strs[i];
str_list = str.split(',')
day_list[str_list[0]] = {"dwjz":str2float(str_list[1]),"jljz":str2float(str_list[2]),
"lshb":str2float(str_list[3]),"mper":str2float(str_list[4]),
"qper":str2float(str_list[5]),"yper":str2float(str_list[6])}
both_dict = {"symbol":both_dict_one["symbol"],"fhday":both_dict_one["fhday"],
"fhvalue":both_dict_one["fhvalue"],"fhchaifen":both_dict_one["fhchaifen"],
"data":day_list}
#獲取基金名稱
name_response = requests.get(name_url,headers=header)
name_str = name_response.text.split('="')[1].split(',')[0]
today_dict["name"] = name_str
both_dict["name"] = name_str
return today_dict,both_dict
def str2float(str):
return 0 if ''==str else float(str)
調(diào)用函數(shù)
我們只需要給出基金代碼弯蚜,既可以獲得數(shù)據(jù)字典
code = "660001"
today_dict,both_dict = catchData(code)
繪制數(shù)據(jù)曲線
pyecharts是非常強大的繪圖工具,非常好用剃法。分為 v0.5.X 和 v1 兩個大版本碎捺,v0.5.X 和 v1 間不兼容,v1 是一個全新的版本贷洲。目前官方已經(jīng)不再維護v0.5.X版本收厨,因此本文建議讀者使用v1版本。
注:v1版本僅支持 Python3.6+
特別注意:本文使用的環(huán)境是一款神器jupyter lab优构,在該環(huán)境下可以使用
render_notebook()直接繪制pyecharts圖形诵叁。但是因為其無法得知用戶的具體開發(fā)環(huán)境,因此需要指定開發(fā)環(huán)境:
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
如果在調(diào)用render_notebook()時繪制的依然為空白俩块,說明環(huán)境沒有正確加載echarts.js等文件黎休,只需要在繪制前調(diào)用:load_javascript()即可。
在jupyter lab環(huán)境中玉凯,調(diào)用load_javascript()與render_notebook()需要和設(shè)置圖形的代碼段分開势腮。
具體詳見官方文檔:
https://pyecharts.org/#/zh-cn/notebook?id=jupyter-lab
繪制實時數(shù)據(jù)折線圖
下面介紹一下繪制實時數(shù)據(jù)折線圖的關(guān)鍵點:
1)通過is_smooth=True可以平滑折線圖
2)通過extend_axis函數(shù)定義第二個y軸,并設(shè)置其格式:formatter="{value} %"
3)字典的keys方法可以將字典的所有索引提取為數(shù)組
4)字典的values方法可以將字典的所有值提取為數(shù)組
from pyecharts.globals import CurrentConfig, NotebookType
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
import pyecharts.options as opts
from pyecharts.faker import Faker
from pyecharts.charts import Line
import numpy as np
yes = today_dict["yes"]
xaxis = list(today_dict["detail"].keys())#獲得x軸數(shù)據(jù)
yaxis = list(today_dict["detail"].values())#獲得y軸數(shù)據(jù)
yaxis_plus_yes = [yes-x for x in yaxis]
dy_max_abs = np.max(np.abs(yaxis_plus_yes))#用來計算百分比和坐標軸范圍
def today_line_smooth() -> Line:
c = (
Line()
.add_xaxis(xaxis)
.add_yaxis("凈值預(yù)測", yaxis , is_smooth=True,is_hover_animation=True,yaxis_index=0)
.extend_axis(
yaxis=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(formatter="{value} %"),
min_=round(-dy_max_abs/yes*100,2),
max_=round(dy_max_abs/yes*100,2)
)
)
.set_global_opts(title_opts=opts.TitleOpts(title="Line-smooth"),
yaxis_opts=opts.AxisOpts(min_=round(yes-dy_max_abs,4),max_=round(yes+dy_max_abs,4)))
)
return c
line = today_line_smooth()
line.load_javascript()
line.render_notebook()
繪制歷史單位凈值及積累凈值曲線
主要需要注意如下幾點:
- 配置AxisOpts漫仆,min_=min,max_=max捎拯,使曲線上只提示最大值和最小值
2)配置TooltipOpts,使鼠標移動顯示十字交叉線盲厌,并提示關(guān)鍵信息:
trigger="axis",trigger_on="mousemove",axis_pointer_type="cross"
3)通過函數(shù)形式署照,返回JsCode字符串設(shè)置自定義Tooltip文字
3.1) 需要包含from pyecharts.commons.utils import JsCode
3.2)JsCode字符串中的字符串必須用單引號'包擴,否則會報錯
3.3)函數(shù)的參數(shù)是個列表吗浩,具體形式可以通過console.log(params)查看建芙,自定義文字所需要的數(shù)據(jù)均在params中,可以通過拼接字符串的型式懂扼,將python中的變量引入到JsCode中禁荸。
def getToolip():
a1 = yaxis_dwjz[0]
a2 = yaxis_jljz[0]
return JsCode("""function (params) {
var dwjz_per = (params[0].value[1]-"""+str(a1)+""")/"""+str(a1)+""";
dwjz_per = (dwjz_per*100).toFixed(2);
var jljz_per = (params[1].value[1]-"""+str(a2)+""")/"""+str(a2)+""";
jljz_per = (jljz_per*100).toFixed(2);
return params[0].axisValue+'<br>'+
params[0].seriesName+' : '+params[0].value[1]+'('+dwjz_per+'%)<br>'+
params[1].seriesName+' : '+params[1].value[1]+'('+jljz_per+'%)<br>';
}""")
定義曲線
from pyecharts.commons.utils import JsCode
datas = both_dict["data"]
xaxis_all = list(datas.keys())
xaxis_all.sort()#升序排列,返回的數(shù)據(jù)是降序的
beginX = "20191113"#設(shè)置繪制的開始時間
endX = "20200221"#設(shè)置繪制的結(jié)束時間
xaxis = []
yaxis_dwjz = []
yaxis_jljz = []
for key in xaxis_all:#提取y軸數(shù)據(jù)
if key<beginX or key>endX:
continue
data = datas[key]
xaxis.append(key)
yaxis_dwjz.append(data["dwjz"])
yaxis_jljz.append(data["jljz"])
#計算坐標軸范圍
max = round(1.05*np.max([yaxis_dwjz,yaxis_jljz]),1)
min = round(0.95*np.min([yaxis_dwjz,yaxis_jljz]),1)
dy_min = (min-yaxis_dwjz[0])/yaxis_dwjz[0]*100
dy_max = (max-yaxis_dwjz[0])/yaxis_dwjz[0]*100
def both_line_smooth_1() -> Line:
c = (
Line()
.add_xaxis(xaxis)
.add_yaxis("單位凈值", yaxis_dwjz)
.add_yaxis("積累凈值", yaxis_jljz)
.extend_axis(
yaxis=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(formatter="{value} %"),
min_=round(dy_min,1),
max_=round(dy_max,1)
)
)
.set_global_opts(title_opts=opts.TitleOpts(title="Line-smooth"),
yaxis_opts=opts.AxisOpts(min_=min,max_=max,interval=round((max-min)/8,1)),
tooltip_opts=opts.TooltipOpts(is_show=True,trigger="axis",
trigger_on="mousemove",axis_pointer_type="cross",
formatter=getToolip()))
.set_series_opts(label_opts = opts.LabelOpts(is_show = False), is_smooth=True,is_hover_animation=True,
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_ = "max",name = "max"),
opts.MarkPointItem(name = "min",type_ = "min")]))
)
return c
line = both_line_smooth_1()
line.render_notebook()
通過同樣的方式阀湿,繪制 歷史回報曲線赶熟、以及排位百分比曲線
總結(jié)
本文為處理量化投資數(shù)據(jù),做了最基本的事情陷嘴。爬取數(shù)據(jù)映砖,解析,并且研究了如何美觀的繪制折線圖灾挨,希望對您有所幫助邑退!