Python开发股票量化系统从入门到放弃(三)

Python开发股票量化系统从入门到放弃(三),第1张

文章目录

  • 三、读取股票数据

    • 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获取证券数据信息,满足量化交易投资者、数量金融爱好者、计量经济从业者数据需求。


发现第三方数据接口的问题是:

  1. 需要一个或几个股票申请,不能全部申请
  2. 请求有速度限制
  3. 有的不能请求全部历史数据
  4. 文本方式请求历史数据数据量过大

所以,读取股票历史数据优选方式是读取股票软件下载的数据。


一直使用同花顺,就决定用同花顺数据来开发。


又给自己挖了一个坑!

2. 获取股票信息 2.1 股票信息文件结构

同花顺安装在”C:\同花顺软件\同花顺\“目录下,stockname目录存放了股票目录信息,具体:

  1. 沪市文件 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=上海电力
  1. 深市文件 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()

查看结果,

结果可以。


3. 获取股票历史数据 3.1. 分析数据结构

历史数据目录:

  • 沪市股票 history/shase/day
  • 深市股票 history/sznse/day

找一个文件600000.day进行分析


上面是文件的二进制显示,找了了一下资料,细节如下;

文件头固定为16个字节,包括:

字节长度内容16进制数据10进制数据
6 字节固定题头68 64 31 2e 30 00
4 字节内容区域的记录条数71 00 00 00113
2 字节内容区域的开始位置c0 00
2 字节内容区域每条记录的字节长度b0 00176
2 字节列定义的列个数2c 0044

从C0开始是数据,都是int,需要

16进制数据10进制数据内容
e2 64 34 0120210914交易日期
ae 24 00 b09390 去除开始4位开盘 9.39
d6 24 00 b09430 去除开始4位最高 9.43
d2 23 00 b09170 去除开始4位最低 9.17
fa 23 00 b09210 去除开始4位收盘 9.21
9e e6 fb 1250063006 去除开始4位成交额/10
81 fa 36 0353934721成交量 股


和数据能对上。


3.2 构建数据库

建股票数据库就简单了,

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,不快

运行结果:


数据存下了。


3.4 保存历史数据

下载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. 总结

读取同花顺历史数据失败。


放弃!

可能需要花钱买会员,累了

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/568989.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存