先日、自動売買ができるFX業者を調べた ところ、MT5を使用できる業者が増えてきていることがわかったので、僕も興味がでてきました。
そこで、とりあえずMT4用に作成したEAをMT5へ移植してみることにしました。
ということで、今回は移植する際に必要だった作業を備忘録をかねて記事にします。
なお、”MT5への移植”ということを主題にしているので、すでにMT4でのEA開発の経験があることを前提にした書き方になっています。
あしからずご了承ください。
ソースファイルのコピー
まずはMT4のソースファイルをMT5の対応するフォルダへコピーします。
(コピー先はデータフォルダを開けば直感的にわかると思います)
コピーしたらファイルの拡張子を”mq4″から”mq5″に変更します。
(ヘッダーの拡張子は”mqh”のままです)
ソースコードの修正
とりあえずコンパイルするとたくさんエラーが出力されると思います。
エラーの多くは「定義名が変わった」とか「型が変わった」とかの単純なものなので片っ端から置き換えます。
単純な置き換えでなかったものについて以下に記載します。
注文処理
MT4(MQL4)では発注、決済、注文内容の変更を、それぞれ OrderSend() 、OrderClose() 、OrderModify() 関数で行っていました。
MT5(MQL5)には同様の処理を行う方法が複数あります。
簡単にいうと以下のような感じです。
方法 1 … すべて”OrderSend()”関数で処理する
(処理内容は第2引数の構造体メンバで指定)
方法 2 … “CTrade”クラスの対応するメソッドで処理する
(買い注文と売り注文は”PositionOpen()”メソッドの第2引数で指定)
方法 3 … “CTrade”クラスの対応するメソッドで処理する
(買い注文と売り注文は”Buy()”、”Sell()”という別メソッド)
詳細は下の表のようになります。
処理内容 | MT4(MQL4) | MT5(MQL5) 方法 1 | MT5(MQL5) 方法 2 | MT5(MQL5) 方法 3 |
---|---|---|---|---|
買い注文 | OrderSend() 第2引数=OP_BUY | OrderSend() 第1引数.action=TRADE_ACTION_DEAL 第1引数.type=ORDER_TYPE_BUY | CTrade.PositionOpen() 第2引数=ORDER_TYPE_BUY | CTrade.Buy() |
売り注文 | OrderSend() 第2引数=OP_SELL | OrderSend() 第1引数.action=TRADE_ACTION_DEAL 第1引数.type=ORDER_TYPE_SELL | CTrade.PositionOpen() 第2引数=ORDER_TYPE_SELL | CTrade.Sell() |
買い注文の決済 | OrderClose() 第2引数=OP_SELL | OrderSend() 第1引数.action=TRADE_ACTION_DEAL 第1引数.type=ORDER_TYPE_SELL | CTrade.PositionClose() | |
売り注文の決済 | OrderClose() 第2引数=OP_BUY | OrderSend() 第1引数.action=TRADE_ACTION_DEAL 第1引数.type=ORDER_TYPE_BUY | CTrade.PositionClose() | |
注文内容の変更 | OrderModify() | OrderSend() 第1引数.action=TRADE_ACTION_SLTP | CTrade.PositionModify() |
検討の結果、僕は”方法 2”で移植しました。
理由としては、方法 1だと”OrderSend()”の呼び出し前にいちいち構造体のセットを行うのが面倒なのと、方法 2や方法 3のほうがMT4(MQL4)と使用感が近い気がしたからです。
方法 3ではなく方法 2にしたのは”Position~”で揃っていたほうが美しいかなーとか気分の問題です。
正直どっちでもいいと思います。
ポジション情報取得処理
MT4(MQL4)では、ポジションの数は OrdersTotal() 、ポジションのストップロス値は OrderStopLoss() といった具合に”Order~()”関数で取得できました。
しかし、MT5(MQL5)は”Order~()”ではポジションの情報を取得することができなくなってしまいました。
どうやら”Order~()”では未決注文の情報しか取得できなくなったようです。
”未決注文”というのは、まだ約定していない注文のことです。
たとえば指値注文などで指定価格になるのを待っている状態です。
MQL5リファレンスの”Orders~()”関数の説明にも次のような記載があります。
(ちょっとわかりにくいですが…)
現在の未決注文はクライアント端末の「ツールボックス」の「取引」タブに表示されているポジションと混乱されてはなりません。注文とはトランザクションを実行するリクエストです。ポジションは 1 つまたは複数の約定の結果です。
MQLリファレンス>取引関数>OrdersTotal より一部抜粋
じゃあ、どうやってポジションの情報を取得するかというと”Position~()”関数を使用します。
OrdersTotal() は PositionsTotal() 、OrderStopLoss() は PositionGetDouble(POSITION_SL) という感じです。
ボリンジャーバンド
MT4(MQL4)は iBands() 関数を使用して情報を取得します。
MT5 (MQL5)では情報を取得する方法が 2つあります。
簡単にいうと以下のような感じです。
方法 1 … iBands() 関数で生成したハンドルと CopyBuffer() 関数で情報を取得する
方法 2 … CiBands クラスの対応するメソッドで取得する
“方法 1″の場合、”iBands() 関数”は同じ名前だけど機能が違うので注意が必要です。
MQL5の”iBands() 関数”は情報へアクセスするための”ハンドル”を生成するだけです。
詳細は下表のようになります。
処理内容 | MT4(MQL4) | MT5(MQL5) 方法1 | MT5(MQL5) 方法2 |
---|---|---|---|
上側の情報取得 | iBands() 第7引数:MODE_UPPER | CopyBuffer() 第1引数=iBands()で生成したハンドル 第2引数=1 | CiBands.Upper() |
下側の情報取得 | iBands() 第7引数:MODE_LOWER | CopyBuffer() 第1引数=iBands()で生成したハンドル 第2引数=2 | CiBands.Lower() |
検討の結果、僕は”方法2”で移植しました。
理由は注文処理と同じでMT4(MQL4)と使用感が近い気がしたからです。
取引コンテキスト状態のチェック
MT4(MQL4)では取引コンテキスト(スレッド)がビジー状態かどうかを返す IsTradeContextBusy() 関数がありました。
MT5(MQL5)では削除されて、さらに代替処理も存在しません。
ビジー状態になることがないものとして処理を変更する必要があります。
変更一覧
参考までに僕が変更した内容を一覧にしておきます。
MT4(MQL4) | MT5(MQL5) |
---|---|
int(時間軸の型) | ENUM_TIMEFRAMES |
int(注文種別の型) | ENUM_ORDER_TYPE(注文を出すとき) ENUM_POSITION_TYPE(ポジション情報を確認するとき) |
OP_BUY | ORDER_TYPE_BUY POSITION_TYPE_BUY |
OP_SELL | ORDER_TYPE_SELL POSITION_TYPE_SELL |
OrderType() | PositionGetInteger(POSITION_TYPE) |
OrderSelect(index, SELECT_BY_POS) | ticket = PositionGetTicket(index) PositionSelectByTicket(ticket) |
OrderComment() | PositionGetString(POSITION_COMMENT) |
OrderSymbol() | PositionGetString(POSITION_SYMBOL) |
OrderTicket() | PositionGetInteger(POSITION_TICKET) |
OrderStopLoss() | PositionGetDouble(POSITION_SL) |
OrderTakeProfit() | PositionGetDouble(POSITION_TP) |
OrdersTotal() | PositionsTotal() |
ー | CTrade cTrade cTrade.SetDeviationInPoints(slippage) cTrade.SetTypeFillingBySymbol(symbol) |
ticket = OrderSend(symbol, orderType, volume, price, slippage, stopLoss, takeProfit) | cTrade.PositionOpen(symbol, orderType, volume, price, stopLoss, takeProfit) ticket = cTrade.ResultDeal() |
OrderClose(ticket, volume, price, slippage) | cTrade.PositionClose(ticket) |
OrderModify(ticket, price, stopLoss, takeProfit, expiration, arrowColor) | cTrade.PositionModify(ticket, stopLoss, takeProfit) |
IntegerToString(GetLastError()) | cTrade.ResultRetcodeDescription() |
OrderOpenPrice() | cTrade.ResultPrice() |
AccountEquity() | AccountInfoDouble(ACCOUNT_EQUITY) |
AccountCurrency() | AccountInfoString(ACCOUNT_CURRENCY) |
AccountLeverage() | AccountInfoInteger(ACCOUNT_LEVERAGE) |
ー | CiBands ciBands ciBands.Create(symbol, timeframe, periods, 0, deviations, PRICE_CLOSE) |
iBands(symbol, timeframe, periods, deviations, 0, PRICE_CLOSE, MODE_UPPER, index) | ciBands.Refresh() ciBands.Upper(index) |
iBands(symbol, timeframe, periods, deviations, 0, PRICE_CLOSE, MODE_LOWER, index) | ciBands.Refresh() ciBands.Lower(index) |
IsTradeContextBusy() | 削除 |
まとめ
僕が試したEAは上記の変更で移植することができました。
少し引っ掛かりそうなところもありますが、自分で組んだEAを移植するのはそれほど難しくないと感じました。
ただし、ほかにも”OrdersTotal()”関数のように同じ名前でもできることが変わっているものが隠れているかもしれないので注意は必要だと思います。