#はじめに
FXや株式、先物トレードのプラットフォームとして知られているMetaTrader5(MT5)には、Pythonから接続するためのモジュールが用意されています。
関数リストやサンプルプログラムがあるので、何となくできることがわかるかと思います。
今回、MT5からFXヒストリカルデータを取得して簡単な分析をしてみたので、メモしておきます。
#動作環境
- Python 3.8.11
- OANDA MetaTrader5 build 2982
Python、MT5の導入については省略します。MT5は基本的にどこの業者でも同じはずですが、うまくいかない場合は、業者を変えるか、インストールし直してみてください。
必要となるモジュールMetaTrader5は、メジャーなものではないので、
pip install MetaTrader5
として、別途インストールしておいてください。
#MT5への接続
まず、正常にログインできるMT5を用意しておいてください。一番簡単な接続方法は、MetaTrader5モジュールのinitialize()
を実行することです。
import MetaTrader5 as mt5
if mt5.initialize():
print('Connected to MT5 Version', mt5.version())
else:
print('initialize() failed, error code = ', mt5.last_error())
MT5が起動していればすぐに接続されます。起動していなければ最後に起動したMT5を自動的に起動して接続します。正常に接続できれば、True
を返すので、MT5のバージョン情報が表示されます。
Connected to MT5 Version (500, 2982, '23 Jun 2021')
接続できない場合はエラーメッセージを表示します。
initialize() failed, error code = (-10003, "IPC initialize failed, Pipe server didn't answer in 60 sec")
その場合、MT5の状態などを確認してみてください。
なお、起動するMT5を直接指定したい場合、以下のように、initialize()
の引数にMT5の実行ファイルのフルパスを入れます。
if mt5.initialize('C:\\Program Files\\OANDA MetaTrader 5\\terminal64.exe'):
#MT5のヒストリカルデータの取得
MT5のチャート上のデータを取得する関数は3つあります。
-
copy_rates_from()
- 開始時刻とバーの個数を指定 -
copy_rates_from_pos()
- 開始するバーの位置とバーの個数を指定 -
copy_rates_range()
- 開始時刻と終了時刻を指定
データの範囲は日時で指定することが多いと思うので、ここでは、開始時刻と終了時刻を指定するcopy_rates_range()
を使ってみます。
from datetime import datetime, timezone
symbol = "EURUSD"
tf = mt5.TIMEFRAME_H1
date_from = datetime(2020, 1, 1, tzinfo=timezone.utc)
date_to = datetime(2020, 12, 31, 23, 59, tzinfo=timezone.utc)
rates = mt5.copy_rates_range(symbol, tf, date_from, date_to)
rates
copy_rates_range()
の引数は、シンボル、タイムフレーム、開始時刻、終了時刻です。
ここでは、シンボルをEURUSD、タイムフレームを1時間足とし、2020年1月1日から2020年12月31日までのデータを取得します。
なお、date_from
は、0時0分からなので、時刻の指定は省略していますが、date_to
は、最も短いタイムフレームが1分足なので、23:59を指定しています。タイムゾーンはutcです。
すると、こんな感じでデータが取得できます。それぞれのバーの開始時刻(time)、始値(open)、高値(high)、安値(low)、終値(close)、ティック数(tick_volume)、スプレッド(spread)、**取引量(real_volume)**のデータです。
array([(1577923200, 1.12082, 1.12154, 1.12082, 1.12136, 321, 19, 0),
(1577926800, 1.12139, 1.12215, 1.12135, 1.12187, 932, 5, 0),
(1577930400, 1.12188, 1.1219 , 1.12155, 1.12182, 1626, 5, 0), ...,
(1609448400, 1.22166, 1.22227, 1.2209 , 1.22096, 2469, 5, 0),
(1609452000, 1.22097, 1.22192, 1.22095, 1.22161, 1725, 5, 0),
(1609455600, 1.2216 , 1.22279, 1.22084, 1.22126, 2507, 5, 0)],
dtype=[('time', '<i8'), ('open', '<f8'), ('high', '<f8'), ('low', '<f8'), ('close', '<f8'), ('tick_volume', '<u8'), ('spread', '<i4'), ('real_volume', '<u8')])
次にデータ処理しやすいように、pandasのDataFrame
にしておきます。また、このままだと時刻がUNIX時刻でわかりにくいので、datetime
に変換しておきます。
import pandas as pd
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
df
すると、こんなデータになりました。
#データ分析例
あとはご自由にデータを分析してください、ということですが、簡単な分析例を載せておきます。
その前に、データを取得してそのままデータ分析する場合、もうMT5とつながっている必要はないので、接続を切っても構いません。切断する関数はshutdown()
です。
mt5.shutdown()
では、データ分析例です。
いま、1時間足のデータがあるので、各時間で上がる日が多いとか、下がる日が多いとかの傾向があるのかを調べてみます。
各バーの始値で売買して終値で決済する場合、同じバーのデータだけ見ればいいので簡単です。ただ、2時間後に決済とか、3時間後に決済する場合はバーをずらさなくてはいけないので、各時間の始値から指定した時間後に決済したときの値動きの平均を計算する関数AveDiff()
を定義しておきます。
import numpy as np
def AveDiff(df, HoldHour):
Bars = HoldHour-1
Ave = np.zeros(24-Bars)
for i in range(24-Bars):
dfo = df[df['time'].dt.hour==i]
dfc = df.iloc[dfo.index+Bars]
dif = np.vstack(dfc['close'].values.T) - np.vstack(dfo['open'].values.T)
Ave[i] = dif.mean()*10000
return pd.Series(Ave)
この関数は、MT5で取得したデータdf
と、何時間後に決済するかを表すHoldHour
を引数とします。
同じバーの始値と終値で1時間の差があるので、始値と終値のバーのずれBars
はHoldHour-1
となります。ただし、終値のバーの時刻を見ているわけではなく、Bars
だけバーをずらしているだけなので、正確にHoldHour
だけずれているわけではありません。
そして、i
を0
から24-Bars-1
まで変えて、dfo
にi
時のデータを、dfc
にi+Bars
時のデータを抽出し、終値から始値を引いた値を平均し、値をpipsとして返します。
結果は以下のようになりました。
- 1時間で決済する場合
AveDiff(df, 1)
0 1.006154
1 2.895385
2 -0.275385
3 -0.293462
4 1.401538
5 0.511154
6 0.151154
7 0.178846
8 0.680385
9 -1.212692
10 1.021923
11 -0.093077
12 -1.016923
13 -0.247308
14 0.250000
15 1.139231
16 0.460769
17 -1.473462
18 -0.782692
19 -0.562308
20 0.900769
21 0.069231
22 0.926538
23 -1.145769
- 2時間で決済する場合
AveDiff(df, 2)
0 3.998077
1 2.653846
2 -0.561923
3 1.105385
4 1.910385
5 0.663846
6 0.330000
7 0.856538
8 -0.531538
9 -0.203462
10 0.926154
11 -1.128077
12 -1.276538
13 0.001923
14 1.408462
15 1.605000
16 -1.017692
17 -2.193077
18 -1.346538
19 0.340000
20 0.952308
21 0.988077
22 -0.221923
- 3時間で決済する場合
AveDiff(df, 3)
0 3.756538
1 2.367308
2 0.836923
3 1.614231
4 2.063077
5 0.842692
6 1.007692
7 -0.355385
8 0.477692
9 -0.299231
10 -0.108846
11 -1.387692
12 -1.027308
13 1.160385
14 1.874231
15 0.126538
16 -1.737308
17 -2.756923
18 -0.444231
19 0.391538
20 1.871154
21 -0.160385
数時間の値動きも平均すれば大きくても数pips程度ですし、1年分のデータでサンプル数が少ないので、この結果からエッジは見つけにくいと思います。今回はデータ分析例ということで、ここまでにしておきます。
#おわりに
PythonからMT5のデータを取得する方法を紹介しました。MetaTrader5のモジュールには、ほかにMT5と接続した状態で実際にトレードを行う関数なども用意されています。
それを使えば、売買システムをPythonで記述することもできるようです。MT5では売買システムはEAを使うのが普通ですが、色々と選択肢が増えるのはいいことです。今後、MetaTrader5モジュールでできることが増えていくことを期待します。