2016-12-16 33 views
5

Muszę otworzyć plik .bi5 i przeczytać jego zawartość, aby skrócić długą historię. Problem: Mam dziesiątki tysięcy plików .bi5 zawierających dane szeregów czasowych, które muszę rozpakować i przetworzyć (odczyt, zrzut do pand).Dekompresuj i przeczytaj pliki kleszczy Dukascopy .bi5

skończyło się instalacji Pythona 3 (użyć 2,7 normalnie) zwłaszcza dla biblioteki lzma, jak prowadził do sporządzania koszmary pomocą tylnej porty lzma Pythona 2.7, więc ustąpił i prowadził Pythona 3, ale bez powodzenie. Problemy są zbyt liczne, aby je ujawnić, nikt nie czyta długich pytań!

Zawarłem jeden z plików .bi5, jeśli ktoś mógłby go umieścić w ramce danych Pandas i pokazać, jak to zrobili, byłoby idealnie.

ps fie jest tylko kilka kb, zostanie pobrany w ciągu sekundy. Dziękuję bardzo z góry.

(Plik) http://www.filedropper.com/13hticks

+0

Czy znasz format oryginalnych danych? Czy jest to na przykład: (int, int, int, float, float) w każdej linii? – ptrj

+0

32-bitowa liczba całkowita: milisekundy od epoki, 32-bitowa liczba zmiennoprzecinkowa: cena za żądanie, 32-bitowa liczba zmiennoprzecinkowa: cena zestawu, 32-bitowa liczba zmiennoprzecinkowa: liczba żądań, liczba zmiennoprzecinkowa 32-bitowa: wolumin stawki. Istnieje biblioteka C++ specjalnie dla tego zadania, ale muszę pracować z Python. Możesz spojrzeć na to tutaj https: // github.pl/dziewięćdziesiąt47/dukascopy – ajsp

+0

Python 2.7 to znaczy. – ajsp

Odpowiedz

7

Poniższy kod powinien załatwić sprawę. Najpierw otwiera plik i dekoduje go w lzma, a następnie używa struct do rozpakowania danych binarnych.

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 

Najważniejszą rzeczą jest znajomość właściwego formatu. Przeszukałem go i próbowałem zgadnąć, a '>3i2f' (lub >3I2f) działa całkiem nieźle. (To jest duży endian 3 ints 2 floats. Co sugerujesz: 'i4f' nie wytwarza sensownych pływaków - bez względu na to, czy jest to duży czy mały endian.) Dla struct i formatowania zobacz 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 

Aktualizacja

Aby porównać wyjście bi5_to_df z https://github.com/ninety47/dukascopy, skompilowany i uruchomić test_read_bi5 stamtąd. Pierwsze wiersze wyjścia są:

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 

I bi5_to_df tego samego pliku wejściowego daje:

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 

więc wszystko wydaje się być w porządku (kod ninety47 za zmieniać kolejność kolumn).

Ponadto jest prawdopodobnie bardziej dokładne użyć '>3I2f' zamiast '>3i2f' (tj unsigned int zamiast int).

+0

Wygląda na prawdopodobny ptrj. Pierwsza kolumna ma być znacznikiem czasu, ale jeśli masz rację, i to jest prawdziwa reprezentacja danych, będę musiał wziąć początkową sygnaturę czasową ze struktury folderów z datą i dodać do niej (długa historia). Sprawdzę to jutro, żeby się upewnić, ale wygląda na to, że zasłużyłeś na nagrodę. Mów szybko. – ajsp

+1

Pierwsze kolumny to "milisekundy od epoki". Jeśli uruchomisz 'pd.TimedeltaIndex (df [0], 'ms')', zobaczysz, że obejmuje on 1 godzinę. Aby uzyskać znaczniki czasu, wykonaj na przykład 'ts + pd.TimedeltaIndex (df [0], 'ms')' gdzie 'ts' to twój znacznik czasu. – ptrj

+0

pierwsze dwie kolumny powinny jednak być pływające. Jest to cena waluty (EURUSD). Czy jest jakaś szansa, że ​​został skompresowany w ten sposób, by zaoszczędzić miejsce? – ajsp

0

Czy próbowałeś używać numpy do analizy danych przed przeniesieniem ich do pandy. Być może jest to dalekosiężne rozwiązanie, ale pozwolę ci na manipulowanie i czyszczenie danych przed wykonaniem analizy w Panda, także integracja między nimi jest całkiem prosta,