取引関数のOrderSelect()、PositionSelect()について、MQL4とMQL5のソースコード共通化する方法を説明しています。
関数定義
MQL4の定義
bool OrderSelect(
int index, // index or order ticket
int select, // flag
int pool=MODE_TRADES // mode
);
約定、未約定の区別はなく、「index」で指定するポジションを選択する。
「pool」の指定でアクティブなポジション(MODE_TRADES)か取引履歴(MODE_HISTORY)かの区別の選択は可能で、履歴を含めたポジションを選択することができます。
MQL5の定義
bool OrderSelect(
ulong ticket // 注文チケット
);
引数が「ticket(=注文チケット)」のみとなり取引履歴を選択することは出来なくなっています。
MQL5でオーダーとポジションが明確に区別されるようになり、MQL4の関数名との整合性がとれなくなってます。
MQL5でオーダーは未約定状態(注文)を指し、MQL4では約定、未約定の区別なくオーダー(Order)を冠する関数名体系であったことから関数名称から推測される機能が大きくかわっています。
よってここで紹介するMQL5のOrderSelect()も機能が大きく変わり、注文チケット(未約定)に該当するオーダーを選択状態にします。
今後、MQL4もMQL5も
未約定状態注文を「オーダー」
約定状態の「ポジション」
という定義で記載していきます。
共通化方法
共通化するにあたり、重要な定義をする必要があると考えています。
- Order系関数はオーダーで使用することとする
OrderSelect() - Position系関数はポジションで使用することとする
PositionSelect()
MQL5ではごく当たり前の定義として強要されますが、MQL4でもこれを適用します。
ただしソース共通化においての注意点は、MQL4でOrder系関数が組込み関数であり、MQL5で注文をOrder系関数を使った記述をしても、MQL4に移植すると約定ポジションも含まれてしまいます。
どういったケースで支障が出るかの洗い出しは完全にはまだできていませんが、考慮する必要があるとすると注文数、ポジション数でMQL4とMQL5で数が違い、取得される種類も変わります。
MQL4でOrdersTotal()を行うとオーダーとポジションポジション数が返されるため、タイプを意識した実装が必要になります。
ソースを共通化するだけではなく、MQL4→MQL5とMQL5→MQL4への移植のケースもあると思います。よってこれら2つのケースも考慮したソース共通化を考えます。
No. | 移植方法 | 特徴 |
---|---|---|
1 | MQL4→MQL5 | OrderSelect()が使われている OrderSelect()は約定、オーダー、ポジションの区別をしない使われ方をしていることを考慮する必要がある |
2 | MQL5→MQL4 | MQL4と同じ引数のOrderSelect()を定義するが、OrderSelect()は注文のオーダーの選択で利用することと定義し、約定のポジションはPositionSelect()関数を定義して利用することとする |
ソース共通化
対処方法
共通化するためにMQL4とMQL5用の定義をします。
#ifdef __MQL5__ ~ #elseを使用することでMQL5のコンパイルにのみ有効となります。
#else~#endifはMQL5以外となるため、必然的にMQL4でのコンパイルのみ有効となります。
#ifdef __MQL5__
///////////////////////////////////////////////////////////////////////////////
// 注文を選択する
bool OrderSelect(int iIndex, int iSelect, int iPool = MODE_TRADES)
{
bool bResult = false;
if (iPool == MODE_TRADES) {
if (SELECT_BY_POS == iSelect) {
bResult = OrderGetTicket(iIndex);
} else if (SELECT_BY_TICKET == iSelect) {
bResult = OrderSelect(iIndex);
}
} else {
//MQL5では履歴から選択できない
//要改善項目(MQL4と動作が不一致)
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
// 約定済ポジション(未決済)を選択する
bool PositionSelect(int iIndex, int iSelect, int iPool = MODE_TRADES)
{
bool bResult = false;
if (MODE_TRADES == iPool) {
if (SELECT_BY_TICKET == iSelect) {
bResult = PositionSelectByTicket(iIndex);
} else {
bResult = (0 == PositionGetTicket(iIndex) ? false : true);
}
} else {
//MQL5では履歴から選択できない
//要改善項目(MQL4と動作が不一致)
}
return bResult;
}
#else //__MQL4__
///////////////////////////////////////////////////////////////////////////////
// 約定済ポジション(未決済)を選択する
bool PositionSelect(int iIndex, int iSelect, int iPool = MODE_TRADES)
{
bool bResult = false;
if (OrderSelect(iIndex, iSelect, iPool)) {
if (MODE_TRADES == iPool) {
//タイプ確認
if (OP_BUY == PositionType() || OP_SELL == PositionType()) {
//未決済の確認
if (0 == PositionCloseTime()) {
bResult = true;
}
}
} else {
//MQL4では履歴から選択できるため成功させる
//要改善項目(MQL5と動作が不一致)
bResult = true;
}
}
return bResult;
}
#endif
MQL5にOrderSelect()とPositionSelect()の定義をし、MQL4にはPositionSelect()を定義しています。
MQL4のPositionSelect()では、iPool=MODE_TRADESの場合に約定済ポジション(未決済)に限定しています。ただし、iPool!=MODE_TRADES(つまりMODE_HISTORY)の場合でも履歴から決済済を選択できるため成功させます。(※要改善項目:MQL5と動作不一致)
MODE_HISTORYのケースで動作が不一致となるのは、OrderSelect()も同様です。(※要改善項目:MQL5と動作不一致)
使用例
ポジションとオーダーをオープンし、その後それぞれの関数を利用してクローズしています。
注意点は、それぞれのループ処理(for文)でタイプを確認していることです。
OrdersTotal()やPositionsTotal()でタイプを意識した総数を取得しているように見えますが、MQL4においてOrdersTotal()でオーダーとポジションの総数を取得してしまうためです。
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);
int iNewOrder = OrderSend(Symbol(), OP_BUYSTOP, 0.03,
NormalizeDouble(140, Digits()), //注文価格
10,
NormalizeDouble(100, Digits()), //S/L
NormalizeDouble(150, Digits()), //T/P
"",
1,
0,
clrBlue);
EventSetTimer(10);
}
}
void OnTimer()
{
bool bResult = false;
//注文の削除
for (int iOrderIndex = OrdersTotal() - 1; iOrderIndex >= 0; iOrderIndex--) {
//注文選択
if (!OrderSelect(iOrderIndex, SELECT_BY_POS, MODE_TRADES)) {
continue;
}
if (OP_BUY == OrderType() || OP_SELL == OrderType()) {
continue;
}
//削除
bResult = OrderDelete(OrderTicket());
}
//ポジションのクローズ
for (int iPositionIndex = PositionsTotal() - 1; iPositionIndex >= 0; iPositionIndex--) {
//ポジション選択
if (!PositionSelect(iPositionIndex, SELECT_BY_POS, MODE_TRADES)) {
continue;
}
if (OP_BUY != PositionType() && OP_SELL != PositionType()) {
continue;
}
//価格設定
double dPrice = OP_BUY == PositionType() ? Bid : Ask;
//クローズ
bResult = PositionClose(PositionTicket(), PositionLots(), dPrice, 5);
}
EventKillTimer();
}
以下の関数については別途説明します。
- PositionType()
- PositionCloseTime()
- PositionTicket()
- PositionLots()
- PositionSelect()
- PositionClose()
- OrderSend()
余談
オーダーが約定してなくて
ポジションが約定してるのね?
そうなの
でもそれは、MQL5での話でMQL4では区別がなかったんだよ
MQL4では履歴もポジション扱いしていたような・・・
オーダー、ポジションとは別で決済された履歴もMQL5では扱いがさらに区別されているんだ
履歴の話も含めて説明するとややこしいので履歴とりあえず忘れて
ふぅ~ん・・・💤
コメント