This code and much utility functions are available for purchase as part of the Common library.
It is a common practice in my code to close all the orders once a certain condition is fulfilled. Normally, a profit target is reached, but there could be other reasons. In this post I will introduce some of the functions I am using to perform that. The main common feature to all of these functions is the counting starts from OrdersTotal()-1 and goes down to 0. This to prevent closing already closed orders as noted in this article - https://book.mql4.com/trading/orderclose.
The standard function to close all the orders is simply going through the open ones and close them one by one, starting from the last towards the first:
Where CloseOrder is:
And ClosePendingOrder() is
With a small utility function:
And
In this standard implementation, I choose to close first all the profiting orders and then to close the losing ones. Reason for that is keeping the balance / equity high thus the margin % high so we will not run into unwanted situations. Once all the profiting ones are close, the losing ones are closed too. If there is a pending order, such a Stop or Limit one, it is taken care of separately in the ClosePendingOrder function.
With this implementation, I am closing all the profiting orders first and then I close the different orders according to their size until the profit == loss. I am using this function whenever there are large positions which are covered by other large positions and I want them to net each other. It is comfortable to call this function, leaving behind the small lots size orders which are still open:
The first loop finds the highest order lots size, the second double loop goes through the different orders and closes them if their lot size is higher than the current one. Once a loop is completed, the current lot size reference decreases with the minimum lot avaialble -
These functions close all orders according to their type, whether they are long or short:
and
It is closing the open orders as well as the pending ones.
These functions close all the profiting orders or the losing ones:
and
Finally, these functions close all live orders or pending ones:
and
As always, I am happy for any inquiries or suggestions for post per email and / or mobile.
Introduction
It is a common practice in my code to close all the orders once a certain condition is fulfilled. Normally, a profit target is reached, but there could be other reasons. In this post I will introduce some of the functions I am using to perform that. The main common feature to all of these functions is the counting starts from OrdersTotal()-1 and goes down to 0. This to prevent closing already closed orders as noted in this article - https://book.mql4.com/trading/orderclose.
Functions
Standard
The standard function to close all the orders is simply going through the open ones and close them one by one, starting from the last towards the first:
bool CloseAllOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && (OrderProfit()+OrderCommission()+OrderSwap())>=0 && CloseOrder(OrderTicket(),OrderLots())==false)
return false;
Sleep(250);
}
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && (OrderProfit()+OrderCommission()+OrderSwap())<0 && CloseOrder(OrderTicket(),OrderLots())==false)
return false;
Sleep(250);
}
return true;
}
Where CloseOrder is:
bool CloseOrder(int argOrder,double argLotSize) export
{
if(OrderSelect(argOrder,SELECT_BY_TICKET) && OrderCloseTime()==0)
{
if(OrderType()!=OP_BUY && OrderType()!=OP_SELL)
return ClosePendingOrder(argOrder);
else if(OrderCloseTime()==0 && OrderClose(argOrder,VerifyLotSize(OrderSymbol(),argLotSize),OrderType()==OP_BUY?MarketInfo(OrderSymbol(),MODE_BID):MarketInfo(OrderSymbol(),MODE_ASK),Slippage,OrderType()==OP_BUY?clrGreen:clrRed)==false)
{
Log(StringConcatenate("Closing order #",argOrder," failed, verified lot size = ",VerifyLotSize(OrderSymbol(),argLotSize)),false,GetLastError());
return false;
}
}
else
{
Log(StringConcatenate("Closing order failed selecting order #",argOrder,", verified lot size = ",VerifyLotSize(OrderSymbol(),argLotSize)),false,GetLastError());
return false;
}
return true;
}
And ClosePendingOrder() is
bool ClosePendingOrder(int argOrder) export
{
if(OrderSelect(argOrder,SELECT_BY_TICKET) && OrderCloseTime()==0)
{
if(OrderDelete(argOrder)==false)
{
Log(StringConcatenate("Delete pending order #",argOrder," failed"),false,GetLastError());
return false;
}
}
else
{
Log(StringConcatenate("Delete pending order failed selecting order #",argOrder),false,GetLastError());
return false;
}
return true;
}
With a small utility function:
void Log(string argMessage,bool argSendNotificationFlag=true,int argErrorCode=0) export
{
if(argErrorCode!=0)
argMessage=StringConcatenate(argMessage,", Error: ",argErrorCode," - ",ErrorDescription(argErrorCode));
Print(StringConcatenate(AccountServer(),", ",IntegerToString(AccountNumber()),", ",MQLInfoString(MQL_PROGRAM_NAME),", ",Symbol()," ",argMessage,", Balance = ",DoubleToString(AccountBalance(),2)," ",AccountCurrency(),", P&L = ",DoubleToString(AccountProfit(),2)," ",AccountCurrency(),", Equity = ",DoubleToString(AccountEquity(),2)," ",AccountCurrency(),", Margin = ",DoubleToString(AccountMargin(),2)," ",AccountCurrency(),", Margin (%) = ",DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL),2),"%"));
if(argSendNotificationFlag==true)
SendNotification(StringConcatenate(AccountServer(),", ",IntegerToString(AccountNumber()),", ",MQLInfoString(MQL_PROGRAM_NAME),", ",Symbol()," ",argMessage,", Balance = ",DoubleToString(AccountBalance(),2)," ",AccountCurrency(),", P&L = ",DoubleToString(AccountProfit(),2)," ",AccountCurrency(),", Equity = ",DoubleToString(AccountEquity(),2)," ",AccountCurrency(),", Margin = ",DoubleToString(AccountMargin(),2)," ",AccountCurrency(),", Margin (%) = ",DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL),2),"%"));
}
And
double VerifyLotSize(string argSymbol,double argLotSize) export
{
argLotSize=MarketInfo(argSymbol,MODE_LOTSTEP)==0.1?NormalizeDouble(argLotSize,1):NormalizeDouble(argLotSize,2);
return MathMax(MarketInfo(argSymbol,MODE_MINLOT),MathMin(MarketInfo(argSymbol,MODE_MAXLOT),argLotSize));
}
In this standard implementation, I choose to close first all the profiting orders and then to close the losing ones. Reason for that is keeping the balance / equity high thus the margin % high so we will not run into unwanted situations. Once all the profiting ones are close, the losing ones are closed too. If there is a pending order, such a Stop or Limit one, it is taken care of separately in the ClosePendingOrder function.
Closing by Lot Size
With this implementation, I am closing all the profiting orders first and then I close the different orders according to their size until the profit == loss. I am using this function whenever there are large positions which are covered by other large positions and I want them to net each other. It is comfortable to call this function, leaving behind the small lots size orders which are still open:
bool CloseAllOrdersByLotSize(string argSymbol="") export
{
double MaxLotSize=0;
double ClosedProfit=0;
for(int i=OrdersTotal()-1; i>=0; i--)
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0))
{
if((OrderProfit()+OrderCommission()+OrderSwap())>=0)
{
if(CloseOrder(OrderTicket())==false)
{
Log(StringConcatenate("Failed closing position #",IntegerToString(OrderTicket())),true,GetLastError());
return false;
}
ClosedProfit+=OrderProfit()+OrderCommission()+OrderSwap();
}
else if(OrderLots()>MaxLotSize)
MaxLotSize=OrderLots();
}
for(double LotSize=MaxLotSize;LotSize>0;LotSize-=MarketInfo(argSymbol,MODE_MINLOT))
for(int j=OrdersTotal()-1;j>=0;j--)
if(OrderSelect(j,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && OrderLots()>=LotSize && (ClosedProfit+OrderProfit()+OrderCommission()+OrderSwap())>=0)
{
if(CloseOrder(OrderTicket())==false)
{
Log(StringConcatenate("Failed closing position #",IntegerToString(OrderTicket())),true,GetLastError());
return false;
}
ClosedProfit+=OrderProfit()+OrderCommission()+OrderSwap();
}
return true;
}
The first loop finds the highest order lots size, the second double loop goes through the different orders and closes them if their lot size is higher than the current one. Once a loop is completed, the current lot size reference decreases with the minimum lot avaialble -
LotSize-=MarketInfo(argSymbol,MODE_MINLOT)
.Closing by Type
These functions close all orders according to their type, whether they are long or short:
bool CloseAllLongOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (OrderType()==OP_BUY || OrderType()==OP_BUYLIMIT || OrderType()==OP_BUYSTOP) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && CloseOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
and
bool CloseAllShortOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (OrderType()==OP_SELL || OrderType()==OP_SELLLIMIT || OrderType()==OP_SELLSTOP) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && CloseOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
It is closing the open orders as well as the pending ones.
Closing by Profit
These functions close all the profiting orders or the losing ones:
bool CloseAllProfitingOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && (OrderProfit()+OrderCommission()+OrderSwap())>0 && CloseOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
and
bool CloseAllLosingOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && (OrderProfit()+OrderCommission()+OrderSwap())<0 && CloseOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
Closing Live vs. Pending Orders
Finally, these functions close all live orders or pending ones:
bool CloseAllLiveOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && (OrderType()==OP_BUY || OrderType()==OP_SELL) && CloseOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
and
bool CloseAllPendingOrders(string argSymbol="") export
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i,SELECT_BY_POS) && (StringLen(argSymbol)==0 || StringCompare(argSymbol,OrderSymbol())==0) && OrderType()!=OP_BUY && OrderType()!=OP_SELL && ClosePendingOrder(OrderTicket())==false)
return false;
Sleep(250);
}
return true;
}
In Common.
- All the functions are boolean and return the failure / success upon completion, you may use it and act accordingly if something went wrong.
- All the functions starts closing from the last function and works backwards to the first one.
- All the functions have a sleeping time between each closure, to prevent overflooding the running thread and miss an order closure.
As always, I am happy for any inquiries or suggestions for post per email and / or mobile.
Comments
Post a Comment