量化交易学习(二十四)下载股票数据保存到数据库

在量化投资中,除了策略外,最重要的东西就是数据了,很多的量化教程会用大量篇幅来介绍数据处理清洗相关的知识。今天我来介绍一下怎么通过调用掘金量化的接口下载股票数据。

掘金量化数据接口

掘金量化的官网其实已经提供了下载数据的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *


# 可以直接提取数据,掘金终端需要打开,接口取数是通过网络请求的方式,效率一般,行情数据可通过subscribe订阅方式
# 设置token, 查看已有token ID,在用户-密钥管理里获取
set_token('your token_id')

# 查询历史行情, 采用定点复权的方式, adjust指定前复权,adjust_end_time指定复权时间点
data = history(symbol='SHSE.600000', frequency='1d', start_time='2020-01-01 09:00:00', end_time='2020-12-31 16:00:00',
fields='open,high,low,close', adjust=ADJUST_PREV, adjust_end_time='2020-12-31', df=True)
print(data)

具体可查看文档:https://www.myquant.cn/docs2/sdk/python/快速开始.html#提取数据研究示例

不过用这个接口下载的数据有一个致命的问题,它没有提供复权因子!也就是说如果要想获取准确的数据,就得在用到数据的时候重新下载,否则就有可能因为除权除息导致股价不准了。

我在掘金量化的官网上找了很久才找到复权因子的下载接口。

最新版的掘金量化提供了专门的股票和基金的复权因子下载接口,不过都是要付费才能用。

stk_get_adj_factor - 查询股票的复权因子:

a9a4100d4fa702aa709f3dace49d9d9f.png

fnd_get_adj_factor - 查询基金复权因子:

2b1440c8ef8b986890b9ca6befdce448.png

我用的是券商版的掘金量化,还没升级到最新版,那两个函数用不了,可以用旧版的这个函数来获取,具体文档查看:https://www.myquant.cn/docs2/sdk/python/API介绍/通用数据函数(免费).html#get-history-symbol-查询指定标的多日交易信息

get_history_symbol - 查询指定标的多日交易信息:

df9a119e8f667af40eb3f97afc855940.png

本地数据库搭建

数据库我采用的是 MySQL ,因为比较熟悉,下载安装数据库的教程网上有很多,这里就不展开了。

这里介绍一下数据表的结构吧,主键id我用了bigint,可能有点浪费,不过如果以后要存储tick级别的数据的话估计用int不够就用了bigint,价格相关的都用的decimal格式,能准确地存储带小数点的价格数据,成交量用的也是bigint,成交额用的是double。

数据表的DDL如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- quant.daily definition

