本节简介:
本节将带你迈出量化投资的第一步,获取金融数据!
有了金融数据,你就可以开始量化研究、构建策略!
本关卡旨在帮助学员掌握金融数据的获取和整理技能,包括股票、期货、基金、债券等数据。通过案例实践,学员将学会如何使用Python获取数据、整理数据,并描述性分析和统计。
1、金融数据的获取
金融数据是一个很大类的统称。例如利率是金融数据,股票价格也是金融数据,期货价格也是金融数据!
1.1股票数据的获取
股票作为重要的金融资产之一,量化投资方法在股票市场上得到了广泛应用。
相关的数据如:股票价格、股票交易量、股票交易量、公司财务等数据就是量化投资研究必不可少的基石。
#导入相关库,为了避免重复,这里一次性导入本内容所需要的所有库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import akshare as ak
import warnings
import time
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['Source Han Sans CN']#和鲸平台可用的中文字体
plt.rcParams['axes.unicode_minus'] = False
# 设置全局字体
#利用开源/付费接口获取股票数据,并绘制走势图
#这里使用的是akshare的股票数据接口作为示例,AKShare 主要是用于财经研究,解决在财经研究中数据获取的问题。项目地址:https://github.com/akfamily/akshare
#获取数据的方法已经封装好了,只需要填充一些参数就可以了,例如akshare获取贵州茅台股票数据,方法详细说明见akshare说明文档
stock_600519 = ak.stock_zh_a_hist(
symbol="600519",#需要获得数据的股票代码
period="daily",#数据周期,一般有分/日/周/月
start_date="20200101",#数据起始日期
end_date='20231201',#数据结束日期
adjust="hfq")#数据格式
stock_600519#查看获取的数据
ak.stock_zh_a_hist这个方法本身返回的数据其实有很多类别,例如价格数据(开盘/收盘/最高价/最低价)、涨跌幅数据等,我们只需要拿走自己需要的数据或者合并即可!
#可视化看看收盘价走势!
stock_600519.plot(x='日期',y='收盘',figsize=(15,8))
关于股票价格的一些阅读材料
由于股票存在配股、分拆、合并和发放股息等事件,会导致股价出现较大的变化。若不注意这一点就处理数据、计算各种指标,将会导致它们失去连续性,计算收益也会出现错误。所以为了保证数据连贯性,常通过前复权或后复权对价格序列进行调整。
前复权:保持当前价格不变,将历史价格进行增减,从而使股价连续。 前复权用来看盘非常方便,能一眼看出股价的历史走势,叠加各种技术指标也比较顺畅,是各种行情软件默认的复权方式。
缺点一:会导致在不同时点看到的历史前复权价可能出现差异。
缺点二:对于有持续分红的公司来说,前复权价可能出现负值。
后复权:保证历史价格不变,在每次股票权益事件发生后,调整当前的股票价格。
后复权价格和真实股票价格可能差别较大,不适合用来看盘。优点在于可以被看作投资者的长期财富增长曲线,反映投资者的真实收益率情况。
一般情况下,看盘用前复权,研究用后复权
1.2获取股票数据练习题
动动手指,试着获取平安银行的数据吧。
请下面代码中,请在symbol参数中填入平安银行的代码000001,在start_date和end_date中填入你想要获取的数据的时间段(格式为20200101),然后运行代码。
stock_000001 = ak.stock_zh_a_hist(
symbol='',#需要获得数据的股票代码
period="daily",#数据周期,一般有日/周/月
start_date='',#数据起始日期,引号中填写
end_date='',#数据结束日期,引号中填写
adjust="hfq")#数据格式
stock_000001#查看获取的数据
#删除前后的三引号,填写完整代码运行,否则会报错。
'''
stock_000001 = ak.stock_zh_a_hist(
symbol='',#需要获得数据的股票代码
period="daily",#数据周期,一般有日/周/月
start_date='',#数据起始日期,引号中填写
end_date='',#数据结束日期,引号中填写
adjust="hfq")#数据格式
stock_000001#查看获取的数据
'''
1.3期货数据获取
get_futures_daily_hist = ak.get_futures_daily(start_date="20231101", end_date="20231130", market="SHFE")
get_futures_daily_hist
#这里获取的数据是上海期货交易所交易品种的数据,我们看看cu2312(沪铜2312期货合约)相关的数据。
get_futures_daily_hist.query("symbol=='CU2312'")
#看看走势图,下面用的链式方法调用,可视化查看收盘价走势
get_futures_daily_hist.query("symbol=='CU2312'").plot(x='date',y='close',figsize=(15,5))
1.4数据筛选小练习:
上面使用了pandas的query方法筛选出来CU2312合约并可视化,你可以使用尝试筛选出来AU2312合约的数据并可视化吗?
关于期货合约的一些阅读材料
由于期货合约本身到期交割,并非永续存在,所以一个期货交易品种,存在不同时间的合约,例如沪铜2312合约,在2023年12月15日停止交易,后面到期后这个合约就不存在交易市场上了,最临近的合约就是沪铜2401合约。
所以,我们在做期货量化策略研究的时候,一定要注意期货合约价格的连续性,或者说数据是否完整,因为可能存在合约到期的情况,导致数据不完整,从而影响策略的准确性。
一般情况下,主力合约连续价格可以作为回测基准数据,当然具体需要什么数据,还是需要根据你的策略来获取
1.5获取数据小结
我们以akshare为例获取了股票/期货的行情数据,使用的是开源库本身封装好的方法,方法相对简单,无论是股票/期货还是债券/基金,获取数据方法都一样,只需要找到开源库对应的函数,填写相应的参数即可,这里因为篇幅限制,无法一一举例,详情可以去项目说明文档查看。
1.6其它获取数据的方法
上面我们是以AKshare这个开源财经库举例,实际上获取数据的方法还有很多,例如:
1.部分行情软件提供数据下载服务,可以下载到本地进行保存研究。
2.python库接口,如tushare注册后可获取部分数据。
3.付费数据接口,如各个财经公司/量化平台提供的数据接口,可在线调用或保存本地。
总之,数据是为研究服务,获取的方法/方式互为补充!
2、数据整理及统计
数据整理及统计是量化金融的重要步骤之一,它通过对数据进行清洗、整理、归纳和可视化等操作,将原始数据转化为具有实用价值的统计信息,以便更好地进行分析和决策。
2.1数据整理的要求
说多了太复杂,数据整理的要求就两条:
让数据变完整:确保数据的完整性,即所有需要的数据是完整连续的。
让数据更准确:确保数据的准确性,即数据是真实和准确的,没有较大的错误或偏差。
#例如我们接下来的研究需要用茅台的历史收盘价序列,我们首先要做的就是查看数据是否完整!
#用xx.isnull().sum()方法查看是否有空值
stock_600519_test=stock_600519[['收盘','日期']]#选取日期,收盘价两列数据
stock_600519_test.isnull().sum()
stock_600519_test
#查看数据格式,是否需要调整
stock_600519_test.info()
#价格数据为float64无需调整,但是日期为obj格式,需要调整为datetime格式。避免后期测试报错。
#设置日期为index,并且转为datetime格式
stock_600519_test['日期']=pd.to_datetime(stock_600519_test['日期'])
stock_600519_test.set_index('日期',inplace=True)
stock_600519_test
stock_600519_test.info()
#这里数据调整过来后,接下来看看数据有无异常
#这里特别提醒一下,所谓的异常数据是根据数据本身来判断的,比如价格数据某一天价格是0,或者某一天价格是负数,这些数据都是异常数据,需要我们调整过来。
#查看价格数据是否有为0或负数的
print(stock_600519_test.apply(lambda x: x[x<=0].value_counts()))
#最后可以可视化查看一下。
stock_600519_test.plot()
2.2小结:
获取数据要求完整、连续、真实,如果没有以上查阅结果显示,价格数据没有空值和异常值,且数据是连续的。
2.3本节思考:
那如果开盘、最高、最低、收盘数据出现缺失怎么办?我们应该如何填充?
提示:数据填充一般有几种方法——前值/后值/均值/中位数/众数/线性回归/插值法等。但注意这里是价格数据,且是连续时间序列,如果设身处地站在T时刻,你没法获取t+1时刻及之后的任何数据(因为是未来),填充中位数/均值等统计数据可能会造成时序价格大幅变动,那么此时t时刻你能填充的数据是?
2.4原始数据探索与统计
原始数据的探索统计方向有数据分布、数据相关性、均值/方差等,探索和统计一定是带有强烈目的性,这样才能节约时间,有利于后续建模。
例如我想知道茅台:
- 是否具有月份效应——每年某个月都上涨或者下跌?
- 价格走势与指数的相关性如何?
- 价格波动与同行业其它个股的关系如何?
- 涨跌幅分布如何?
那么我就要进行对应的探索。
#例如对茅台股价涨跌幅分布的探索
stock_600519['涨跌幅'].hist()#直方分布图
#例如上期所期货的相关性研究探索。
get_futures_pivot_tabl=get_futures_daily_hist.pivot_table(values='close',index='date', columns='symbol',aggfunc='sum')
'''pandas.pivot_table 的参数说明:
data: 需要创建透视表的 DataFrame。
values: 需要进行透视的列名。
index: 透视表的行标签。
columns: 透视表的列标签。
aggfunc: 聚合函数或函数列表。默认是 'sum'。可以是 'sum', 'mean', 'count', 'min', 'max' 等'''
get_futures_pivot_tabl
import seaborn as sns
get_futures_pivot_tabl.loc[:,['AG2312','CU2312']]#找出部分合约来看看相关性
# 绘制热力图
sns.heatmap(get_futures_pivot_tabl.loc[:,['AG2312','CU2312']].corr())
# 显示图形
plt.show()
#数据统计方面,使用describe()方法查看常见统计数据。
stock_600519.describe()
2.5本节练习题
上面案例查看了'AG2312','CU2312'两个合约的相关系数,你能利用上述代码,可视化CU2312与AU2312的相关系吗?
提示:数据整理已经做好了,可视化只需要改动对应期货合约代码即可。
获取数据后的统计,可以是集中趋势的度量,如:平均数、中位数、众数、分位数等;也可以是分散程度的度量,如:方差、标准差、极差等;当然也可以是位置的度量,如分位数。
2.6本节小结:
金融数据的探索和统计方法其实并不复杂,探索和统计的目的是为了更了解数据,为后续的建模做准备。例如在数据探索中,我发现A股票和B股票历史走势极度趋同,相关系数较高,那么统计分析两者的价差或者价格比后,也具有显著性,我是不是可以据此指定一个量化策略?
很多量化策略的诞生都是源于原始金融数据探索统计。
3、获取数据python函数化
一般情况下,我们可以自定义函数,以解决重复写代码的问题。
例如获取100只个股的历史数据,正常调用接口就需要100次,如果循环调用,上下文代码变量会有冲突,这个时候我们就可以自定义封装一个函数。后续只需要调用函数名即可。
#股票列表
# 举例,一般股票列表自己设置或者通过ak.stock_zh_a_spot_em() 中获取
'''stocks = ['000001', '600519', '601398']
for i in stocks:
stock_data = ak.stock_zh_a_hist(
symbol=i,#需要获得数据的股票代码
period="daily",#数据周期,一般有分/日/周/月
start_date="20200101",#数据起始日期
end_date='20231201',#数据结束日期
adjust="hfq")#数据格式
# 保存
stock_data.to_csv(r'\home\mw\%s.csv' % i, index=False)
time.sleep(1)'''
#这样获取数据,上下文代码变量容易冲突不说,每次还要重复粘贴。
#修改一些,自定义函数。
def get_stock_save(stocks:list,period:str,start_date:str,end_date:str,adjust:str):
'''
period:数据周期,三选一['daily', 'weekly', 'monthly']
start_date:数据起始日期->'20200101'
end_date:数据结束日期->'20210101'
adjust:数据格式->'qfq' or 'hfq'
'''
for i in stocks:
stock_data = ak.stock_zh_a_hist(
symbol=i,#需要获得数据的股票代码
period=period,#数据周期,一般有分/日/周/月
start_date=start_date,#数据起始日期
end_date=end_date,#数据结束日期
adjust=adjust)#数据格式
# 保存
stock_data.to_csv(r'\home\mw\%s.csv' % i, index=False)#在本地运行,需要正确粘贴路径
time.sleep(1)
#我们自定义好需要获取的股票列表,调用函数就可以保存数据了
stocks = ['000001', '600519', '601398']
get_stock_save(stocks,'daily','20200101','20231201','hfq')
这里有一个建议,凡是高频且重复的代码,建议封装成函数,这样调用比较节约时间。
封装函数可以层层嵌套,比如我们获取股票数据,再对数据进行清洗,再保存也可以写成函数。
至于函数名称的命名,一般按照功能命名,比如获取股票数据的函数,可以命名为get_stock_data。
当然,你写 def abcd():也没关系,前提是你自己能记住,与人合作的时候,你还要让其他的人也记住才行0.0