MT5のcandleデータをDataframeで取得する

MT5のcandleデータをPythonのライブラリpandasのDataframeに取り込む方法について

使用するライブラリ

python3.9を使用しています。
pandasとMetaTrader5というPythonのライブラリを使います。

■padas
DatarameというExcelのようにデータを扱えるクラスが使えます。ですが、Excelよりも断然使いやすいです。
install方法
pip install pandas

■MetaTrader5
MT5にPythonでアクセスするためのライブラリです。
install方法
pip install MetaTrader5
詳細

MetaTrader5のイニシャライズ

import MetaTrader5 as mt5

class Mt5Terminal:

    def __init__(self):
        ok = False
        for i in range(120):
            if mt5.initialize(path=r"C:\\Program Files\\OANDA MetaTrader 5\\terminal64.exe"):
                ok = True
                break
            else:
                print("initialize() failed, error code =", mt5.last_error())
                time.sleep(60)
        if not ok:
            raise Exception("initialize() failed, error code =", mt5.last_error())

MT5を起動し、アカウント情報を設定して、通貨ペアのローソク足が確認できる状態にしておきます。
mt5.initialize()のパラメータに”MT5のterminal64.exeの場所”を指定して、callします。MT5に接続できない時もありますので、その場合はMT5を起動しなおしたり、Windowsを再起動するとうまくいくことがあります。

Summer Timeの計算

“夏時間、冬時間を計算”の投稿に記載しています。

MT5からcandleデータを取得してDataframeにする

最新位置から取得個数指定

# イニシャライズのコードに記載したclass Mt5Terminal:の続きです    

    @property
    def zonemt5(self):
        #GMT+2(夏時間の場合はGMT+3)
        jst_time = datetime.datetime.now(tz=JST)
        # jst_time = datetime.datetime.now()
        if is_summer_time(jst_time):
            return datetime.timedelta(hours=3)
        else:
            return datetime.timedelta(hours=2)

    def _convert_timerate_granularity_to_mt5(self, granularity):
        ret_timerate = None
        if granularity == 'M1':
            ret_timerate = mt5.TIMEFRAME_M1
        elif granularity == 'M2':
            ret_timerate = mt5.TIMEFRAME_M2
        elif granularity == 'M3':
            ret_timerate = mt5.TIMEFRAME_M3
        elif granularity == 'M5':
            ret_timerate = mt5.TIMEFRAME_M5
        elif granularity == 'M15':
            ret_timerate = mt5.TIMEFRAME_M15
        elif granularity == 'M30':
            ret_timerate = mt5.TIMEFRAME_M30
        elif granularity == 'H1':
            ret_timerate = mt5.TIMEFRAME_H1
        elif granularity == 'H4':
            ret_timerate = mt5.TIMEFRAME_H4
        elif granularity == 'H6':
            ret_timerate = mt5.TIMEFRAME_H6
        elif granularity == 'D':
            ret_timerate = mt5.TIMEFRAME_D1
        elif granularity == 'W':
            ret_timerate = mt5.TIMEFRAME_W1
        elif granularity == 'M':
            ret_timerate = mt5.TIMEFRAME_MN1
        else:
            raise Exception("ERROR:unsupport:",granularity)
        return ret_timerate

    def get_candle_from(self, symbol, granularity, count=2000, past_idx=0):
        '''

        :param symbol: ドル円の場合"USDUPY"
        :param granularity: 五分足の場合"M5"
        :param count: 取得数
        :param past_idx: 取得開始index indexは現在から過去になるほど増える 現在が0
        :return:
        '''
        UTC = datetime.timezone.utc
        JST = datetime.timezone(datetime.timedelta(hours=+9), 'JST')
        timerate = self._convert_timerate_granularity_to_mt5(granularity)
        rates = mt5.copy_rates_from_pos(symbol, timerate, past_idx, count)
        rates_frame = pd.DataFrame(rates)
        try:
            rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s')
        except Exception as e:
            print("ERROR: get_candle_from", symbol, granularity, count, datetime.datetime.now())
            raise e
        rates_frame.loc[:, 'time'] = rates_frame.time - self.zonemt5 #mt5時間対応
        df = rates_frame.set_index('time')
        df = df.tz_localize(UTC).tz_convert(JST)
        if 'volume' not in df.columns:
            if 'tick_volume' in df.columns:
                df = df.rename(columns={'tick_volume': 'volume'})
        return df

get_candle_from()ローソク足をDataframeに変換して返します。
パラメータpast_idxは最新のデータを取得する場合は0を指定して、1,2と増えるとその分過去の値を最後の値として、パラメータcountの数ローソク足を取得します。
_convert_timerate_granularity_to_mt5()で、”M5″などを、MetaTrader5用のパラメータに変換します。

取得したデータをDataframeに変換
rates_frame = pd.DataFrame(rates)

秒での時間をdatetime形式に変換する
rates_frame[‘time’] = pd.to_datetime(rates_frame[‘time’], unit=’s’)

