This code and much utility functions are available for purchase as part of the Common library.


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.

 

This entry was posted by . Bookmark the . Titled

Leave a Reply

Your email address will not be published. Required fields are marked *