2018年6月17日日曜日
MT4 のヒストリカルデータを Python で読み込んでみた
MetaTrader のフォーラムに .hst
ファイルフォーマットについて書かれていたので、Python で読み込むクラスを作ってみました。
参考
この手のバイト列を扱うクラスは struct を使うと比較的簡単に実装できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # -*- coding: utf-8 -*- import calendar import collections import mmap import struct import time class History: """ .hst ファイルを collection にマップするクラス 各レコードは以下の値を持つ ctm: レコードの時間(1970/1/1 からの秒) open: 始値 high: 高値 low: 安値 close: 終値 volume: 出来高 以下は version 401 spread: スプレッド real_volume: 実出来高? """ def __init__( self , file ): self .mm = mmap.mmap( file .fileno(), 0 , access = mmap.ACCESS_READ) # Read Header self .version, self .copyright, self .symbol, self .period, self .digits, self .timesign, self .last_sync = \ struct.unpack( "<i64s12s4i" , self .mm[: 96 ]) # Check version and detect record structure self .header_size = 148 if self .version = = 400 : self .record_size = 44 self .record_struct = struct.Struct( "<i5d" ) self .candle = collections.namedtuple( 'Candle' , [ 'ctm' , 'open' , 'low' , 'high' , 'close' , 'volume' ]) elif self .version = = 401 : self .record_size = 60 self .record_struct = struct.Struct( "<q4dqiq" ) self .candle = collections.namedtuple( 'Candle' , [ 'ctm' , 'open' , 'high' , 'low' , 'close' , 'volume' , 'spread' , 'real_volume' ]) else : raise NotImplementedError self . len = int (( len ( self .mm) - self .header_size) / self .record_size) def __len__( self ): return self . len def __getitem__( self , i): if i < 0 or self . len < = i: raise IndexError pivot = self .header_size + self .record_size * i return self .candle( * self .record_struct.unpack( self .mm[pivot:pivot + self .record_size])) |
以下のように、普通の配列同等に扱えます。
1 2 3 4 5 6 7 | with open ( "USDJPY1.hst" , "rb" ) as f: history = History(f) for record in history: print ( "{0} Open:{1} High:{2} Low:{3} Close:{4} Volume:{5} Spread:{6} RealVolume:{7}" . format ( time.strftime( "%Y/%m/%d %H:%M" , time.gmtime(record.ctm)), record. open , record.high, record.low, record.close, record.volume, record.spread, record.real_volume)) |
次は日付でアクセス出来るようにするかな。