MT5は夏時間は3時間、冬時間は2時間UTCからずれているのでその分を補正し、
rates_frame.loc[:, ‘time’] = rates_frame.time – self.zonemt5 #mt5時間対応

時刻データをDataframeのindexに
df = rates_frame.set_index(‘time’)

UTCをJSTに変換します。
df = df.tz_localize(UTC).tz_convert(JST)

volumeはtick_volumeとして格納されるので、volumeに変更します。

    if 'volume' not in df.columns:
        if 'tick_volume' in df.columns:
            df = df.rename(columns={'tick_volume': 'volume'})

取得間隔指定

時間指定の場合は特にタイムゾーンを意識する必要があります。タイムゾーンはイギリスが中心で日本は+9時間、MT5は夏は+3時間、冬は+2時間ずれます。
MetaTrader5のpythonライブラリの公式サイトでは、utc時間でローソク足が取れるように記載されていますが、実際にやってみるとそうではなく、utc時間より夏は+3時間、冬は+2時間ずらした値を引数にする必要がありました。


    def get_candle_from_to(self, symbol, granularity, time_from, time_to):
        '''
        ローソク足をfromからtoまで取得
        :param symbol:
        :param granularity:
        :param time_from:
        :param time_to:
        :return:
        '''
        if time_to is None:
            time_to = datetime.datetime.now(tz=UTC)
        timerate = self._convert_timerate_granularity_to_mt5(granularity)
        mt5_from = self._tz_del(time_from) + self.zonemt5
        mt5_to = self._tz_del(time_to) + self.zonemt5
        rates = mt5.copy_rates_range(symbol, timerate, mt5_from, mt5_to)
        rates_frame = pd.DataFrame(rates)
        rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s') - self.zonemt5
        rates_frame = rates_frame.copy()
        rates_frame['time'] = rates_frame.time
        df = rates_frame.set_index('time')
        df = df.tz_localize(UTC).tz_convert(JST)
        if 'volume' not in df.columns:
            if 'tick_volume' in df.columns:
                df = df.rename(columns={'tick_volume': 'volume'})
        return df

get_candle_from_to()メソッドは、パラメータの時刻から一旦タイムゾーン情報を破棄し、MT5時間(夏は+3時間、冬は+2時間)を足しています。

        mt5_from = self._tz_del(time_from) + self.zonemt5
        mt5_to = self._tz_del(time_to) + self.zonemt5

_tz_del()は、以下のように時刻データの型を見て、データ形式に合わせてUTC時刻に変換しています。
サポートできていない方もあるとは思いますが、よく使用されそうなものは大抵これで処理可能だと思います。

    def _tz_del(self, tgt_time):
        if tgt_time is not None:
            if type(tgt_time) is datetime.datetime:
                if tgt_time.tzinfo == UTC:
                    pass
                elif tgt_time.tzinfo is None:
                    tgt_time = tgt_time.replace(tzinfo=UTC)
                elif str(tgt_time.tzinfo).startswith('UTC') or str(tgt_time.tzinfo).startswith('MT5'):
                    tgt_time = tgt_time.astimezone(UTC)
                elif tgt_time.tzinfo is not None and (tgt_time.tzinfo == JST or tgt_time.tzinfo.zone == 'Asia/Tokyo'):
                    tgt_time = tgt_time.astimezone(UTC)
                else:
                    raise Exception(tgt_time)
            elif type(tgt_time) is pd.Timestamp:
                if tgt_time.tzinfo == UTC:
                    pass
                else:
                    tgt_time = tgt_time.tz_convert(UTC)
                    tgt_time = tgt_time.to_pydatetime()
            elif type(tgt_time) is np.datetime64:
                tgt_time = pd.to_datetime(tgt_time, unit='s')
                tgt_time = tgt_time.tz_localize(UTC)
                tgt_time = tgt_time.to_pydatetime()
            else:
                print(type(tgt_time))
                raise Exception(tgt_time)
        return tgt_time

MetaTrader5ライブラリを使用しMT5からロウソク足データを取得します。
このあたりのデータ変換処理はget_candle_from()と同じなので説明を省きますが、
取得したデータはMT5の時刻((夏は+3時間、冬は+2時間))ですので、UTCになるようにずらしてさらに日本時間JSTに変換しています。これでDatetimeのindexは日本時間になります。

        rates = mt5.copy_rates_range(symbol, timerate, mt5_from, mt5_to)
        rates_frame = pd.DataFrame(rates)
        rates_frame['time'] = pd.to_datetime(rates_frame['time'], unit='s') - self.zonemt5
        rates_frame = rates_frame.copy()
        rates_frame['time'] = rates_frame.time
        df = rates_frame.set_index('time')
        df = rates_frame.set_index('time')
        df = df.tz_localize(UTC).tz_convert(JST)

以上です。

プログラムはGithubに置いています。

コメント