この記事の内容をコピペしていけば、PythonとMT5を連携させた基本的なFX自動売買ツールを作成することが可能です。
初心者向けになるべくコードの意味まで丁寧に解説するように心がけていますので、初心者の方も是非、PythonでのFX自動売買botの作成にチャレンジしてみてください。
また、最後にこの記事で紹介したコードをまとめた.ipynbファイルをダウンロード可能にしております。順番にコピペしていっても上手くいかない場合や、一つずつコピペしていくのが大変な方はご活用ください。
FX自動売買ツールの設計概要
基本的なFX自動売買ツール(bot)の設計概要は以下の通りです。
- 四本値(始値、高値、安値、終値)データを取得
- 四本値データを基にテクニカル指標を計算
- テクニカル指標を基に売買判断フラグを生成
- ポジション情報を取得して既存のポジションを確認
- 新規エントリー(買いまたは売り)の条件を満たしている場合、注文を送信
- エントリー時に設定した利確幅またはストップロス幅に到達したらポジションクローズ
- 上記全てをループ処理
ロジック概要
今回作成するFX自動売買ツール(bot)のロジック概要は以下のように非常にシンプルです。
- テクニカル指標(MAとRSI)を用いて売買判断条件を作成
- 売買判断条件を満たした場合にbuyまたはsellの注文を行う
- ATR(Average True Range)を基準に利確幅とストップロス幅を決める
複雑な条件は可能な限り排除した単純なモデルを想定しているため、buy(買い又はロング)ポジション、sell(売り又はショート)ポジションでそれぞれ1つまでしかポジションを持ちません。buyとsellで同時に1つずつポジションを持つことはあり得ます。
なお、エントリー注文を行う際にtp(利確用の指値)とsl(ストップロス用の逆指値)も設定して注文を行うようにします。
Pythonの環境設定
この記事では、基本的なPythonの環境設定は整っていて、Jupyter Notebookを使用する前提で話を進めます。
Python用MetaTrader5のインストール
まず、MetaTrader5をインストールします。Jupyter Notebook上で以下のコマンドを入力すればインストールされます。
pip install MetaTrader5
この処理は一度だけ実行すれば問題なく、その後繰り返し実行する必要は問題ありません。
Python用MetaTrader5のインポート
ここからは、Jupyter Notebook上に順番にコードを入力していきます。一通り入力して保存しておけば、それがFX自動売買ツール(bot)としての実行ファイルになります。
まずは、インストール済みのPython用MetaTrader5を以下のコマンドでインポートします。
import MetaTrader5 as mt5
この処理により、今後は、「mt5.関数名」という形で、Python用MT5で定義されている関数を呼び出すことが可能になります。
その他ライブラリのインポート
以下のライブラリをインポートしておきます。
import numpy as np
import pandas as pd
import time
いずれもPythonにおいては基本的なライブラリですので説明は省略します。
ログイン情報を入力
Pythonの場合、APIを介してMT5にログインするような形になるので、ログイン情報を入力する必要があります。通常MT5にログインするのと同じ、以下の情報を用意します。
login_ID = 12345678 # ご自身のログインIDを入力
login_server = 'XMTrading-MT5' # ご自身のログインサーバーを入力
login_password = 'XXXXXXXXX' # ご自身のログインパスワードを入力
上記はサンプルですので、ご自身のログイン情報に書き換えてください。
MT5に接続
上記のログイン情報で指定した取引口座でMT5に接続します。
# ログイン情報で指定した取引口座でMetaTrader5に接続
if not mt5.initialize(login=login_ID, server=login_server,password=login_password):
print("initialize() failed, error code =",mt5.last_error())
quit()
この際、自動的にMT5が起動すると思いますが、事前にMT5を起動しておいた方がその後の処理に支障が出ないかもしれません。
MT5のインストール
上記の処理は、MT5がインストールされていることが前提です。MT5をインストールした状態で進めてください。
インストールされていない方は、以下のリンクから「PC対応MT5」をダウンロードしてインストールしておきます。
アルゴリズム取引を許可
MT5を開いたら、ツールのオプションで以下の通り、
「アルゴリズム取引を許可」にチェックを入れておきます。
「外部Python APIを介したアルゴリズム取引を無効にする」にチェックが入っていないことも確認しておいてください。
そうでないと、PythonからMT5にアクセス出来ません。
Inputの設定
初期設定として、いくつかインプットを定めておきます。
symbol = "GOLD" # 取引対象
first_lot = 0.01 # 初期ロット数
tp_factor = 2.0 # 利確係数
sl_factor = 1.5 # ストップロス係数
magic_number = 10001 # マジックナンバー
slippage = 10 # スリッページ
bar_period = 30 # 取得する四本値の本数
取引対象(symbol)
取引対象(通貨ペア)を選びます。ここでは、XMTradingのGOLDを取引対象としますので、’GOLD’と入力します。
初期ロット数(first_lot)
ポジションを取得する時のロット数の設定です。今回のモデルでは、ナンピンを行うわけでもなく、勝敗によってロット数を変更するというようなロジックも入れていませんので、常に初期ロット数で注文を行います。
利確係数(tp_factor)
利確幅の設定に使用します。ATR(Average True Range)を基準にして、ATRの”tp_factor”倍を利確幅になるように設定します。
ストップロス係数(sl_factor)
ストップロス幅の設定に使用します。利確幅と同様に、ATRの”sl_factor”倍がストップロス幅になるように設定します。
例えば、sl_factor = 1.5と設定している場合、エントリー時のATRが4.00であれば、ストップロス幅は1.5倍の6.00が設定されます。
マジックナンバー(magic_number)
どんなEAにも存在する識別番号のようなものです。他のEAと同時に動かすようなことがなければ、どんな数値でも構いません。ロジックには関係ありません。ここでは適当に10001と設定しています。
スリッページ(slippage)
MT4では、注文時にスリッページの許容範囲が設定可能です。ただし、業者によっては設定しても無効になるようです。XMTradingもその一つで、注文時にスリッページの許容範囲を設定しても無効になります。ただし、以下の公式の説明の通り、スリッページはほとんど発生しません。
スリッページは発生しますか?
当社で取引される場合、スリッページはほとんど発生しません。しかし、特に重要な経済ニュースの発表時などは、市場価格の急騰または急落により、お客様の注文はリクエストされたものと異なるレートで執行される場合があります。
ここでは適当に10と設定しておきます。
取得する四本値の本数(bar_period)
これは取得するバー(四本値)の本数です。使用するテクニカル指標に合わせて必要な本数を設定するようにしてください。
今回はATRで期間14、MAで期間15、RSIで期間14を使用するので、30本あれば十分です。後の説明で出てきますが、最新の値よりもひとつ前のバーを使用するので、使用する期間よりも2本くらい多めに設定しておくと良いです。
各種情報取得
必要な情報をMT5から取得します。ここではひとまず、pointのみです。
point=mt5.symbol_info(symbol).point # 価格の最小単位
pointは、通貨ペア(取引対象)毎に定まる価格の最小単位です。XMTradingのGOLDの場合は、point=0.01を取得します。
テクニカル指標の関数定義
今回使用するテクニカル指標を計算する関数を以下のように定義しておきます。
ATR(Average True Range)
def calculate_atr(data, period=14):
data['tr'] = np.maximum((data['high'] - data['low']),
np.maximum(abs(data['high'] - data['close'].shift()), abs(data['low'] - data['close'].shift())))
data['atr'] = data['tr'].rolling(window=period).mean()
return data
引数は、’high’、’low ‘、’close’が入ったデータフレーム(data)です。
期間(period)はデフォルトで14と設定しています。
例えば15分足のdataを与えれば、期間14のATRが15分足ベースで計算されます。
MA(単純移動平均)
def calculate_ma(data, period=15, price_type='close'):
data['ma'] = data[price_type].rolling(window=period).mean()
return data
引数は、’close’が入ったデータフレーム(data)です。
price_type=’close’で終値の単純移動平均を計算します。
期間(period)はデフォルトで15と設定しています。
例えば15分足のdataを与えれば、期間15の終値ベースのMAが15分足ベースで計算されます。
RSI(Relative Strength Index)
def calculate_rsi(data, period=14, price_type='close'):
delta = data[price_type].diff()
gains = delta.where(delta > 0, 0)
losses = -delta.where(delta < 0, 0)
avg_gain = gains.rolling(window=period).mean()
avg_loss = losses.rolling(window=period).mean()
rs = avg_gain / avg_loss
data['rsi'] = 100 - (100 / (1 + rs))
return data
引数は、’close’が入ったデータフレーム(data)です。
price_type=’close’で終値のRSIを計算します。
期間(period)はデフォルトで14と設定しています。
例えば15分足のdataを与えれば、期間14のRSIが15分足ベースで計算されます。
売買判断フラグを設定する関数
ここでは、売買判断フラグを設定する関数を定義します。
def generate_trade_flgs(data, symbol_tick):
# テクニカル指標の計算
data = calculate_ma(data)
data = calculate_rsi(data)
# 売買判断フラグ
buy_flg = (symbol_tick.ask > data['ma'].iloc[-2]) & (data['rsi'].iloc[-2] < 30)
sell_flg = (symbol_tick.bid < data['ma'].iloc[-2]) & (data['rsi'].iloc[-2] > 70)
return buy_flg, sell_flg
引数の設定
引数は四本値のデータフレーム(data)と、現在価格(symbol_tick)です。
テクニカル指標の計算
今回はMAとRSIで売買判断を行うので、’ma’と’rsi’をdataに追加します。
売買判断フラグ
買い判断フラグ(buy_flg)と売り判断フラグ(sell_flg)をそれぞれ設定します。
buy_flg
現在の買い価格(symbol_tick.ask)が移動平均線より高く、RSIが30未満の場合、買いフラグがTrueになります。
sell_flag
現在の売り価格(symbol_tick.bid)が移動平均線より低く、RSIが70より高い場合、売りフラグがTrueになります。
ループ処理
初期設定が終わり、ここからループ処理に入ります。
無限ループ(while True:)
while True:
これは、Pythonにおいて無限ループを実現させる方法の一つです。MQL5のvoid OnTick()のように、tickを受信する度というループではなく、tickによらず無限に処理をループします。
これ以降は、「while True:」の中に記載していく内容になります。
最新価格(tick)情報を取得
まず、最新の価格(tick)情報を取得します。
symbol_tick=mt5.symbol_info_tick(symbol) # symbolのtick情報を取得
これで、symbol_tick.ask
や、symbol_tick.bid
によって、Ask値やBid値を取得することが出来るようになります。
ループ処理の終わり
ループ処理の最後の部分に、以下の記載を入れておきます。
time.sleep(60) # 1分間隔でループを実行
四本値データを取得
copy_rates_from_pos関数を用いて、今回は15分足データを取得します。
# 15分足データを取得
rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M15, 0, bar_period)
data = pd.DataFrame(rates)
data['time'] = pd.to_datetime(data['time'], unit='s')
TIMEFRAME_M15
の部分を、TIMEFRAME_M5
にすれば5分足になりますし、TIMEFRAME_H1
にすれば1時間足になります。
ATRを計算
事前に定義しておいたcalclate_atr関数を用いてATRを計算します。
# ATRを計算
data = calculate_atr(data)
atr = data['atr'].iloc[-2]
売買判断フラグを設定
こちらも事前に定義しておいたgenerate_trade_flgs関数でフラグを取得します。
# 売買判断フラグを設定
buy_flg, sell_flg = generate_trade_flgs(data, symbol_tick)
最新のMAとRSIを用いて判定された売買判断フラグ(buy_flg, sell_flg)が返ってきます。
ポジションの確認
ここでは、positions_get関数を用いて、buyポジションとsellポジションの情報を取得します。
# ポジション情報を取得
buy_position = None
sell_position = None
positions = mt5.positions_get(group='*' + symbol + '*')
for position in positions:
order_type = position[5]
if order_type == 0:
buy_position = position
elif order_type == 1:
sell_position = position
ポジションがない場合は、buy_positionとsell_positionはそれぞれNoneになります。今回のシンプルなロジックではポジションを持っているかどうかしか情報を必要としませんが、ポジションを持っている場合は、buy_positionやsell_positionにそれぞれのポジションの価格やロット数の情報等が入ります。
新規エントリー注文
続いて、新規エントリー注文です。
buyエントリー
まずは、buyエントリーです。
# buyエントリー
if buy_flg and buy_position is None:
tp = round((symbol_tick.ask + atr * tp_factor) / point) * point
sl = round((symbol_tick.ask - atr * sl_factor) / point) * point
request = {
'symbol': symbol,
'action': mt5.TRADE_ACTION_DEAL,
'type': mt5.ORDER_TYPE_BUY,
'volume': first_lot,
'price': symbol_tick.ask,
'sl': sl,
'tp': tp,
'deviation': slippage,
'magic': magic_number,
'type_time': mt5.ORDER_TIME_GTC,
'type_filling': mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
buyフラグがTrue(買いの条件を満たす)で、buyポジションを持っていない場合に動くロジックです。
当初の想定通り、利確幅をATRの”tp_factor”倍、ストップロス幅をATRの”sl_factor”倍として、それぞれの価格(tpとsl)を計算しています。
そして、エントリー注文の際にtp(利益確定の指値)とsl(ストップロスの逆指値)も設定した注文にしておきます。
sellエントリー
続いて、sellエントリーです。基本的にbuyエントリーと同様です。
# sellエントリー
if sell_flg and sell_position is None:
tp = round((symbol_tick.bid - atr * tp_factor) / point) * point
sl = round((symbol_tick.bid + atr * sl_factor) / point) * point
request = {
'symbol': symbol,
'action': mt5.TRADE_ACTION_DEAL,
'type': mt5.ORDER_TYPE_SELL,
'volume': first_lot,
'price': symbol_tick.bid,
'sl': sl,
'tp': tp,
'deviation': slippage,
'magic': magic_number,
'type_time': mt5.ORDER_TIME_GTC,
'type_filling': mt5.ORDER_FILLING_IOC,
}
result = mt5.order_send(request)
sellフラグがTrue(売りの条件を満たす)で、sellポジションを持っていない場合に動くロジックです。
その他、「注文有効期限(type_time)」や「注文タイプ(type_filling)」等について詳しく確認したい場合は、order_send関数を確認してください。ただし、今回の目的においては、この通りの設定のままで特に問題ないかと思います。
まとめ
以上、これまで見てきたものを組み合わせるだけで、テクニカル指標による売買判断を取り入れたFX自動売買ツールは完成です。
いかがでしたでしょうか。思ったよりシンプルな構造ということがよくわかったかと思います。
テクニカル指標の拡張
今回は、テクニカル指標としてMAとRSIを用いた売買判断ロジックをご紹介しましたが、”売買判断フラグを設定する関数”部分を他のテクニカル指標に置き換えるだけで様々なロジックのFX自動売買ツールを作成することが可能です。
次の記事ではいくつかパターンをご紹介しています。この記事のbotの拡張方法の解説になります。
機械学習モデルの導入
この記事では、テクニカル指標を用いて売買判断を決定するロジックをご紹介しましたが、この売買判断ロジック部分を機械学習モデルによるものに変更するだけで、シンプルなMLbot(機械学習を取り入れたFX自動売買ツール)に変換可能です。
以下の記事では、その方法をご紹介しています。この記事のbotの拡張方法の解説になります。
ipynbファイルのダウンロード
今回ご紹介したコードをまとめたものは以下からダウンロード可能です。
Pythonでバックテスト
PythonでFX自動売買ツールを開発するために、バックテスト環境を整えることも重要です。以下の記事ではMT4やMT5ではなく、Pythonでバックテストを行う方法をご紹介しています。