取引関数のOrderModify()、PositionModify()について、MQL4とMQL5のソースコード共通化する方法を説明しています。
関数定義
MQL4の定義
bool OrderModify(
int ticket, // ticket
double price, // price
double stoploss, // stop loss
double takeprofit, // take profit
datetime expiration, // expiration
color arrow_color // color
);
ポジション、オーダーの区別はなく、「ticket」で指定した対象(ポジション、オーダー共に対象とすることが可能)を更新します。
MQL5の定義
定義なし
MQL5には、OrderModify()がありません。
共通化方法
- Order系関数はオーダーで使用することとする
OrderModify() - Position系関数はポジションで使用することとする
PositionModify()
ただし、MQL5でオーダーはOrder系関数を使った記述をしても、MQL4に移植するとポジションも含まれてしまいます。
ソースを共通化するだけではなく、MQL4→MQL5とMQL5→MQL4への移植のケースもあると思います。よってこれら2つのケースも考慮したソース共通化を考えます。
No. | 移植方法 | 特徴 |
---|---|---|
1 | MQL4→MQL5 | オーダー、ポジションの更新をOrderModify()で行われている OrderModify()はオーダー、ポジションの区別をしない使われ方をしていることを考慮する必要がある PositionModify()の使用に分けた実装にすることが望ましい |
2 | MQL5→MQL4 | MQL4と同じ引数のOrderModiy()を定義するが、OrderModify()はオーダーの更新で利用することと定義し、ポジションはPositionModify()関数を定義して利用することとする |
ソース共通化
対処方法
共通化するためにMQL4とMQL5用の定義をします。
#ifdef __MQL5__ ~ #elseを使用することでMQL5のコンパイルにのみ有効となります。
#else~#endifはMQL5以外となるため、必然的にMQL4でのコンパイルのみ有効となります。
#ifdef __MQL5__
///////////////////////////////////////////////////////////////////////////////
// オーダーを更新する
bool OrderModify(long lTicket, double dPrice, double dStopLoss, double dTakeProfit, datetime dtExpiration, color arrow_color = clrNONE)
{
bool bResult = false;
bResult = OrderSelect(lTicket);
if (bResult) {
MqlTradeRequest mqlRequest = {};
MqlTradeResult mqlResult = {};
ZeroMemory(mqlRequest);
ZeroMemory(mqlResult);
int iDigits = (int)SymbolInfoInteger(OrderSymbol(), SYMBOL_DIGITS); // 小数点以下の桁数
mqlRequest.action = TRADE_ACTION_MODIFY;
mqlRequest.order = lTicket; // 注文チケット
mqlRequest.price = NormalizeDouble(dPrice, iDigits); // 価格
mqlRequest.sl = NormalizeDouble(dStopLoss, iDigits);
mqlRequest.tp = NormalizeDouble(dTakeProfit, iDigits);
mqlRequest.symbol = OrderSymbol(); // シンボル
mqlRequest.volume = NormalizeDouble(OrderLots(), 2); // ポジションボリューム
mqlRequest.deviation = 0; // 価格からの許容偏差
mqlRequest.type = (ENUM_ORDER_TYPE)OrderType(); // ポジションのType
mqlRequest.magic = OrderMagicNumber(); // ポジションのMagicNumber
long lMode = SymbolInfoInteger(mqlRequest.symbol, SYMBOL_FILLING_MODE);
mqlRequest.type_filling = SYMBOL_FILLING_IOC == lMode ? ORDER_FILLING_IOC : ORDER_FILLING_FOK;
bResult = OrderSend(mqlRequest, mqlResult);
if (bResult) {
} else {
ERR("retcode", mqlResult.retcode);
}
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
// ポジションを更新する
bool PositionModify(long lTicket, double dPrice, double dStopLoss, double dTakeProfit, datetime dtExpiration, color arrow_color = clrNONE)
{
bool bResult = false;
bResult = PositionSelect((int)lTicket, SELECT_BY_TICKET, MODE_TRADES);
if (bResult) {
MqlTradeRequest mqlRequest = {};
MqlTradeResult mqlResult = {};
ZeroMemory(mqlRequest);
ZeroMemory(mqlResult);
int iDigits = (int)SymbolInfoInteger(PositionSymbol(), SYMBOL_DIGITS); // 小数点以下の桁数
mqlRequest.action = TRADE_ACTION_SLTP;
mqlRequest.position = lTicket; // ポジションチケット
mqlRequest.price = NormalizeDouble(PositionOpenPrice(), iDigits);// 価格
mqlRequest.sl = NormalizeDouble(dStopLoss, iDigits);
mqlRequest.tp = NormalizeDouble(dTakeProfit, iDigits);
mqlRequest.symbol = PositionSymbol(); // シンボル
mqlRequest.volume = NormalizeDouble(PositionLots(), 2); // ポジションボリューム
mqlRequest.type = (ENUM_ORDER_TYPE)PositionType(); // ポジションのType
mqlRequest.magic = PositionMagicNumber(); // ポジションのMagicNumber
long lMode = SymbolInfoInteger(mqlRequest.symbol, SYMBOL_FILLING_MODE);
mqlRequest.type_filling = SYMBOL_FILLING_IOC == lMode ? ORDER_FILLING_IOC : ORDER_FILLING_FOK;
bResult = OrderSend(mqlRequest, mqlResult);
if (bResult) {
} else {
ERR("retcode", mqlResult.retcode);
}
}
return bResult;
}
#else //__MQL4__
///////////////////////////////////////////////////////////////////////////////
// ポジションを更新する
bool PositionModify(long lTicket, double dPrice, double dStopLoss, double dTakeProfit, datetime dtExpiration, color arrow_color = clrNONE)
{
return OrderModify(lTicket, dPrice, dStopLoss, dTakeProfit, dtExpiration, arrow_color);
}
#endif
MQL5にOrderModify()とPositionModify()の定義をし、MQL4にはPositionModify()を定義しています。
MQL4のPositionModify()は、OrderModify()をそのまま呼び出す移植用のラッパー関数でしかありません。そのため、オーダーに対して使用してもそのまま動作します。よって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()
{
static int iCountCall = 0;
switch (iCountCall) {
case 0:
Modify(iCountCall);
break;
case 1:
Close();
break;
default:
EventKillTimer();
break;
}
iCountCall++;
}
void Modify(int iCount)
{
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 = OrderModify(OrderTicket(), OrderOpenPrice() + 1, OrderStopLoss() + 1, OrderTakeProfit() + 1, 0, clrNONE);
}
//ポジションの更新
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 = PositionModify(PositionTicket(), PositionOpenPrice(), PositionStopLoss() + 1, PositionTakeProfit() + 1, 0, clrNONE);
}
}
void Close()
{
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);
}
}
以下の関数については別途説明します。
- OrderSend()
- PositionType()
- PositionTicket()
- PositionLots()
- PositionSelect()
- PositionClose()
- PositionOpenPrice()
- PositionStopLoss()
- PostionTakeProfit()
- PositionModify()
余談
TRADE_ACTION_MODIFY
と
TRADE_ACTION_SLTP
の使い分けがなんだかややこしいね
TRADE_ACTION_MODIFY:オーダー
TRADE_ACTION_SLTP:ポジション
で使い分けするのよね
名称にはそこが現れていないのが混乱の元だね
TRADE_ACTION_MODIFY
だけで良かったのにぃ~
それな!
覚えれば済むけどね・・・💤
コメント