Python 解压缩并读取Dukascopy.bi5 tick文件

Python 解压缩并读取Dukascopy.bi5 tick文件,python,csv,pandas,binary,lzma,Python,Csv,Pandas,Binary,Lzma,我需要打开一个.bi5文件,阅读其中的内容,以便将长话短说。问题是:我有成千上万的.bi5文件,其中包含需要解压缩和处理(读取、转储到pandas)的时间序列数据 我最终专门为lzma库安装了Python3(我通常使用2.7),因为我使用Python2.7的lzma后台端口编译噩梦,所以我让步,使用Python3运行,但没有成功。问题太多,无法透露,没有人会阅读冗长的问题 我已经包含了一个.bi5文件,如果有人能够设法将其放入熊猫数据帧并向我展示他们是如何做到的,那将是理想的 ps的fie只有几

我需要打开一个
.bi5
文件,阅读其中的内容,以便将长话短说。问题是:我有成千上万的
.bi5
文件,其中包含需要解压缩和处理(读取、转储到pandas)的时间序列数据

我最终专门为
lzma
库安装了Python3(我通常使用2.7),因为我使用Python2.7的
lzma
后台端口编译噩梦,所以我让步,使用Python3运行,但没有成功。问题太多,无法透露,没有人会阅读冗长的问题

我已经包含了一个
.bi5
文件,如果有人能够设法将其放入熊猫数据帧并向我展示他们是如何做到的,那将是理想的

ps的fie只有几kb,它将在一秒钟内下载。非常感谢

(档案)

下面的代码应该可以做到这一点。首先,它打开一个文件并将其解码,然后使用解包来解包二进制数据

import lzma
import struct
import pandas as pd


def bi5_to_df(filename, fmt):
    chunk_size = struct.calcsize(fmt)
    data = []
    with lzma.open(filename) as f:
        while True:
            chunk = f.read(chunk_size)
            if chunk:
                data.append(struct.unpack(fmt, chunk))
            else:
                break
    df = pd.DataFrame(data)
    return df
最重要的是知道正确的格式。我在谷歌上四处搜索,试着猜猜,
'>3i2f'
(或
>3i2f
)效果相当不错。(它是big-endian 3整数2浮点数。您建议的:
'i4f'
不会产生合理的浮点数-无论是big还是little-endian。)有关
结构和格式语法,请参阅


更新

要将
bi5_到_df的输出与
进行比较, 我在那里编译并运行
test\u read\u bi5
。输出的第一行是:

time, bid, bid_vol, ask, ask_vol
2012-Dec-03 01:00:03.581000, 131.945, 1.5, 131.966, 1.5
2012-Dec-03 01:00:05.142000, 131.943, 1.5, 131.964, 1.5
2012-Dec-03 01:00:05.202000, 131.943, 1.5, 131.964, 2.25
2012-Dec-03 01:00:05.321000, 131.944, 1.5, 131.964, 1.5
2012-Dec-03 01:00:05.441000, 131.944, 1.5, 131.964, 1.5
同一输入文件上的bi5到df给出:

bi5_to_df('01h_ticks.bi5', '>3I2f').head()
Out[295]: 
      0       1       2     3    4
0  3581  131966  131945  1.50  1.5
1  5142  131964  131943  1.50  1.5
2  5202  131964  131943  2.25  1.5
3  5321  131964  131944  1.50  1.5
4  5441  131964  131944  1.50  1.5
所以一切似乎都很好(ninety47的代码对列进行了重新排序)


此外,使用
'>3I2f'
而不是
'>3I2f'
(即
无符号int
而不是
int
)可能更准确。

在将数据传输到pandas之前,您是否尝试使用numpy作为解析数据的工具。也许这是一个很长的解决方案,但我允许您在Panda中进行分析之前操作和清理数据,而且它们之间的集成非常简单,

