【问题标题】:Decompress and read Dukascopy .bi5 tick files解压并读取 Dukascopy .bi5 刻度文件
【发布时间】:2017-05-01 18:20:44
【问题描述】:

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

我最终专门为lzma 库安装了 Python 3(我通常使用 2.7),因为我遇到了使用 Python 2.7 的lzma 后向端口编译噩梦,所以我承认并使用 Python 3,但没有成功。问题多得不胜枚举,长问题没人看!

我已经包含了一个.bi5 文件,如果有人能设法将它放入 Pandas 数据框并告诉我他们是如何做到的,那将是理想的。

ps这个文件只有几kb,它会在一秒钟内下载。首先十分感谢。

(文件) http://www.filedropper.com/13hticks

【问题讨论】:

  • 你知道原始数据的格式吗?例如:(int, int, int, float, float) 在每一行?
  • 32 位整数:自纪元以来的毫秒数,32 位浮点数:卖出价,32 位浮点数:买入价,32 位浮点数:卖出量,32 位浮点数:买入量。有一个专门用于此任务的 C++ 库,但我需要使用 Python 工作。你可以看这里github.com/ninety47/dukascopy
  • Python 2.7 即。

标签: python csv pandas binary lzma


【解决方案1】:

下面的代码应该可以解决问题。首先,它打开一个文件并在lzma 中对其进行解码,然后使用struct 解压缩二进制数据。

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)工作得很好。 (它是大端 3 个整数 2 个浮点数。您的建议是:'i4f' 不会产生合理的浮点数 - 无论是大端还是小端。)对于 struct 和格式语法,请参阅 docs

df = bi5_to_df('13h_ticks.bi5', '>3i2f')
df.head()
Out[177]: 
      0       1       2     3     4
0   210  110218  110216  1.87  1.12
1   362  110219  110216  1.00  5.85
2   875  110220  110217  1.00  1.12
3  1408  110220  110218  1.50  1.00
4  1884  110221  110219  3.94  1.00

更新

比较bi5_to_dfhttps://github.com/ninety47/dukascopy 的输出, 我从那里编译并运行test_read_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_to_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' 可能更准确(即unsigned int 代替int)。

【讨论】:

  • 它看起来是合理的 ptrj。第一列应该是时间戳,但如果你是正确的,那是数据的真实表示,我将不得不从过时的文件夹结构中获取初始时间戳并添加到它(长篇大论)。明天我会检查一下以确定,但看起来你已经获得了赏金。快说吧。
  • 第一列是“自纪元以来的毫秒数”。如果你运行pd.TimedeltaIndex(df[0], 'ms'),你会看到它覆盖了 1 个小时。要获取时间戳,例如 ts + pd.TimedeltaIndex(df[0], 'ms') 其中ts 是您的时间戳。
  • 前两列应该是浮点数。它是一种货币的价格 (EURUSD)。有没有可能以这种方式压缩它,也许是为了节省空间?
  • 当我说前两列时,我的意思是毫秒后的前两列,所以要清楚的是第二列和第三列。或者12这个案例。
  • @RaduS 不确定您的意思。您可以简单地将两列中的数字除以 100,例如 df.iloc[:, [1, 2]] = df.iloc[:, [1, 2]] / 100。对于这个货币对,系数是 100。对于另一个货币对,它可能不同 - 它没有在输入文件中编码 - 你不知道。
【解决方案2】:
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]))

【讨论】:

  • 谢谢你,非常感谢,你知道他们多久更新一次他们的提要吗?
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 2021-06-10
    相关资源
    最近更新 更多