上一节回顾
在上一节中,从股票的基本功能和主要数据进行小结,明确了进行backtrader回测所需要的数据,并且学习了backtrader的数据来源以及PandasData的格式要求,已经做到假设拿到.txt或.csv文件后,能把里面的股票基本数据(6项)处理成backtrader接受的格式,并加入backtrader进行回测。
本节实践目标
- 某支股票的日线数据获取
- 沪深京全股票列表获取与制作
- ETF/LOF列表获取与制作
- 根据全股票列表完成代码、拼音缩写以及中文名称的任意搜索
- 自选股列表制作以及多股票循环回测
01_某支股票的日线数据获取
001_tushare.pro的获取
首先可以确定,当前2024年tushare已经不能用了,前几年的参考文档大多都是基于tushare来做的,这没过多久一眨眼世界就全变了。就像当年的小灵通,就像当年的诺基亚,就像当年的Adobe Flash,自己花了挺长时间去学习和研究,结果一转眼它就退出历史舞台了。
# 尝试老版本的数据调用
import tushare as ts
df1 = ts.get_hist_data('600848')
df1
---------------------
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2
HTTP Error 404: Not Found
HTTP Error 404: Not Found
HTTP Error 404: Not Found
OSError: 获取失败,请检查网络.
由于它的报错里还给你提供了Pro版的接口,所以第一时间我们被引流到了tushare.pro这里。
Tushare数据
Tushare.pro采用的是积分制,应该是运营成本的问题,相当于数据调取是有权限的,每个用户都会有个token,调取数据会用到,新用户是120积分,很多的数据调取是没有权限的。
股票的历史行情数据调取是可以的。先在官网上--个人主页--接口Token中复制好你的专属Token,然后开始历史行情数据的获取。
mytoken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
import tushare as ts
ts.set_token(mytoken)
pro = ts.pro_api()
df = pro.daily(ts_code='002519.SZ',adj='qfq' )
df
------------------------------
ts_code trade_date open high low close pre_close change pct_chg vol amount
0 002519.SZ 20240909 4.35 4.41 4.31 4.37 4.37 0.00 0.0000 102720.70 44840.7400
1 002519.SZ 20240906 4.46 4.47 4.36 4.37 4.46 -0.09 -2.0179 142496.70 62822.5690
2 002519.SZ 20240905 4.42 4.48 4.41 4.46 4.42 0.04 0.9050 134730.29 59894.7670
3 002519.SZ 20240904 4.43 4.49 4.42 4.42 4.48 -0.06 -1.3393 126888.00 56413.2490
4 002519.SZ 20240903 4.45 4.51 4.43 4.48 4.44 0.04 0.9009 133124.75 59516.6510
... ... ... ... ... ... ... ... ... ... ... ...
3201 002519.SZ 20101213 46.83 49.94 46.71 49.03 46.83 2.20 4.7000 25985.88 126183.4667
3202 002519.SZ 20101210 45.08 46.98 45.07 46.83 46.29 0.54 1.1700 19911.31 92133.9409
3203 002519.SZ 20101209 49.01 49.50 46.21 46.29 50.09 -3.80 -7.5900 42875.93 203500.2357
3204 002519.SZ 20101208 50.08 52.88 49.82 50.09 51.92 -1.83 -3.5200 52722.99 268521.1764
3205 002519.SZ 20101207 51.50 57.50 51.04 51.92 36.80 15.12 41.0900 110572.18 598764.3096
根据上节的交给backtrader前的处理,我们能看到tushare.pro得到的股票的历史行情数据有一些特点:
- 索引是数字
- 代码是6位数据加上市场的拼音缩写,比如深圳(SZ)
- 日期是倒序的
- 开、高、低、收的英文与backtrader接受的相同,成交量是vol,需要改为volume
- 有些列不需要,日涨跌change及日涨跌幅度 pct_chg (这个相当于收益率,可用于评价)
002_数据的保存与更新
数据获取后应当保存在本地,避免重复的调用接口且可以在没有网络的情况下进行回测。另外,保存在本地可以追加数据。
要追加数据,就要用到索引,数字的索引可做不到正确的追回数据,必须使用datetime。
003_Akshare的获取
其实,除了tushare.pro外,现在有很多的可以获取股票数据的方式,比如Akshare,qstock...
这里就简单借用akshare来获取日线的历史行情数据。
import akshare as ak
stock_zh_a_hist_df = ak.stock_zh_a_hist(symbol="000001",
period="daily",
start_date="20200301",
end_date='20241028',
adjust="qfq")
stock_zh_a_hist_df
-----------------------------
日期 股票代码 开盘 收盘 最高 最低 成交量 成交额 振幅 涨跌幅 涨跌额 换手率
0 2020-03-02 000001 12.92 13.16 13.32 12.83 1116581 1.647432e+09 3.81 2.25 0.29 0.58
1 2020-03-03 000001 13.33 13.09 13.36 13.00 1153584 1.705816e+09 2.74 -0.53 -0.07 0.59
2 2020-03-04 000001 13.05 13.06 13.15 12.88 862595 1.261123e+09 2.06 -0.23 -0.03 0.44
3 2020-03-05 000001 13.17 13.76 14.01 13.10 2686602 4.089494e+09 6.97 5.36 0.70 1.38
4 2020-03-06 000001 13.55 13.40 13.64 13.39 1228531 1.858691e+09 1.82 -2.62 -0.36 0.63
... ... ... ... ... ... ... ... ... ... ... ... ...
1098 2024-09-04 000001 10.05 10.02 10.15 10.00 847992 8.522247e+08 1.49 -0.60 -0.06 0.44
1099 2024-09-05 000001 10.03 10.07 10.08 9.98 594209 5.958458e+08 1.00 0.50 0.05 0.31
1100 2024-09-06 000001 10.06 10.08 10.21 10.05 878865 8.915078e+08 1.59 0.10 0.01 0.45
1101 2024-09-09 000001 10.05 9.85 10.07 9.84 1639175 1.624858e+09 2.28 -2.28 -0.23 0.84
1102 2024-09-10 000001 9.86 9.90 9.92 9.78 767901 7.561248e+08 1.42 0.51 0.05 0.40
在获取了某股的历史行情后,我们再使用与第1节相同的处理方式,就可以把数据送到backtrader里进行回测了。
df = hist_df
df.rename(columns={
'日期':'date',
'开盘':'open',
'收盘':'close',
'最高':'high',
'最低':'low',
'成交量':'volume',
},inplace=True)
df.index = pd.to_datetime(df.date)
df['openinterest'] = 0
df = df[['open','high','low','close','volume','openinterest']]
df
-----------------------
open high low close volume openinterest
date
2020-03-02 2.48 2.54 2.48 2.52 1010956 0
2020-03-03 2.53 2.55 2.52 2.54 1114739 0
2020-03-04 2.53 2.56 2.53 2.55 701546 0
2020-03-05 2.56 2.59 2.56 2.58 1194563 0
2020-03-06 2.57 2.58 2.55 2.55 808703 0
... ... ... ... ... ... ...
2024-08-07 4.61 4.66 4.59 4.62 1419535 0
2024-08-08 4.63 4.65 4.61 4.62 734659 0
2024-08-09 4.62 4.65 4.60 4.63 961159 0
2024-08-12 4.63 4.68 4.62 4.66 1027279 0
2024-08-13 4.65 4.72 4.64 4.70 1491920 0
02_股票全列表获取
这个在tushare.pro中是可以获取的,但积分需要2000,所以很多人是不能通过tushare.pro来调取的,所以这里我们用Akshare来获取。
使用Akshare也有几种方式可以来获取到全股票列表,其中的一种是直接调用东财接口获取
import akshare as ak
# 股票列表
stock_info_a_code_name_df = ak.stock_info_a_code_name()
stock_info_a_code_name_df
-------------------------------
code name
0 000001 平安银行
1 000002 万 科A
2 000004 国华网安
3 000006 深振业A
4 000007 全新好
... ... ...
5345 873806 云星宇
5346 873833 美心翼申
5347 920002 万达轴承
5348 920008 成电光信
5349 920118 太湖远大
5350 rows × 2 columns
另一种是通过调用实时行情,然后从里面把股票列表给取出来。两种方式获取到的排列顺序是不同的,上面是以代码000001开始的按数字顺序排序,而调用实时行情的是以涨跌幅进行的排序。
# 股票实时行情数据
import akshare as ak
stock_zh_a_spot_em_df = ak.stock_zh_a_spot_em()
stock_zh_a_spot_em_df.iloc[:,:5]
-----------------------------
序号 代码 名称 最新价 涨跌幅
0 1 300134 大富科技 10.61 20.02
1 2 300925 法本信息 12.25 19.98
2 3 300030 阳普医疗 5.83 19.96
3 4 300510 金冠股份 3.85 19.94
4 5 300157 新锦动力 2.48 19.81
... ... ... ... ... ...
5636 5637 002520 日发精机 5.37 -10.05
5637 5638 600576 祥源文旅 5.00 -10.07
5638 5639 002596 海南瑞泽 1.69 -10.11
5639 5640 300068 南都电源 10.67 -11.31
5640 5641 300205 ST天喻 4.23 -12.24
5641 rows × 5 columns
03_ETF列表
ETF列表这里直接调用ETF实时行情,从里面取代码和名称即可
# ETF 列表 -- 按当天涨跌幅顺序
import akshare as ak
fund_etf_spot_em_df = ak.fund_etf_spot_em()
fund_etf_spot_em_df.iloc[:,:8]
--------------------------
代码 名称 最新价 IOPV实时估值 基金折价率 涨跌额 涨跌幅 成交量
0 159527 数据ETF 0.930 0.9287 -0.14 0.029 3.22 25433.0
1 159890 云计算ETF 0.738 0.7373 -0.09 0.021 2.93 222770.0
2 561010 软件ETF基金 0.651 0.6510 0.00 0.018 2.84 20005.0
3 560660 云50ETF 0.700 0.6989 -0.16 0.019 2.79 26965.0
4 159852 软件ETF 0.490 0.4897 -0.06 0.013 2.73 1098940.0
... ... ... ... ... ... ... ... ...
950 560080 中药ETF 0.952 0.9494 -0.27 -0.019 -1.96 450444.0
951 561510 中医药ETF 0.931 0.9302 -0.09 -0.019 -2.00 59762.0
952 159647 中药ETF 0.882 0.8797 -0.26 -0.018 -2.00 325992.0
953 562390 中药50ETF 0.872 0.8704 -0.18 -0.019 -2.13 40116.0
954 159666 交通运输ETF 0.849 0.8494 0.05 -0.020 -2.30 20067.0
955 rows × 8 columns
04_添加拼音缩写
上面的步骤完成后,我们就有了全股票以及ETF的列表,这个时候我们就可以根据列表进行查找,然后再用tushare.pro或者akshare对这个股票/ETF的历史行情数据进行请示调取了。
这里就借鉴各股票软件文本输入框的功能,可以是数字代码,也可以是中文名称或者拼音缩写。在全股票列表中已经有代码和中文名称,我们只需要在它里面添加上一列拼音首字母缩写就可以了。
借用pypinyin库来制作,这个库的安装直接在cmd窗口里pip install即可。
pip install pypinyin
然后,直接问AI "使用pypinyin库获取中文名称的拼音首字母缩写,请提供代码",得到回答:
from pypinyin import lazy_pinyin
def get_initials(name):
"""
获取中文名称的拼音首字母缩写。
"""
initials = [pinyin[0].upper() for pinyin in lazy_pinyin(name)]
return ''.join(initials)
# 示例使用
if __name__ == "__main__":
name = "工商银行"
initials = get_initials(name)
print(f"拼音首字母缩写: {initials}")
-------------
拼音首字母缩写: GSYH
这里其实已经能满足大部分股票的需要了,但是在股票里还有一些比如ST开头的,我们需要把英文字符都显示出来,于是我们再次问AI,得到的回答:
from pypinyin import lazy_pinyin
def get_initials(mixed_string):
"""
获取包含中文和英文的字符串的拼音首字母缩写。
"""
# 分离中文和英文部分
chinese_part = ''
english_part = ''
for char in mixed_string:
if '\u4e00' <= char <= '\u9fff': # 判断是否为中文字符
chinese_part += char
else:
english_part += char
# 获取中文部分的拼音首字母
chinese_initials = [pinyin[0].upper() for pinyin in lazy_pinyin(chinese_part)]
# 获取英文部分的首字母
english_initials = [word[0].upper() for word in english_part.split()]
# 合并结果
initials = chinese_initials + english_initials
return ''.join(initials)
# 示例使用
if __name__ == "__main__":
mixed_string = "ST星光"
initials = get_initials(mixed_string)
print(f"拼音首字母缩写: {initials}")
-------------
拼音首字母缩写: XGS
但是这次,AI给出的代码出问题了,从代码上看,把中文字符和非中文分开来是没问题的,但是顺序上就变成了先中文后非中文,这样是不对的,这里需要再给AI说明一下,并且我们又在ETF里发现一堆例如“沪深300ETF天弘”,"中证1000ETF"等里面除了中文和英文还有数字的,一并交给AI进行,就得到了最终版的代码:
from pypinyin import lazy_pinyin
def get_initials(mixed_string):
"""
获取包含中文和英文的字符串的拼音首字母缩写。
参数:
mixed_string (str): 包含中文和英文的字符串。
返回:
str: 拼音首字母缩写。
"""
initials = []
for char in mixed_string:
if '\u4e00' <= char <= '\u9fff': # 判断是否为中文字符
# 对于中文字符,获取其拼音首字母
pinyin = lazy_pinyin(char)[0]
initials.append(pinyin[0].upper())
elif char.isalpha(): # 对于英文字符,直接获取首字母
initials.append(char.upper())
else: # 对于数字或其他字符,直接保留
initials.append(char)
return ''.join(initials)
# 示例使用
if __name__ == "__main__":
mixed_string = "沪深300ETF天弘"
initials = get_initials(mixed_string)
print(f"拼音首字母缩写: {initials}")
---------------------
拼音首字母缩写: HS300ETFTH
完成了添加拼音首字母缩写之后,我们就可以在全股票列表添加一列“PY_ABBR”,然后apply刚上的函数
code_name_df['PY_ABBR'] = code_name_df.name.apply(get_initials)
code_name_df
---------------------------
code name PY_ABBR
0 000001 平安银行 PAYX
1 000002 万 科A W KA
2 000004 国华网安 GHWA
3 000006 深振业A SZYA
4 000007 全新好 QXH
... ... ... ...
5345 873806 云星宇 YXY
5346 873833 美心翼申 MXYS
5347 920002 万达轴承 WDZC
5348 920008 成电光信 CDGX
5349 920118 太湖远大 THYD
5350 rows × 3 columns
至此,通过查表,就可以以任意一种方式返回我们所需要的股票的代码,然后再通过xxshare请求该股票的历史行情数据了。
05_自选股列表
当我们进行策略回测时,没有效率的做法是想起一支股票好像叫什么名字,然后查询得到这支股票,然后再做回测;而没有意义的做法是把全股票列表中的所有股票都回测一遍。
参考股票软件,都会有自选股,而且现在都可以分组,分很多组那种,有的股票软件称为自定义板块。所以,一般的情况下,我们都会有一组自己在意的股票,往往我们只要对这一组股票进行回测就可以了。
制作自选股列表非常简单,直接用一个list保存就可以了,或者保存在一个.csv或.txt文件中,每次读取这个文件就能得到自选股列表,当我们需要对其中某支或某几支进行回测时,我们输入它的index即可,而如果我们需要对全部的自选股进行回测,则简单使用for in循环就可以搞定。
在后续backtrader一系列实践完成后,假如我们做一个窗口程序,那么自选股列表就可以以checklist的形式显示出来,需要回测哪几支,直接勾选上就好。
本节小结
这一节我们对股票一系列数据的获取和制作进行了实践,通过实践我们知道了怎么通过tushare.pro或akshare获取某股票的历史行情数据,也知道了怎么制作全股票列表和ETF列表,并且我们添加了拼音首字母缩写以及自选股列表,让backtrader的回测在数据准备方面更加的方便有效,从而提高将来我们回测和分析的效率~