Чтение файла HST истории котировок Metatrader 4

Файлы истории котировок Metatrader 4 имеют расширение .hst и находятся в папке данных торгового терминала, в каталоге history. Они сгруппированы в подкаталогах, имена которых совпадают с названиями серверов, например: ForexClub-MT4 Demo Server или Alpari-ECN-Live. Имена файлов начинаются с наименования торгового инструмента, далее указывается таймфрейм (количество минут), например, для часового таймфрейма: EURUSD60.hst, для дневного: GBPUSD1440.hst.

Запись котировок в эти файлы производится в отложенном режиме, последние данные будут гарантированно сброшены из оперативной памяти в файл только при закрытии терминала Metatrader. Другими словами, здесь мы будем рассматривать только работу с историческими данными, а котировки в реальном времени придётся получать другим способом.

Число баров/свечей, хранящихся в файлах .hst, устанавливается параметром Макс. баров истории в окне настроек терминала, которое вызывается при выполнении команды главного меню Сервис ‣ Настройки (вкладка Графики).

Каталог данных торгового терминала Metatrader 4 открывается с помощью команды главного меню: Файл ‣ Открыть каталог данных. Для удобства скопируем какой-нибудь файл .hst в папку Temp на диске D:.

Для работы с этим файлом откроем его для чтения в двоичном режиме:

# hstFilename = "C:/Users/ИмяПользователя/AppData/Roaming/MetaQuotes/Terminal/ШестнадцатеричныйНомер/history/ИмяСервера/EURUSD60.hst"
hstFilename = "d:/Temp/EURUSD60.hst"
hstf =  open(hstFilename, 'rb') # Открыли бинарный (binary) файл для чтения (read).

Формат файла .hst описан в разделе Формат файла истории котировок HST в Metatrader 4. В самом начале файла .hst хранится заголовок длиной 148 байт для служебных данных. Первые 4 байта заголовка содержат номер версии формата данных. В старых билдах (до 509) использовался формат 400. В новых билдах – формат 401. Нам необходимо выяснить номер формата, т.к. от него зависит количество и размер полей в файле.

Для чтения данных из файла будем использовать метод read(n), где n – число байт, которые мы хотим прочитать. Для распаковки данных будем использовать функцию unpack модуля struct, её первый параметр – строка формата ("i" для целых 4-байтных чисел, "L" – для беззнаковых 4-байтных целых, "Q" – для беззнаковых 8-байтных целых, "d" – для вещественных 8-байтных чисел, символ "<" в начале строки формата указывает, что первым хранится младший байт многобайтного целого числа), второй параметр – исходные данные. Функция unpack всегда возвращает в качестве результата кортеж (tuple), поэтому надо явно указать, что мы хотим записать в переменную не весь кортеж, а его первый элемент (приходится ставить запятую после имени переменной перед знаком присваивания или явно обращаться к нулевому элементу кортежа):

import struct # Импортировали модуль для работы с двоичными записями.
ver, = struct.unpack("<i", hstf.read(4))  # Прочитали 4 байта из файла (номер версии формата данных).
print('Version: %d' % ver)  # Вывели на экран в форме целого числа.

Получили:

Version: 401

Далее читаем из заголовка файла .hst строку копирайта (64 байта); наименование торгового инструмента (тикер, 12 байт); номер таймфрейма (4 байта); количество десятичных знаков в котировках (4 байта); время создания файла (4 байта); время последней синхронизации данных (4 байта) и 52 байта неиспользованных данных (зарезервированных для будущих нужд).

copywrite = hstf.read(64) # Строка копирайта (64 байта).
print('%s' % copywrite)
symbol = hstf.read(12) # Тикер (12 байт).
print('Symbol: %s' % symbol)
period,digits,timesign,last_sync  = struct.unpack("<iiii", hstf.read(16)) # Таймфрейм, число знаков, время создания, время синхронизации.
print('Timeframe: %d' % int(period))
print('Digits: %d' % int(digits))
import datetime # Для работы с датой и временем.
timesign_dt = datetime.datetime.fromtimestamp(timesign)
print('Timesign: ' + str(timesign_dt))
last_sync_dt = datetime.datetime.fromtimestamp(last_sync)
print('Last sync: ' + str(last_sync_dt))
unused = hstf.read(52) # Неиспользуемые данные в заголовке файла.
(C)opyright 2003, MetaQuotes Software Corp.
Symbol: EURUSD
Timeframe: 60
Digits: 5
Timesign: 2014-12-14 11:14:04
Last sync: 1970-01-01 03:00:00

Итак, заголовок файла прочитан, далее идут сами котировки. Для старых форматов каждая запись о котировке имеет длину 44 байта: дата и время открытия бара/свечи (4 байта), цена открытия (8 байт), минимум бара (8 байт), максимум бара (8 байт), цена закрытия (8 байт) и тиковый объём (8 байт).

Для нового формата длина записи 60 байт (добавился 4-байтный спред и 8-байтный реальный объём, дата и время теперь занимают также 8 байт).

Фрагмент программы на языке Python для чтения котировок из файла .hst старого и нового форматов:

