tick数据什么方式保存?写入csv还是hdf5或是数据库?

csv写入最高效,最大的问题是大文件的读取,就算用上一些提高效率的方式,也远远不如hdf5和数据库。

hdf5如果是整块写入速度很快,但是记录实时行情需要不断追加,要想像csv那样按行写入,就只能每次获取到数据转换成DataFrame,效率非常低下。

代码1是 csv和hdf5的对比

代码2是 csv和SQLite数据库

import numpy as np
import pandas as pd
import csv
df=pd.read_csv('a.csv')

%%time
csvheader = ['date','open','high','low','close']
csvfile = open('t1.csv', 'w', newline='')
csvfile_w = csv.writer(csvfile)
csvfile_w.writerow(csvheader)
i=0
for date,o,h,l,c in zip(df['date'],df['open'],df['high'],df['low'],df['close']):
    i+=1
    if i>100:
        break
    mdlist=[date,o,h,l,c]
    csvfile_w.writerow(mdlist)
csvfile.close()
# Wall time: 34.9 ms

%%time
store=pd.HDFStore('t1','w')
i=0
for date,o,h,l,c in zip(df['date'],df['open'],df['high'],df['low'],df['close']):
    i+=1
    if i>100:
        break
    mdlist=[date,o,h,l,c]
    df1=pd.DataFrame([mdlist],columns=['date','open','high','low','close'])
    store.append('df1',df1)

store.close()
# Wall time: 464 ms

为了尽量还原场景,我把3个合约的tick合并后按时间排序

import csv, sqlite3
from line_profiler import LineProfiler

subID = ['rb2310', 'au2310', 'sc2309']
with open('../data/rb2310_tick.csv', newline='') as f:
    reader = csv.reader(f)
    next(reader)
    a = list(reader)

with open('../data/au2310_tick.csv', newline='') as f:
    reader = csv.reader(f)
    next(reader)
    b = list(reader)
with open('../data/sc2309_tick.csv', newline='') as f:
    reader = csv.reader(f)
    next(reader)
    c = list(reader)
res = a + b + c
res.sort(key=lambda x: x[18])  # 根据tick时间排序


def test_csv_write(res):
    csvfiles = {}
    submap = {}
    csvheader = ['symbol', 'updateTime', 'lastPrice']
    for id in subID:
        csvname = f"./csv/{id}_tick.csv"
        csvfile = open(csvname, 'w', newline='')
        csvfile_w = csv.writer(csvfile)
        csvfile_w.writerow(csvheader)
        csvfiles[id] = csvfile
        submap[id] = csvfile_w
    for tick in res:
        submap[tick[1]].writerow([tick[1], tick[18], tick[2]])
        csvfiles[tick[1]].flush()


def test_db_write(res):
    dbfiles = {}
    for id in subID:
        fname = f"./db/{id}_tick.db"
        conn = sqlite3.connect(fname)
        conn.execute('''CREATE TABLE IF NOT EXISTS tick
                     (id INTEGER PRIMARY KEY AUTOINCREMENT,
                     symbol varchar(10),
                     updateTime varchar(10),
                     lastPrice varchar(10));''')
        dbfiles[id] = conn
    for tick in res:
        dbfiles[tick[1]].execute(f"insert into tick (symbol,updateTime,lastPrice) values ('{tick[1]}','{tick[18]}','{tick[2]}')")
        dbfiles[tick[1]].commit()


def main():
    test_csv_write(res)
    test_db_write(res)

lp = LineProfiler()
test_func = lp(main)
test_func()
lp.print_stats()

下面是打印结果

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    54                                           def main():
    55         1     302705.0 302705.0      0.2      test_csv_write(res)
    56         1  179921444.0 179921444.0     99.8      test_db_write(res)

总结:

实时数据的记录用csv是最高效的,可以在每天收盘后把csv转换成hdf5或数据库。

数据库管理起来方便,但空间占用跟csv文件差不多。hdf5就算不使用压缩参数也比csv小很多,虽然也可以追加写入,不如数据库方便。

 

我自己的方案是对csv文件进行管理,比如K线文件,我实盘需要的K线数量300根已经足够,所以只要csv文件超过300行,就可以处理掉多余的数据。

比如每次开盘前程序启动,先检查各个合约的csv文件的行数,如果超过5000行就打包成rar,以合约id+当前日期 命名,并自动上传到百度网盘。然后读取该文件后,取最后300行重新写入到该文件。

为了提高效率,不一定要检查csv文件的行数,可以用 os.path.getsize(file_name) 读取文件字节,估算下超过多少字节可以清理。

或者干脆每次开盘前一律取300行数据重写csv文件。最简单的代码:

pd.read_csv(fname).tail(300).to_csv(fname,index=False)

 

posted @   C羽言  阅读(411)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示