三、读取股票数据
- 1. 选择数据来源
- 2. 获取股票信息
- 2.1 股票信息文件结构
- 2.2 建股票信息数据库
- 2.3 更新股票数据库
- 3. 获取股票历史数据
- 3.1. 分析数据结构
- 3.2 构建数据库
- 3.3 读取单个股票数据
- 3.4 保存历史数据
- 3.5 保存全部历史数据
- 4. 总结
三、读取股票数据 1. 选择数据来源
既然要开发自己的量化系统,那么一定要将股票数据拿到本地。
网上查了一下,免费的第三方数据接口包括:
-
新浪财经
请求:http://hq.sinajs.cn/list=sh601003,sh601001
-
腾讯财经
请求:http://qt.gtimg.cn/q=sh601003,sh601001
-
雪球
请求:https://stock.xueqiu.com/v5/stock/realtime/quotec.json?symbol=SH601003,SH601001
-
Tushare
Tushare是一个免费、开源的python财经数据接口包,不仅包括股票、期货行情数据,还有丰富的财经资讯数据。
-
BaoStock
证券宝www.baostock.com是一个免费、开源的证券数据平台(无需注册)。
提供大量准确、完整的证券历史行情数据、上市公司财务数据等。
通过python API获取证券数据信息,满足量化交易投资者、数量金融爱好者、计量经济从业者数据需求。
发现第三方数据接口的问题是:
- 需要一个或几个股票申请,不能全部申请
- 请求有速度限制
- 有的不能请求全部历史数据
- 文本方式请求历史数据数据量过大
所以,读取股票历史数据优选方式是读取股票软件下载的数据。
一直使用同花顺,就决定用同花顺数据来开发。
2. 获取股票信息 2.1 股票信息文件结构又给自己挖了一个坑!
同花顺安装在”C:\同花顺软件\同花顺\“目录下,stockname目录存放了股票目录信息,具体:
- 沪市文件 stockname_16_0.txt
[name_16_17]
ConfigVer=20220406_2542505106
600000=浦发银行
600004=白云机场
600006=东风汽车
600007=中国国贸
600008=首创环保
600009=上海机场
600010=包钢股份
600011=华能国际
600012=皖通高速
600015=华夏银行
600016=民生银行
600017=日照港
600018=上港集团
600019=宝钢股份
600020=中原高速
600021=上海电力
- 深市文件 stockname_32_0.txt
[name_32_33]
ConfigVer=20220406_820764519
000001=平安银行
000002=万 科A
000004=国华网安
000005=ST星源
000006=深振业A
000007=*ST全新
000008=神州高铁
000009=中国宝安
000010=美丽生态
000011=深物业A
000012=南 玻A
000014=沙河股份
000016=深康佳A
000017=深中华A
000019=深粮控股
000020=深华发A
000021=深科技
000023=深天地A
000025=特 力A
000026=飞亚达
2.2 建股票信息数据库
建数据库语句如下:
CREATE TABLE StockBase
(
StockCode CHAR(6) NOT NULL,
StockName varchar(10) NOT NULL,
StockMarket char(2) NOT NULL,
StockType INT NOT NULL,
CONSTRAINT stockBase_pk PRIMARY KEY (StockCode,StockMarket)
)
2.3 更新股票数据库
正常情况下,更新股票数据信息会使用存储进程,
create proc UpdateStockBase
@StockCode CHAR(6),
@StockName varchar(10),
@StockMarket char(2),
@StockType INT,
as
if exists (select * from StockBase where StockName=@StockName and StockMarket=@StockMarket)
Update StockBase
set StockName = @StockName
where StockName=@StockName and StockMarket=@StockMarket
else
insert into StockBase (StockCode,StockName,StockMarket,StockType)
values (@StockCode,@StockName,@StockMarket,@StockType)
go
考虑的挺好的,SQLite不支持存储进程!!
SQlite是自己选的,含泪也得继续。
最后没有办法,判断语句在程序里面运行吧,上代码:
import sqlite3
import configparser
#读数据库,获取已有的StockCode,并将数据存放到列表中
connect = sqlite3.connect('stock.db')
cursor = connect.cursor()
cursor.execute('select StockCode from StockBase order by StockCode')
CodeBase = set()
for row in cursor.fetchall():
CodeBase.add(row[0])
#读上海数据
config = configparser.ConfigParser()
config.read('stockname_16_0.txt')
items = config.items('name_16_17')
#每一个数据存放数据库中
for i in range(1,len(items)):
if (items[i][0] in CodeBase):
SQL = ("update StockBase "
"set StockName='{0}' where StockCode='{1}'"
).format(items[i][1][0:4],items[i][0])
else:
SQL = ("INSERT INTO StockBase "
"(StockCode, StockName, StockMarket, StockType) "
"VALUES ('{0}','{1}','{2}',{3})"
).format(items[i][0],items[i][1][0:4],'sh',1)
cursor.execute(SQL)
#读深圳数据
config.read('stockname_32_0.txt')
items = config.items('name_32_33')
#每一个数据存放数据库中
for i in range(1,len(items)):
if (items[i][0] in CodeBase):
SQL = ("update StockBase "
"set StockName='{0}' where StockCode='{1}'"
).format(items[i][1][0:4],items[i][0])
else:
SQL = ("INSERT INTO StockBase "
"(StockCode, StockName, StockMarket, StockType) "
"VALUES ('{0}','{1}','{2}',{3})"
).format(items[i][0],items[i][1][0:4],'sz',1)
cursor.execute(SQL)
connect.commit()
connect.close()
查看结果,
结果可以。
历史数据目录:
- 沪市股票 history/shase/day
- 深市股票 history/sznse/day
找一个文件600000.day进行分析
上面是文件的二进制显示,找了了一下资料,细节如下;
文件头固定为16个字节,包括:
字节长度 | 内容 | 16进制数据 | 10进制数据 |
---|---|---|---|
6 字节 | 固定题头 | 68 64 31 2e 30 00 | |
4 字节 | 内容区域的记录条数 | 71 00 00 00 | 113 |
2 字节 | 内容区域的开始位置 | c0 00 | |
2 字节 | 内容区域每条记录的字节长度 | b0 00 | 176 |
2 字节 | 列定义的列个数 | 2c 00 | 44 |
从C0开始是数据,都是int,需要
16进制数据 | 10进制数据 | 内容 |
---|---|---|
e2 64 34 01 | 20210914 | 交易日期 |
ae 24 00 | 9390 去除开始4位 | 开盘 9.39 |
d6 24 00 | 9430 去除开始4位 | 最高 9.43 |
d2 23 00 | 9170 去除开始4位 | 最低 9.17 |
fa 23 00 | 9210 去除开始4位 | 收盘 9.21 |
9e e6 fb | 50063006 去除开始4位 | 成交额/10 |
81 fa 36 03 | 53934721 | 成交量 股 |
和数据能对上。
建股票数据库就简单了,
CREATE TABLE "StockTrade"
(
StockCode char(6) ,
TradeDate int,
TradeOpen int,
TradeHigh int,
TradeLow int,
TradeClose int,
TradeVolume int,
TradeAmount int,
CONSTRAINT StockTrade_pk PRIMARY KEY (StockCode,TradeDate)
)
3.3 读取单个股票数据
读取600000文件试试,代码
self.file = open(self.FileName,'rb')
self.file.read(6) #hd 1
self.file.read(4) #record num
self.head = self.file.read(6)
self.head = struct.unpack('HHH',self.head)
self.DataBegin = self.head[0]
self.DataPage = self.head[1]
self.fieldNum = self.head[2]
self.unpackStr = 'I' * self.fieldNum
self.file.seek(self.DataBegin+self.DataPage)
self.connect = sqlite3.connect('stock.db')
self.cursor = self.connect.cursor()
while True:
data = self.file.read(self.DataPage)
if(len(data)==self.DataPage):
data = struct.unpack(self.unpackStr,data)
dataDate = data[0]
dataOpen = data[1] & 0x00FFFFFF
dataHigh = data[2] & 0x00FFFFFF
dataLow = data[3] & 0x00FFFFFF
dataClose = data[4] & 0x00FFFFFF
dataAmount = data[5]
dataVolume = data[6]
SQL = ('INSERT INTO StockTrade '
'(StockCode, TradeDate, TradeOpen, TradeHigh, TradeLow, TradeClose, TradeVolume, TradeAmount) '
'VALUES ({},{},{},{},{},{},{},{})'.format(self.stockCode,dataDate,dataOpen,dataHigh,dataLow,dataClose,dataVolume,dataAmount))
self.cursor.execute(SQL)
self.connect.commit()
运行时间:0.404s
100多记录需要0.4s,不快
运行结果:
数据存下了。
下载2010/01/01到现在的数据
记住左下角的文件数
以600004为例运行。
插入2817条数据,耗时6.195s。
有点慢,优化!问题出在多次执行insert语句,改成运行Executemany。
将之前运行SQL语句换成
self.para.append((self.stockCode,dataDate,dataOpen,dataHigh,dataLow,dataClose,dataVolume,dataAmount))
添加
def SaveDatatoDB(self):
if len(self.para):
self.connect = sqlite3.connect('stock.db')
self.cursor = self.connect.cursor()
SQL = ('INSERT INTO StockTrade '
'(StockCode, TradeDate, '
'TradeOpen, TradeHigh, TradeLow, TradeClose, '
'TradeVolume, TradeAmount) VALUES '
'(?,?,?,?,?,?,?,?)')
self.cursor.executemany(SQL,self.para)
self.connect.commit()
self.connect.close()
从新运行,插入2817条数据,耗时0.035s
3.5 保存全部历史数据connect = sqlite3.connect('stock.db')
cursor = connect.cursor()
cursor.execute('select StockCode,stockMarket from StockBase order by StockCode')
CodeBase = queue.Queue()
for row in cursor.fetchall():
CodeBase.put((row[0],row[1]))
connect.close()
while not CodeBase.empty():
data = CodeBase.get()
begin = time.time()
tradeData = TradeData(data[0],data[1])
tradeData.ReadData()
tradeData.SaveDatatoDB()
jobTime = time.time()-begin
print ("%d processing %s with %.3f" % (CodeBase.qsize(), data,jobTime))
运行速度还可以,stock.db也有300M了。
等等,读历史数据有错误文件,
显示有2733个文件不存在!回头看了一下day目录,确实没有。
4. 总结累了,毁灭吧。
读取同花顺历史数据失败。
放弃!
可能需要花钱买会员,累了
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)