data = []  # Сюда будем записывать прочитанные данные.
count = 0  # Счётчик записей.
if ver == 400: # Если старый формат.
    len1 = 44  # Длина одной записи
    while len1 == 44:
        r1 = hstf.read(44) # Прочитали очередную запись из файла.
        len1 = len(r1)     # Длина прочитанной записи.
        if len1 == 44:     # Если прочитано 44 байта.
            ctm,open1,low1,high1,close1,vol1 = struct.unpack("<i5d", r1)
            dt = datetime.datetime.fromtimestamp(ctm)
            print('Date & Time: %d = %s %s' % (ctm, dt.date().strftime("%Y-%m-%d"), dt.time().strftime("%H:%M")))
            print('Open: %7.5f' % open1)
            print('Low %7.5f' % low1)
            print('High: %7.5f' % high1)
            print('Close %7.5f' % close1)
            print('Volume %d' % int(vol1))
            date1 = dt.date().strftime("%Y-%m-%d")
            time1 = dt.time().strftime("%H:%M")
            rw1 = [date1, time1, open1, high1, low1, close1, vol1]
            data.append(rw1) # Добавили прочитанные даные.
            print("----------------")
            count += 1       # Инкремент счётчика записей.
            if count > 4:    # После прочтения первых 5 записей
                hstf.close() # Закрываем файл.
                break        # Прерываем цикл.
elif ver == 401: # Если новый формат.
    len1 = 60    # Длина одной записи.
    while len1 == 60:
        r1 = hstf.read(60) # Прочитали очередную запись из файла.
        len1 = len(r1)     # Длина прочитанной записи.
        if len1 == 60:     # Если прочитано 60 байт.
            ctm,open1,low1,high1,close1,vol1,spread1,rvol1 = struct.unpack("<QddddQLQ", r1)
            dt = datetime.datetime.fromtimestamp(ctm)
            print('Date & Time: %d = %s %s' % (ctm, dt.date().strftime("%Y-%m-%d"), dt.time().strftime("%H:%M")))
            print('Open: %7.5f' % open1)
            print('Low %7.5f' % low1)
            print('High: %7.5f' % high1)
            print('Close %7.5f' % close1)
            print('Volume %d' % int(vol1))
            print('Spread %d' % spread1)
            print('Real volume %d' % int(rvol1))
            date1 = dt.date().strftime("%Y-%m-%d")
            time1 = dt.time().strftime("%H:%M")
            rw1 = [date1, time1, open1, high1, low1, close1, vol1, spread1, rvol1]
            data.append(rw1) # Добавили прочитанные даные.
            print("----------------")
            count += 1       # Инкремент счётчика записей.
            if count > 4:    # После прочтения первых 5 записей
                hstf.close() # Закрываем файл.
                break        # Прерываем цикл.

print("Converted: %d bars" % count)
print(data)

Получили:

Date & Time: 1408114800 = 2014-08-15 19:00
Open: 1.33893
Low 1.34041
High: 1.33759
Close 1.33973
Volume 2971
Spread 0
Real volume 0
----------------
Date & Time: 1408118400 = 2014-08-15 20:00
Open: 1.33976
Low 1.34011
High: 1.33838
Close 1.33921
Volume 2543
Spread 0
Real volume 0
----------------
Date & Time: 1408122000 = 2014-08-15 21:00
Open: 1.33922
Low 1.34110
High: 1.33771
Close 1.33819
Volume 3193
Spread 0
Real volume 0
----------------
Date & Time: 1408125600 = 2014-08-15 22:00
Open: 1.33817
Low 1.33992
High: 1.33799
Close 1.33902
Volume 3491
Spread 0
Real volume 0
----------------
Date & Time: 1408129200 = 2014-08-15 23:00
Open: 1.33906
Low 1.33939
High: 1.33798
Close 1.33855
Volume 1829
Spread 0
Real volume 0
----------------
Converted: 5 bars
[['2014-08-15', '19:00', 1.33893, 1.33759, 1.34041, 1.33973, 2971, 0, 0],
['2014-08-15', '20:00', 1.33976, 1.33838, 1.34011, 1.33921, 2543, 0, 0],
['2014-08-15', '21:00', 1.33922, 1.33771, 1.3411, 1.33819, 3193, 0, 0],
['2014-08-15', '22:00', 1.33817, 1.33799, 1.33992, 1.33902, 3491, 0, 0],
['2014-08-15', '23:00', 1.33906, 1.33798, 1.33939, 1.33855, 1829, 0, 0]]

Здесь мы ограничились чтением 5 записей и прервали цикл.

Осталось оформить чтение даных из файла .hst в виде отдельной функции, чтобы её было удобно использовать в дальнейшем. Предоставляем это читателю в качестве упражнения.


Теги: Python




Комментарии

Комментариев пока нет.

* Обязательные поля
(Не публикуется)
 
Жирный Курсив Подчеркнутый Перечеркнутый Степень Индекс Код PHP Код Кавычки Вставить линию Вставить маркированный список Вставить нумерованный список Вставить ссылку Вставить e-mail Вставить изображение Вставить видео
 
Улыбка Печаль Удивление Смех Злость Язык Возмущение Ухмылка Подмигнуть Испуг Круто Скука Смущение Несерьёзно Шокирован
 
1000
Captcha
Refresh
 
Введите код:
 
Запомнить информацию введенную в поля формы.