Pythonスクリプトでレート情報を自動収集する
スポンサーリンク

レート情報取得を自動化する

以前の記事でレート情報の傾向を見るために、主要28通貨ペア、過去11年分のレートを収集しました。
MT5の画面上から手動で取得しても良いのですが、手待ち時間と頻度を考えると自動化が楽でおすすめです。

MetaTrader Python パッケージ

2019年6月リリースの Build 2085 からPythonパッケージが使用できるようになっています。

環境準備

本家ブログPyPIも参考にさせて頂きながら実行環境を整備。特段ハマるポイントはありませんでしたが、
Python 3.8では動作せず。 Python 3.7で環境を作成しました。

追加のライブラリは本体の MetaTrader5に加え pandas, pytz 程度。

pip install MetaTrader5
pip install pandas
pip install pytz

データ取得スクリプト

・取得フォーマットとしてcsv, parquetに対応
・通貨ペアと期間足を指定したら、その組み合わせ全てを出力する
・日付範囲は指定可能。 日付fromは必須、日付toは任意(デフォルト当日)

くらいを追加しましたが、土台部分はリファレンス通り。

"""get rate from MT5"""

from datetime import datetime
from enum import IntEnum, auto
import configparser
import os
import pytz
import sys

import pandas as pd
from MetaTrader5 import *


class FileFormat(IntEnum):
    csv = auto()
    parquet = auto()


class MT5:
    date_from = ''
    date_from_tz = ''
    date_to = ''
    date_to_tz = ''
    vendor_prefix = ''
    output_format = ''

    currency_list = []
    timeframe_list = []

    dict_timeframe = {'M1': MT5_TIMEFRAME_M1,
                      'M2': MT5_TIMEFRAME_M2,
                      'M3': MT5_TIMEFRAME_M3,
                      'M4': MT5_TIMEFRAME_M4,
                      'M5': MT5_TIMEFRAME_M5,
                      'M6': MT5_TIMEFRAME_M6,
                      'M10': MT5_TIMEFRAME_M10,
                      'M12': MT5_TIMEFRAME_M12,
                      'M15': MT5_TIMEFRAME_M15,
                      'M20': MT5_TIMEFRAME_M20,
                      'M30': MT5_TIMEFRAME_M30,
                      'H1': MT5_TIMEFRAME_H1,
                      'H2': MT5_TIMEFRAME_H2,
                      'H3': MT5_TIMEFRAME_H4,
                      'H4': MT5_TIMEFRAME_H3,
                      'H6': MT5_TIMEFRAME_H6,
                      'H8': MT5_TIMEFRAME_H8,
                      'H12': MT5_TIMEFRAME_H12,
                      'D1': MT5_TIMEFRAME_D1,
                      }

    def __init__(self):
        config = configparser.ConfigParser()

        config.read('./app.ini', encoding='utf-8')

        self.config = config
        self.mt5_path = config.get('common', 'mt5_path')
        self.data_dir_path = config.get('common', 'data_dir')
        self.timezone = pytz.timezone('Etc/UTC')

        MT5Initialize(self.mt5_path)
        MT5WaitForTerminal()

        print(MT5TerminalInfo())
        print(MT5Version())

    def convert_date(self):
        self.date_from_tz = self.date_from.astimezone(self.timezone)

        if self.date_to == '':
            self.date_to = datetime.now()
        self.date_to_tz = self.date_to.astimezone(self.timezone)

    def generate_parameter(self):
        self.convert_date()
        df_currency = pd.DataFrame({'currency_pair_name': self.currency_list}).assign(dummy_key=1)
        df_timeframe = pd.DataFrame({'timeframe_string': self.timeframe_list}).assign(dummy_key=1)

        # full outer join
        df = df_currency.merge(df_timeframe, how='outer',on='dummy_key').drop('dummy_key', 1)
        df['date_from_tz'] = self.date_from_tz
        df['date_to_tz'] = self.date_to_tz
        df['timeframe_int'] = df['timeframe_string'].map(self.dict_timeframe)

        param_list = []
        list_append = param_list.append
        for param_dict in df.to_dict(orient='index').items():
            list_append(param_dict[1])

        return param_list

    def output_file(self):
        df = pd.DataFrame(list(self.rates),
                          columns=['time', 'open', 'low', 'high', 'close',
                                   'tick_volume', 'spread', 'real_volume'])

        df['vendor_name'] = self.vendor_prefix
        df['currency_pair_name'] = self.param['currency_pair_name']
        df['timeframe'] = self.param['timeframe_string']

        file_name = '{}_{}_{}'.format(self.vendor_prefix,
                                      self.param['timeframe_string'],
                                      self.param['currency_pair_name'])

        if self.output_format == FileFormat.csv:
            file_path = os.path.join(self.data_dir_path, 'csv', '{}.csv'.format(file_name))
            df.to_csv(file_path, index=False)

        elif self.output_format == FileFormat.parquet:
            file_path = os.path.join(self.data_dir_path, 'parq', '{}.parq'.format(file_name))
            df.to_parquet(file_path, index=False)

    def get_rate_main(self):
        params = self.generate_parameter()

        for param in params:
            print('get rate: {} {}'.format(param['currency_pair_name'], param['timeframe_string']))
            self.param = param
            self.rates = MT5CopyRatesRange(param['currency_pair_name'],
                                           param['timeframe_int'],
                                           param['date_from_tz'],
                                           param['date_to_tz'])

            self.output_file()

    def close(self):
        MT5Shutdown()


if __name__ == '__main__':
    try:
        mt5 = MT5()
        mt5.vendor_prefix = 'XM'
        mt5.output_format = FileFormat.parquet
        mt5.date_from = datetime.strptime('2009-01-01', '%Y-%m-%d')
        mt5.currency_list = ['USDJPY', 'EURUSD', 'EURJPY', 'CADJPY', 'CHFJPY', 'EURCAD', 'EURCHF', 'EURGBP', 'CADCHF',
                             'GBPCAD', 'GBPCHF', 'GBPJPY', 'GBPUSD', 'USDCHF', 'AUDNZD', 'AUDCAD', 'AUDCHF', 'AUDJPY',
                             'EURAUD', 'AUDUSD', 'EURNZD', 'NZDUSD', 'GBPAUD', 'GBPNZD', 'NZDCAD', 'NZDCHF', 'NZDJPY',
                             'USDCAD']
        mt5.timeframe_list = ['M1', 'H1']

        mt5.get_rate_main()

        mt5.close()

        print('success.')
    except Exception as e:
        print(e)
        sys.exit(-1)
スポンサーリンク

取得結果

きれいに取得できました。
データ量は28通貨ペア・1分足データ11年分で約110,000,000レコード、8GB位くらい。

活用例

まとめ

1分足単位にローソク足、スプレッド情報等取得できるので、色々な分析に利用できそうです。

複数の証券会社の配信レートを収集すれば、配信レートやスプレッドの異常値(ノミ行為的な)なんかも見えてきそうですが。
日本の証券会社は軒並みMT5に対応していないので、この方法では情報取れないのが残念です。

 

スポンサーリンク
おすすめの記事