Modification of Orders
MQL4 allows you to modify market and pending orders. Orders are modified according to the rules described in Order Characteristics and in Appendix 3.
Function OrderModify()
Trade requests for modifying of market and pending orders are formed using the function OrderModify().
bool OrderModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)
The function modifies the parameters of market and pending orders. The function returns TRUE, if the trade is made successfully. Otherwise, it returns FALSE.
Parameters:
ticket - the unique number of the order.
price - the newly requested price of a pending order or the new open price for a market order.
stoploss - the new value of StopLoss.
takeprofit - the new value of TakeProfit.
expiration - the expiration time of a pending order.
arrow_color - the color of arrows for modifying of StopLoss and/or TakeProfit in the chart. If this parameter is unavailable or its value is equal to that of CLR_NONE, the arrows will not be displayed in the chart.
Note: You can change open price and expiration only for pending orders.
If you pass unchanged values as the function parameters, the terminal will generate error 1 (ERR_NO_RESULT). There can be a limitation set for application of expiration time to pending orders on some trade servers. In this case, if you try to create a non-zero value in the parameters of expiration, error 147 (ERR_TRADE_EXPIRATION_DENIED) will be generated.
Modification of Market Orders
A standard market order contains two stop orders - StopLoss and TakeProfit. They instruct to close the order at the requested prices in order to stop losses and fix profits.
Modification of market orders may be useful for changing of the requested prices of stop orders either as a result of new calculated values obtained in the program or at the trader's initiative. The client terminal has its own tool used for modification of StopLoss: Trailing Stop. It allows the program to modify the level of StopLoss following the rate at a certain fixed distance from it (see MetaTrader 4 Cleitn Terminal User Guide).
The order-modifying function OrderModify() expands the modification capacities considerably:
The requested prices of both stop orders can be changed in the direction of the market price or deleted. A limitation for market order modification is the minimum allowed distance between the stop order and the market price, set by the dealing center (see Order Characteristics and Requirements and Limitations in Making Trades). If the program tries to change the position of a stop order in such a way that it is placed closer to the market than the allowed minimum distance, such trade request will be rejected by the client terminal and the execution of the function OrderModify()
will fail (error 130). This is why you should provide a special block in your program, which will consider this limitation.
|
Example of a simple Expert Advisor that modifies StopLosses of all market orders, for which the distance between the requested price of StopLoss and the market price is larger than the preset one (modifystoploss.mq4) |
extern int Tral_Stop=10;
int start()
{
string Symb=Symbol();
for(int i=1; i<=OrdersTotal(); i++)
{
if (OrderSelect(i-1,SELECT_BY_POS)==true)
{
int Tip=OrderType();
if(OrderSymbol()!=Symb||Tip>1)continue;
double SL=OrderStopLoss();
while(true)
{
double TS=Tral_Stop;
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);
if (TS < Min_Dist)
TS=Min_Dist;
bool Modify=false;
switch(Tip)
{
case 0 :
if (NormalizeDouble(SL,Digits)<
NormalizeDouble(Bid-TS*Point,Digits))
{
SL=Bid-TS*Point;
string Text="Buy ";
Modify=true;
}
break;
case 1 :
if (NormalizeDouble(SL,Digits)>
NormalizeDouble(Ask+TS*Point,Digits)
|| NormalizeDouble(SL,Digits)==0)
{
SL=Ask+TS*Point;
Text="Sell ";
Modify=true;
}
}
if (Modify==false)
break;
double TP =OrderTakeProfit();
double Price =OrderOpenPrice();
int Ticket=OrderTicket();
Alert ("Modification ",Text,Ticket,". Awaiting response..");
bool Ans=OrderModify(Ticket,Price,SL,TP,0);
if (Ans==true)
{
Alert ("Order ",Text,Ticket," is modified:)");
break;
}
int Error=GetLastError();
switch(Error)
{
case 130:Alert("Wrong stops. Retrying.");
RefreshRates();
continue;
case 136:Alert("No prices. Waiting for a new tick..");
while(RefreshRates()==false)
Sleep(1);
continue;
case 146:Alert("Trading subsystem is busy. Retrying ");
Sleep(500);
RefreshRates();
continue;
case 2 : Alert("Common error.");
break;
case 5 : Alert("Old version of the client terminal.");
break;
case 64: Alert("Account is blocked.");
break;
case 133:Alert("Trading is prohibited");
break;
default: Alert("Occurred error ",Error);
}
break;
}
}
}
return;
}
The above program is an Expert Advisor. If necessary, you can easily realize the order-modifying function in a script. However, it wouldn't be very useful to use a normal script in this example, because the script would end its operations after the trade has been made. The use of a script would be reasonable, in case the program realizes a one-time performing of an operation, for example, opening or closing orders. In this case, however, we're solving a task that needs continuous control over the situation: change the position of a stop order, if a certain condition is met, namely, if the distance between the market rate and the requested value of the stop order exceeds a certain preset value (10 points, in our case). For a long-term usage, it is much more convenient to write an EA that is launched for execution at every tick and stops working only upon the direct instruction by the user.
The algorithm of the above EA
modifystoploss.mq4 is very simple. The main calculations are performed in the cycle of searching in the orders (block 2-9).
The order is searched in both market and pending orders (the parameter 'pool' in the function call OrderSelect() is not explicitly specified). In block 2-3, pending orders and the orders opened for another symbol are filtered out; for the orders that have been selected, the value of StopLoss is determined.
Block 3-9 represents a cycle for modification of the selected order. In block 3-4, the new current value of the limiting distance is determined (your broker can change this value at any moment). In block 4-5, the necessity to modify the selected order (currently processed in the cycle 'for') is calculated, as well as a new value of StopLoss.
If the current order needn't be modified, the program exits the cycle 'while' at the end of block 4-5 and this order is not modified (in block 5-6).
However, if the order needs to be modified, the control is passed to block 5-6, in which the necessary parameters are calculated and the function OrderModify() is called
that forms a trade request.
If a trade is completed successfully, the operator 'break' in block 6-7 will end the execution of the cycle 'while', which results in ending of the current iteration of the order-searching cycle 'for' (the next order will start to be processed at the next iteration). If the trade is not performed successfully, the errors will be processed. If an error turns out not to be critical, the program retry to make a trade. However, if the error is estimated as critical, the control will be passed outside the modification cycle for processing of the next order (in the cycle 'for').
You should note a small feature here that relates to the modification of market orders. Function OrderModify() sets new price values for both stop orders simultaneously. However, the necessity to comply with the minimum distance concerns only the stop order, the new value of which differs from the current one. If the new value remains the same as the current one, the stop order may be at any distance from the market price, whereas the corresponding trade request is considered as correct.
For example, we have a market order Buy opened at the price of 1.295467, with the following stop orders:
StopLoss = 1.2958 and TakeProfit = 1.2960. The minimum distance set by the broker is 5 points. For the market price Bid = 1.2959, the conditions for modification of the order arise, namely, for placing StopLoss = 1.2949 (Bid - 10 points). In order to execute the function OrderModify(), you should also specify a new value of TakeProfit. Our EA does not change the position of TakeProfit, so we set its current value in the function: TakeProfit
= 1.2960.
In spite of the fact that the new requested value of TakeProfit = 1.2960 is close to the market price Bid (only 1 point, i.e., less than the allowed minimum distance of 5 points),
this value does not differ from the current value of TakeProfit = 1.2960, so the trade request will be considered as correct and performed on the server (in general, the request may be rejected, but for other reasons). Fig. 102 and 103 represent the results of a successful modification in such situation.
Fig. 102. Alerting window and symbol window as they appear at modification of an order by EA modifystoploss.mq4 when the market rate is close to the requested value of TakeProfit.
Fig. 103. Modified order in the "Terminal" window.
We can see in Fig. 103 that the modification resulted in the new value of StopLoss = 1.2949,
and the current price Bid = 1.2959 was at a distance of 1 point from the value of TakeProfit.
It must be noted separately that neither market nor pending orders should be modified) in isolation from the market situation analysis. Such modification can only be useful, if the market rate moves rapidly and in one direction, which may happen after important news. However, if you trade on a "normal" market, the decision of the necessity to modify orders must be made on the basis of market criteria. In Expert Advisor
modifystoploss.mq4, we also use a criterion (StopLoss is further from the market price than we want), on the basis of which the program decides to modify orders. However, this criterion is too simple and tough to be considered as a criterion that characterizes market situation.
Modification of Pending Orders
Modification of pending orders slightly differs from that of market orders. The important difference is that it is possible to change the requested price of the order itself. You must keep the rules limiting the position of a pending order as related to the market price and of stop orders as related to the requested order price (see Order Characteristics and Requirements and Limitations in Making Trades). At the same time, all characteristics of the pending order are considered as newly requested, whatever the previous history of related events is stored.
For example, suppose we have a pending order BuyStop = 1.2030 with StopLoss = 1.2025 and
TakeProfit = 1.2035. The broker set the minimum allowed distance as 5 points. It is easy to see that the stop orders are within the allowed band,
so any modification of the requested order open price will result in the necessary modification of at least one of the stop orders. However, if a trade request is formed that is going to change the requested order price, the values of stop orders remaining the same, the client terminal will consider this request as a wrong one and will not send it to the server for execution. For example, if the request specifies the following values: BuyStop = 1.
2028, StopLoss = 1.2025 and TakeProfit = 1.2035, this request is wrong, although the values of its stop orders have not been changed: in this case, the request is breaking the rule of keeping the minimum distance between the requested order open price and the price of one of the stop orders (see Requirements and Limitations in Making Trades).
Let's see how a script may look that modifies a pending order to approximate its requested price to the market price to a certain predefined distance. Let's set the distance as 10 points. In order to indicate the order to be modified (there can be several pending orders in the window), we are using the price, at which the script was attached to the symbol window.
|
Example of a simple script that modifies a pending order, the requested open price of which is closer to the script-attachment price than the prices of other pending orders
(modifyorderprice.mq4).
|
int start()
{
int Tral=10;
string Symb=Symbol();
double Dist=1000000.0;
double Win_Price=WindowPriceOnDropped();
for(int i=1; i<=OrdersTotal(); i++)
{
if (OrderSelect(i-1,SELECT_BY_POS)==true)
{
if (OrderSymbol()!= Symb) continue;
if (OrderType()<2) continue;
if(NormalizeDouble(MathAbs(OrderOpenPrice()-Win_Price),Digits)
< NormalizeDouble(Dist,Digits))
{
Dist=MathAbs(OrderOpenPrice()-Win_Price);
int Tip =OrderType();
int Ticket=OrderTicket();
double Price =OrderOpenPrice();
double SL =OrderStopLoss();
double TP =OrderTakeProfit();
}
}
}
if (Tip==0)
{
Alert("For ",Symb," no pending orders available");
return;
}
while(true)
{
RefreshRates();
double TS=Tral;
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);
if (TS < Min_Dist)
TS=Min_Dist;
string Text="";
double New_SL=0;
double New_TP=0;
switch(Tip)
{
case 2:
if (NormalizeDouble(Price,Digits) <
NormalizeDouble(Ask-TS*Point,Digits))
{
double New_Price=Ask-TS*Point;
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price-(Price-SL);
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price+(TP-Price);
Text= "BuyLimit ";
}
break;
case 3:
if (NormalizeDouble(Price,Digits) >
NormalizeDouble(Bid+TS*Point,Digits))
{
New_Price=Bid+TS*Point;
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price+(SL-Price);
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price-(Price-TP);
Text= "SellLimit ";
}
break;
case 4:
if (NormalizeDouble(Price,Digits) >
NormalizeDouble(Ask+TS*Point,Digits))
{
New_Price=Ask+TS*Point;
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price-(Price-SL);
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price+(TP-Price);
Text= "BuyStopt ";
}
break;
case 5:
if (NormalizeDouble(Price,Digits) <
NormalizeDouble(Bid-TS*Point,Digits))
{
New_Price=Bid-TS*Point;
if (NormalizeDouble(SL,Digits)>0)
New_SL=New_Price+(SL-Price);
if (NormalizeDouble(TP,Digits)>0)
New_TP=New_Price-(Price-TP);
Text= "SellStop ";
}
}
if (NormalizeDouble(New_SL,Digits)<0)
New_SL=0;
if (NormalizeDouble(New_TP,Digits)<0)
New_TP=0;
if (Text=="")
{
Alert("No conditions for modification.");
break;
}
Alert ("Modification ",Text,Ticket,". Awaiting response..");
bool Ans=OrderModify(Ticket,New_Price,New_SL,New_TP,0);
if (Ans==true)
{
Alert ("Modified order ",Text," ",Ticket," :)");
break;
}
int Error=GetLastError();
switch(Error)
{
case 4: Alert("Trade server is busy. Retrying..");
Sleep(3000);
continue;
case 137:Alert("Broker is busy. Retrying..");
Sleep(3000);
continue;
case 146:Alert("Trading subsystem is busy. Retrying..");
Sleep(500);
continue;
}
switch(Error)
{
case 2 : Alert("Common error.");
break;
case 64: Alert("Account is blocked.");
break;
case 133:Alert("Trading is prohibited");
break;
case 139:Alert("Order is blocked and is being processed");
break;
case 145:Alert("Modification prohibited. ",
"Order is too close to the market");
break;
default: Alert("Occurred error ",Error);
}
break;
}
Alert ("The script has completed its operations -----------------------");
return;
}
The distance between the market price and the requested price of the pending order is set in the variable
Tral. The variable Win_Price contains the value of the price, at which the script was attached to the symbol window. In the cycle of searching in orders (block 2-5), the characteristics of the order closest to the script-attachment level are calculated. Block 6-13 represents the cycle of closing orders. In block 8-9, it is decided about whether the selected order must be modified. If necessary, the new values of the requested price of stop orders are calculated here. The modification of the order is requested using the function
OrderModify() in block 10-11. Errors are processed in block 11-13.
Block 8-9 consists of four similar blocks, in which the new values used in the request are calculated. Let's consider the one intended for order SellLimit:
case 3:
if (NormalizeDouble(Price,Digits) >
NormalizeDouble(Bid+TS*Point,Digits))
{
New_Price=Bid+TS*Point;
if (NormalizeDouble(SL,Digits)>0)
New_SL = New_Price+(SL-Price);
if (NormalizeDouble(TP,Digits)>0)
New_TP = New_Price-(Price-TP);
Text= "SellLimit ";
}
break;
The new parameters of the order are calculated only if the current price 'Price' is further from the current market price Bid than the desired distance TS. If it is so, the control will be passed to the body of the operator 'if' where the new open price of the order, New_Price, is calculated. The new values of StopLoss and TakeProfit are calculated only for nonzero values. The distance between the requested order price and each price of the stop order remains the same.
For example, order SellLimit is placed at 1.2050, its StopLoss = 1.2073 and its TakeProfit
= 1. 2030. Suppose the calculations result in the new order open price equal to
1.2040. In this case, the new values of stop orders will be as follows: StopLoss = 1.2063, TakeProfit = 1. 2020. Thus, the program operations result in that the order is modified
"as a whole" - all three basic parameters (open price, StopLoss and TakeProfit)
move down simultaneously, keeping a distance between them.
At the end of block 8-9, the new values of stop orders are checked for negative values. This checking is useful if a previously placed (by another program or manually) stop order was close to zero price, for example, only 1 point above zero. In this case, if the order moves down by more than 1 point, the new price of one of the stop orders will become negative.
If this value were specified in a trade request, the request would be rejected by the client terminal.
We have to point at a disadvantage of such programs - both scripts and Expert Advisors. The program
modifyorderprice.mq4 above is highly limited in its action decision. The order to be modified can only be moved in one direction - in the direction of the market rate, its stop orders being strictly
"anchore" to the order. This program is not adjusted to modifying of the requested order price in the direction other than the market price. The possibility to change the position of any separate stop order is not realized in the program either.
The above limitation is determined, first of all, by the amount of the controls used. In this program, there is only one control of the kind - the location where the script was attached to the symbol window. Using this parameter, the trader can determine any order to be modified. However, this is all of the user's initiative. In order to work more efficiently, the user needs additional tools allowing him or her to affect other parameters of orders.
These tasks can be quite efficiently solved using MQL4. However, you will have to use another, more "intellectual" algorithm for this purpose.
It is possible to create a program that will automate your trading and modify orders in accordance with your desires. You can use in such a program, for example, graphical objects as additional controlling tools for manual trading.