取引関数のOrderClose()、PositionClose()について、MQL4とMQL5のソースコード共通化する方法を説明しています。
関数定義
MQL4の定義
bool OrderClose(
int ticket, // ticket
double lots, // volume
double price, // close price
int slippage, // slippage
color arrow_color // color
);
MQL5の定義
定義なし
EAでは使用頻度が高い関数ですが、MQL5では取引関数の仕様は大きく変更されてOrderClose()自体がMQL5では削除されています。
その為、MQL5用の定義をしてOrderClose()を利用できるように対応します。
ただし、MQL5ではオーダーとポジションという表現を区別しているため工夫が必要です。
共通化方法
ソース共通化
対処方法
共通化するためにMQL5用の定義をします。
#ifdef __MQL5__ ~ #endifを使用することでMQL5のコンパイルにのみ有効となります。
MQL4の場合は「__MQL4__」を使用しますが、今回使用していないためMQL4は既存で組み込まれた定義済み変数が利用されます。
後述する使用例でポジションオープンを行うので、OrderSend()についても定義しています。
#ifdef __MQL5__
#define OP_BUY ((int)0)
#define OP_SELL ((int)1)
#define OP_BUYLIMIT ((int)2)
#define OP_SELLLIMIT ((int)3)
#define OP_BUYSTOP ((int)4)
#define OP_SELLSTOP ((int)5)
///////////////////////////////////////////////////////////////////////////////
// 約定ポジションをクローズする
bool OrderClose(int iTicket, double dLots, double dPrice, int iSlippage, color arrow_color = clrNONE)
{
bool bResult = false;
bResult = PositionSelectByTicket(iTicket);
if (bResult) {
MqlTradeRequest mqlRequest = {};
MqlTradeResult mqlResult = {};
ZeroMemory(mqlResult);
ZeroMemory(mqlResult);
mqlRequest.action = TRADE_ACTION_DEAL; // 取引操作タイプ
mqlRequest.position = iTicket; // ポジションチケット
mqlRequest.symbol = PositionGetString(POSITION_SYMBOL); // シンボル
mqlRequest.volume = dLots; // ポジションボリューム
mqlRequest.deviation = iSlippage; // 価格からの許容偏差
mqlRequest.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY; // ポジションのType
mqlRequest.magic = 0; // ポジションのMagicNumber
long lMode = SymbolInfoInteger(mqlRequest.symbol, SYMBOL_FILLING_MODE);
mqlRequest.type_filling = SYMBOL_FILLING_IOC == lMode ? ORDER_FILLING_IOC : ORDER_FILLING_FOK;
if (OrderSend(mqlRequest, mqlResult)) {
bResult = true;
} else {
bResult = false;
}
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
// MQL5のオーダータイプに変換する
ENUM_ORDER_TYPE GetOrderType(int iOrderType)
{
ENUM_ORDER_TYPE OrderTypeTbl [] = {
ORDER_TYPE_BUY,
ORDER_TYPE_SELL,
ORDER_TYPE_BUY_LIMIT,
ORDER_TYPE_SELL_LIMIT,
ORDER_TYPE_BUY_STOP,
ORDER_TYPE_SELL_STOP,
ORDER_TYPE_BUY_STOP_LIMIT,
ORDER_TYPE_SELL_STOP_LIMIT,
ORDER_TYPE_CLOSE_BY,
};
return OrderTypeTbl[iOrderType];
}
///////////////////////////////////////////////////////////////////////////////
// オーダーによりポジションをオープンする
int OrderSend(string strSymbol, int iOrderType, double dLots, double dPrice, int iSlippage,
double dSL, double dTP, string strComment, int iMagicNumber, datetime dtExpiration, color clOrder)
{
int iResult = -1;
MqlTradeRequest mqlRequest = {};
MqlTradeResult mqlResult = {};
ZeroMemory(mqlRequest);
ZeroMemory(mqlResult);
if (OP_BUY == iOrderType || OP_SELL == iOrderType) {
mqlRequest.action = TRADE_ACTION_DEAL;
} else {
mqlRequest.action = TRADE_ACTION_PENDING;
}
mqlRequest.symbol = strSymbol;
mqlRequest.volume = dLots;
mqlRequest.type = GetOrderType(iOrderType);
mqlRequest.price = dPrice;
mqlRequest.sl = NormalizeDouble(dSL, (int)SymbolInfoInteger(strSymbol, SYMBOL_DIGITS));
mqlRequest.tp = NormalizeDouble(dTP, (int)SymbolInfoInteger(strSymbol, SYMBOL_DIGITS));
mqlRequest.price = dPrice;
mqlRequest.deviation = iSlippage;
mqlRequest.magic = iMagicNumber;
mqlRequest.comment = strComment;
long lMode = SymbolInfoInteger(strSymbol, SYMBOL_FILLING_MODE);
mqlRequest.type_filling = SYMBOL_FILLING_IOC == lMode ? ORDER_FILLING_IOC : ORDER_FILLING_FOK;
bool bResult = OrderSend(mqlRequest, mqlResult);
if (bResult) {
iResult = (int)mqlResult.order;
} else {
iResult = -1;
}
return iResult;
}
#endif
MQL4ではOrderClose()ですが、MQL5ではOrderSend()でクローズしていることがわかります。
MQL4で指定する必要がない、シンボル(通貨)やオーダータイプ(ENUM_ORDER_TYPE)で反対となるオーダータイプを指定していることから、逆の注文を行うことでクローズするイメージであることがわかります。
使用例
0.02LotsのBUYポジションをオープンして、10秒後にクローズする処理です。
OrderClose()の5つめの引数でcolorを指定していますが、MQL5で色の指定が無いようなので無視する実装としています。
int iNewTicket = -1;
void OnTick()
{
if (-1 == iNewTicket) {
iNewTicket = OrderSend(Symbol(), OP_BUY, 0.02,
NormalizeDouble(Ask, Digits), //注文価格
10,
NormalizeDouble(100, Digits), //S/L
NormalizeDouble(150, Digits), //T/P
"",
1,
0,
clrBlue);
EventSetTimer(10);
}
}
void OnTimer()
{
bool bResult = OrderClose(iNewTicket, 0.02, Bid, 10, clrNONE);
EventKillTimer();
}
オーターとポジションの区別
MQL5では、未約定の予約注文をオーダー、約定済をポジションと明確に区別しています。
その為、OrderClose()という関数名はMQL5では未約定オーダーに関する関数のように見えます。
よって、オーダーとポジションを区別するために関数名が以下の名前であることが良いのですが、懸念点も生じます。
No | 関数名 | 懸念 |
---|---|---|
1 | PositionClose() | MQL4ではOrderClose()が組込み関数のためPositionClose()に関数名変更しなければMQL4では今まで通りの動作になる |
2 | OrderClose() | MQL5の場合、OrderClose()という関数名は未約定ポジションのクローズという意味となるが、未約定ポジションのクローズはMQL4ではOrderDelete()がある 未約定ポジションは削除する必要があるためである |
MQL4において、OrderClose()としての役割と名前がMQL5となった場合に矛盾が生じるが以下の定義とします。
No | 関数名 | MT | 動作 | 説明 |
---|---|---|---|---|
1 | PositionClose() | MT4 | ポジションのクローズ | 新たな関数としてポジションのクローズを行う (可読性を考慮して、今後はPositionClose()で記述することが望ましい) |
2 | MT5 | ポジションのクローズ | 新たな関数としてポジションのクローズを行う | |
3 | OrderClose() | MT4 | オーダーのクローズ | オーダーのクローズを行う (ただしポジションを指定するとポジションもクローズ出来てしまう) |
4 | MT5 | ポジションのクローズ | MQL4からの移植を考慮してポジションのクローズを行う | |
5 | OrderDelete() | MT4 | 注文の削除 | 注文の削除を行う |
6 | MT5 | 注文の削除 | MQL4と同様に注文の削除を行う |
追加の定義
オーダーとポジションの区別を考慮するために以下の追加定義を行います。
MQL4/5の両方で呼出しができるように定義します。
///////////////////////////////////////////////////////////////////////////////
// MQL4/5用コード
///////////////////////////////////////////////////////////////////////////////
bool PositionClose(int iTicket, double dLots, double dPrice, int iSlippage, color arrow_color = clrNONE)
{
bool bResult = false;
return OrderClose(iTicket, dLots, dPrice, iSlippage, arrow_color);
}
使用例も以下のコードが推奨となります。
OnTimer()でOrderClose()ではなく、PositionClose()を使用しています。
何故、PositionSend()ではなく、OrderSend()で成行注文をしているかというのは、ポジションも成行で注文して約定しているためOrderSend()で注文していることとなります。
int iNewTicket = -1;
void OnTick()
{
if (-1 == iNewTicket) {
iNewTicket = OrderSend(Symbol(), OP_BUY, 0.02,
NormalizeDouble(Ask, Digits), //注文価格
10,
NormalizeDouble(100, Digits), //S/L
NormalizeDouble(150, Digits), //T/P
"",
1,
0,
clrBlue);
EventSetTimer(10);
}
}
void OnTimer()
{
bool bResult = PositionClose(iNewTicket, 0.02, Bid, 10, clrNONE);
EventKillTimer();
}
以下の関数については別途説明します。
余談
オーダーとポジション区別するMQL5で不都合な関数名だね
未約定のオーダーはクローズ(Close)ではなく、削除(Delete)だもんね
過去の関数名をなかったことにする潔さ
抹消する必要があった関数名だね・・・💤
コメント