您知道原始数据的格式吗?是否每行中都有:(int,int,int,float,float)?32位整数:从历元开始的毫秒,32位浮点:询问价格,32位浮点:出价价格,32位浮点:询问音量,32位浮点:出价音量。这里有一个C++库专门用于这个任务,但是我需要从Python工作。你可以在这里看到Python2.7,也就是说,它看起来像ptrj。第一列应该是一个时间戳,但如果您是正确的,并且这是数据的真实表示形式,那么我必须从带日期的文件夹结构中获取初始时间戳并将其添加到其中(说来话长)。我明天会查清楚的,不过看起来你把赏金存起来了。请稍后发言。第一栏是“自大纪元以来的毫秒”。如果您运行pd.TimedeltaIndex(df[0],'ms')
,您将看到它覆盖了1个小时。要获取时间戳,请执行例如
ts+pd.TimedeltaIndex(df[0],'ms')
的操作,其中
ts
是您的时间戳。前两列应该是浮动。这是一种货币的价格(欧元兑美元)。有没有可能是这样压缩的,为了节省空间?当我说前两列时,我指的是毫秒后的前两列,所以这将是第二列和第三列。或者
1
2
这种情况。@RaduS不知道你的意思。您可以简单地将两列中的数字除以100,例如
df.iloc[:,[1,2]]=df.iloc[:,[1,2]]/100
。对于该货币对,系数为100。对于另一对,它可能是不同的-它没有编码在输入文件中-你不知道。谢谢你,非常感谢,你知道他们多久更新一次他们的提要吗?
import requests
import struct
from lzma import LZMADecompressor, FORMAT_AUTO

# for download compressed EURUSD 2020/06/15/10h_ticks.bi5 file
res = requests.get("https://www.dukascopy.com/datafeed/EURUSD/2020/06/15/10h_ticks.bi5", stream=True)
print(res.headers.get('content-type'))

rawdata = res.content

decomp = LZMADecompressor(FORMAT_AUTO, None, None)
decompresseddata = decomp.decompress(rawdata)

firstrow = struct.unpack('!IIIff', decompresseddata[0: 20])
print("firstrow:", firstrow)
# firstrow: (436, 114271, 114268, 0.9399999976158142, 0.75)
# time = 2020/06/15/10h + (1 month) + 436 milisecond

secondrow = struct.unpack('!IIIff', decompresseddata[20: 40])
print("secondrow:", secondrow)
# secondrow: (537, 114271, 114267, 4.309999942779541, 2.25)

# time = 2020/06/15/10h + (1 month) + 537 milisecond
# ask = 114271 / 100000 = 1.14271
# bid = 114267 / 100000 = 1.14267
# askvolume = 4.31
# bidvolume = 2.25

# note that 00 -> is january
# "https://www.dukascopy.com/datafeed/EURUSD/2020/00/15/10h_ticks.bi5" for january
# "https://www.dukascopy.com/datafeed/EURUSD/2020/01/15/10h_ticks.bi5" for february

#  iterating
print(len(decompresseddata), int(len(decompresseddata) / 20))
for i in range(0, int(len(decompresseddata) / 20)):
    print(struct.unpack('!IIIff', decompresseddata[i * 20: (i + 1) * 20]))
import requests
import struct
from lzma import LZMADecompressor, FORMAT_AUTO

# for download compressed EURUSD 2020/06/15/10h_ticks.bi5 file
res = requests.get("https://www.dukascopy.com/datafeed/EURUSD/2020/06/15/10h_ticks.bi5", stream=True)
print(res.headers.get('content-type'))

rawdata = res.content

decomp = LZMADecompressor(FORMAT_AUTO, None, None)
decompresseddata = decomp.decompress(rawdata)

firstrow = struct.unpack('!IIIff', decompresseddata[0: 20])
print("firstrow:", firstrow)
# firstrow: (436, 114271, 114268, 0.9399999976158142, 0.75)
# time = 2020/06/15/10h + (1 month) + 436 milisecond

secondrow = struct.unpack('!IIIff', decompresseddata[20: 40])
print("secondrow:", secondrow)
# secondrow: (537, 114271, 114267, 4.309999942779541, 2.25)

# time = 2020/06/15/10h + (1 month) + 537 milisecond
# ask = 114271 / 100000 = 1.14271
# bid = 114267 / 100000 = 1.14267
# askvolume = 4.31
# bidvolume = 2.25

# note that 00 -> is january
# "https://www.dukascopy.com/datafeed/EURUSD/2020/00/15/10h_ticks.bi5" for january
# "https://www.dukascopy.com/datafeed/EURUSD/2020/01/15/10h_ticks.bi5" for february

#  iterating
print(len(decompresseddata), int(len(decompresseddata) / 20))
for i in range(0, int(len(decompresseddata) / 20)):
    print(struct.unpack('!IIIff', decompresseddata[i * 20: (i + 1) * 20]))