ホーム » ソース共通化 » 取引関数 » OrderModify() – 取引関数

OrderModify() – 取引関数

取引関数

取引関数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.移植方法特徴
1MQL4→MQL5オーダー、ポジションの更新をOrderModify()で行われている
OrderModify()はオーダー、ポジションの区別をしない使われ方をしていることを考慮する必要がある
PositionModify()の使用に分けた実装にすることが望ましい
2MQL5→MQL4MQL4と同じ引数の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);
	}
}

以下の関数については別途説明します。

  1. OrderSend()
  2. PositionType()
  3. PositionTicket()
  4. PositionLots()
  5. PositionSelect()
  6. PositionClose()
  7. PositionOpenPrice()
  8. PositionStopLoss()
  9. PostionTakeProfit()
  10. PositionModify()

余談

ヒナタ
ヒナタ

TRADE_ACTION_MODIFY

TRADE_ACTION_SLTP
の使い分けがなんだかややこしいね

ITサービス屋
ITサービス屋

TRADE_ACTION_MODIFY:オーダー
TRADE_ACTION_SLTP:ポジション
で使い分けするのよね
名称にはそこが現れていないのが混乱の元だね

ヒナタ
ヒナタ

TRADE_ACTION_MODIFY
だけで良かったのにぃ~

ITサービス屋
ITサービス屋

それな!

ヒナタ
ヒナタ

覚えれば済むけどね・・・💤

コメント

タイトルとURLをコピーしました