ヒストリカルデータをCSVファイルに変換する
pythonでヒストリカルデータ(HST形式のファイル)をCSV形式に変換するツールを作成します。なぜ、pythonかというと最近仕事でpythonに触れる機会がありまして、pythonの書きやすさや可読性の高さに惚れたからです。私はC++を基本的に読み書きすることが多く、C++と比較して「なんてpythonは書きやすく、読みやすいんだ」と感動しました。もうpythonが書きたくて仕方ない!!そんな感じに今なっています。
私のpythonへの愛情表現はこの辺にしておき、早速本題に入ります。 ヒストリカルデータはほかの記事で説明したとおり、HSTという拡張子のファイルでファイルの中には決まったデータ形式(フォーマット)でデータが記録されています。今回作成するツールは、HSTファイルを読み込み、CSV形式でデータを出力するツール(スクリプト)です。
ヒストリカルデータのフォーマット
ヒストリカルデータファイルには、以下の形式でデータが格納されています。(バージョンによって違うみたいですが、私の使用したHSTファイルは以下のようになってました。) 著作権等の管理情報が入ったヘッダーデータと、始値/終値/高値/低値が入ったデータ部で構成されています。
CSVファイルに変換するPythonスクリプトを作る
HSTファイルのフォーマットがわかったので、あとはフォーマットに沿って読み込み、必要なデータのみをCSV形式で書き出すPythonスクリプトを作るのみです!! こんな感じになりました。
実行環境
OS: Windows 7 x64 Python for Windowsインストール環境 Python 3.6.2
ソースコード
import argparse import io from ctypes import * import struct import datetime # HSTファイルのヘッダー構成 class HSTHeader(Structure): _fields_ = [ ( 'version',c_int ), ( 'copyright',c_char * 64 ), ( 'symbol',c_char * 12 ), ( 'period',c_int ), ( 'digits',c_int ), ( 'timesign',c_int ), ( 'last_sync',c_int ), ( 'unused',c_int * 13 ), ] # HSTファイルのデータ構成 # アライメントが入ってしまうので現在時刻についてはfields含めない class HSTData(Structure): _fields_ = [ ( 'open' , c_double ), ( 'low' , c_double ), ( 'high', c_double ), ( 'close', c_double ), ( 'vol',c_double ), ] def __init__(self): # 現在時刻についてはfieldsに入れてしまうと # 自動アライメントが入ってしまうので別枠で用意しておく。 self.currentTime = 0 # HSTHeaderの解析関数 def analyzeHstHeader(fileObj): # Header部のサイズ headerSize = sizeof(HSTHeader) # Header部のバイナリデータを取得 headerBinaryData = fileObj.read(headerSize) # HSTHeaderにバイナリデータをキャスト headerData = HSTHeader() buffer = io.BytesIO(headerBinaryData) buffer.readinto(headerData) return headerData # HSTDataの解析関数 # 読み込むデータがない場合はNoneを返却する。 def analyzeHstData(fileObj): data = HSTData() # 時刻データの取得 dateBinaryData = fileObj.read(4) # fileが末尾だったらNULLを返却 if dateBinaryData == b'': return None data.currentTime, = struct.unpack('i',dateBinaryData) # Data部のサイズ dataSize = sizeof(HSTData) # Data部のバイナリデータを取得 dataBinaryData = fileObj.read(dataSize) # HSTDataにバイナリデータをキャスト buffer = io.BytesIO(dataBinaryData) buffer.readinto(data) return data # HSTHeader情報を標準出力に出力する def outputHstHeader(headerData): print('version:',headerData.version) print('copyright:',headerData.copyright.decode('utf-8')) print('symbol:',headerData.symbol.decode('utf-8')) print('period:',headerData.period) print('digits:',headerData.digits ) print('timesign:',headerData.timesign ) print('last_sync:',headerData.last_sync ) print('-------------------------------') # CSVにヘッダーを出力 def outputCSVHeader(): print('currentTime,open,low,high,close,vol') # HSTファイルのデータ部出力 def outputHstData(data): print( datetime.datetime.fromtimestamp(data.currentTime), ',' , data.open, ',' ,data.low, ',' ,data.high, ',' ,data.close, ',' ,data.vol) if __name__ == '__main__': argParser = argparse.ArgumentParser() argParser.add_argument("HSTFilePath") args = argParser.parse_args() # バイナリモードでHSTファイルを読み込む fileObj = open(args.HSTFilePath,"rb") headerData = analyzeHstHeader(fileObj) outputHstHeader(headerData) outputCSVHeader() data = analyzeHstData(fileObj) while data is not None: # dataについて出力 outputHstData(data) # 次のデータを取得。ファイルの末尾ならNoneになる。 data = analyzeHstData(fileObj) fileObj.close()
(念のため) このソースの使用については自由ですが、いかなる事象や理由であろうと責任は一切負いません
実行例
> python hst_to_csv.py USDJPY.hst version: 400 copyright: (C)opyright 2003, MetaQuotes Software Corp. symbol: USDJPY period: 1 digits: 1 timesign: 1403020128 last_sync: 0 ------------------------------- currentTime,open,low,high,close,vol 2005-01-10 11:31:00 , 104.79 , 104.79 , 104.79 , 104.79 , 5.0 2005-01-10 11:32:00 , 104.79 , 104.78 , 104.79 , 104.78 , 6.0 2005-01-10 11:33:00 , 104.78 , 104.77 , 104.78 , 104.77 , 5.0 2005-01-10 11:34:00 , 104.77 , 104.77 , 104.79 , 104.79 , 5.0 2005-01-10 11:35:00 , 104.79 , 104.78 , 104.79 , 104.78 , 4.0 2005-01-10 11:36:00 , 104.78 , 104.78 , 104.78 , 104.78 , 2.0 2005-01-10 11:37:00 , 104.78 , 104.78 , 104.78 , 104.78 , 2.0 2005-01-10 11:38:00 , 104.78 , 104.78 , 104.78 , 104.78 , 2.0 2005-01-10 11:39:00 , 104.78 , 104.78 , 104.79 , 104.79 , 4.0 2005-01-10 11:40:00 , 104.8 , 104.77 , 104.8 , 104.77 , 5.0 2005-01-10 11:41:00 , 104.77 , 104.75 , 104.78 , 104.75 , 9.0 2005-01-10 11:42:00 , 104.75 , 104.75 , 104.76 , 104.76 , 3.0 2005-01-10 11:43:00 , 104.76 , 104.74 , 104.76 , 104.74 , 5.0 2005-01-10 11:44:00 , 104.74 , 104.74 , 104.74 , 104.74 , 3.0 2005-01-10 11:45:00 , 104.74 , 104.74 , 104.74 , 104.74 , 2.0
さ、これでMT4を使用しなくてもPythonを使用して、バックテスト(過去のチャートでトレード検証)ができそうです。 (MT4もいつかは覚えなくてはならないような気もする....)