CREATE TABLE `daily` (
`id` bigint NOT NULL AUTO_INCREMENT,
`symbol` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标的代码',
`frequency` varchar(10) NOT NULL COMMENT '频率',
`open` decimal(20,5) DEFAULT NULL COMMENT '开盘价',
`high` decimal(20,5) DEFAULT NULL COMMENT '最高价',
`low` decimal(20,5) DEFAULT NULL COMMENT '最低价',
`close` decimal(20,5) DEFAULT NULL COMMENT '收盘价',
`volume` bigint DEFAULT NULL COMMENT '成交量',
`amount` double DEFAULT NULL COMMENT '成交额',
`pre_close` decimal(20,5) DEFAULT NULL COMMENT '前收盘价',
`position` bigint DEFAULT NULL COMMENT '持仓量(仅期货)',
`bob` datetime DEFAULT NULL COMMENT 'bar开始时间',
`eob` datetime DEFAULT NULL COMMENT 'bar结束时间',
`adj_factor` double DEFAULT NULL COMMENT '复权因子',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '标的名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1733793 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

数据下载

数据的下载过程使用到了 historyget_history_symbol 这两个接口,虽然get_history_symbol 接口也提供了开盘价、最高价、最低价、收盘价等信息,但它只有日线数据,要下载分钟线级别的数据还是要用history接口。

在下载时,一定要下载不复权的数据,不复权的数据借助复权因子可以算出前、后复权的数据。如果下载的是前、后复权数据则只能确保下载的那天数据是对的。

数据库的操作采用sqlalchemy库实现。具体代码如下:

首先导入各个库:

1
2
3
4
5
6
7
8
9
10
# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import sessionmaker

from sqlalchemy.orm import declarative_base
from sqlalchemy import Column,String,BigInteger,Numeric,Double,DateTime

然后定义数据模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Base = declarative_base()
class Daily(Base):
__tablename__ = 'daily'

id = Column(BigInteger,primary_key=True,autoincrement=True)
symbol = Column(String(20))
frequency = Column(String(10))
open=Column(Numeric(precision=20, scale=5))
high=Column(Numeric(precision=20, scale=5))
low=Column(Numeric(precision=20, scale=5))
close=Column(Numeric(precision=20, scale=5))
pre_close=Column(Numeric(precision=20, scale=5))
volume=Column(BigInteger)
amount=Column(Double)
position=Column(BigInteger)
bob=Column(DateTime)
eob=Column(DateTime)
adj_factor=Column(Double)
name=Column(String(20))

数据下载部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def init(context):
# 替换为你的数据库连接信息
DATABASE_URI = "mysql+pymysql://root:quant@localhost/quant"
engine = create_engine(DATABASE_URI)
# 创建会话
Session = sessionmaker(bind=engine)
session = Session()
# 股票或基金代码,这里都是ETF代码,我主要炒ETF
symbols=['SHSE.510050','SHSE.510300','SZSE.159915','SHSE.588000','SHSE.510500','SHSE.512100','SZSE.159920','SHSE.513180','SZSE.159941','SHSE.513500',
'SHSE.513330','SHSE.513050','SHSE.512480','SZSE.159997','SHSE.515880','SZSE.159819','SHSE.512720','SHSE.515400','SHSE.515230','SZSE.159869',
'SHSE.512980','SHSE.513360','SHSE.562500','SHSE.515250','SHSE.515030','SHSE.515790','SHSE.512660','SHSE.513060','SHSE.512170','SHSE.512010',
'SZSE.159992','SHSE.560080','SZSE.159928','SHSE.512690','SZSE.159865','SZSE.159996','SZSE.159766','SHSE.512800','SHSE.512880','SHSE.512070',
'SHSE.512200','SHSE.516970','SZSE.159870','SZSE.159611','SHSE.515220','SHSE.515210','SHSE.512400','SHSE.516150','SHSE.518880','SHSE.510880',]

# 下载日线的代码
def get_history_etf_data(symbol,start_time,end_time):
# 第一步下载数据
data=history(symbol=symbol, frequency='1d', start_time=start_time, end_time=end_time, fields='symbol,frequency,open,high,low,close,volume,amount,position,bob,eob,pre_close', skip_suspended=True,
fill_missing=None, adjust=ADJUST_NONE, adjust_end_time='', df=True)

infos=get_history_symbol(symbol=symbol, start_date=start_time[:10], end_date=end_time[:10], df=True) # '1991-01-01'
# 把两张表结合起来,把复权因子和股票名字加到数据中
data['adj_factor']=infos['adj_factor']
data['name']=infos['sec_name']
# 遍历数据,准备写到数据库中
for row in data.itertuples():
daily = Daily(symbol=row.symbol,
frequency=row.frequency,
open=row.open,
high=row.high,
low=row.low,
close=row.close,
pre_close=row.pre_close,
volume=row.volume,
amount=row.amount,
position=row.position,
bob=row.bob,
eob=row.eob,
adj_factor=row.adj_factor,
name=row.name)

session.add(daily)

# 写入数据库中
session.commit()

for symbol in symbols:
get_history_etf_data(symbol=symbol,start_time='1991-01-01 09:00:00',end_time='2024-02-21 16:00:00')
print(symbol,'ok')


print('total ok')

主函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if __name__ == '__main__':
'''
strategy_id策略ID, 由系统生成
filename文件名, 请与本文件名保持一致
mode运行模式, 实时模式:MODE_LIVE回测模式:MODE_BACKTEST
token绑定计算机的ID, 可在系统设置-密钥管理中生成
backtest_start_time回测开始时间
backtest_end_time回测结束时间
backtest_adjust股票复权方式, 不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
backtest_initial_cash回测初始资金
backtest_commission_ratio回测佣金比例
backtest_slippage_ratio回测滑点比例
'''
run(strategy_id='xxxxxxxxxxxxxxxx',
filename='main.py',
mode=MODE_BACKTEST,
serv_addr='192.168.0.102:7001',
token='xxxxxxxxxxxxxxx',
backtest_start_time='2020-11-01 08:00:00',
backtest_end_time='2020-11-10 16:00:00',
backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)

这篇文章就到这里啦,下一篇文章介绍怎么在backtrader中使用mysql中的数据。

复权价格计算: T日后复权价格 = T日不复权价格 * T日累计后复权因子 T日前复权价格 = T日不复权价格 * T日前复权因子

T 日前复权因子=T 日累计后复权因子/复权基准日累计后复权因子

江达小记