So in case we have 4 short position, when a long position comes, it may close 2 of them only. [...]
This is a very common question, and it's perhaps time for another full explanation rather than just pointing you towards one of the 1,432 existing topics about it on the forum.
Let's take a scenario where you have 4 sell orders open; you are about to place a buy order; and therefore all 4 existing orders should be closed. What happens in your ClosePosition() function is as follows:
* Let's call the open orders A, B, C and D. At the beginning, A is at position #0 (i.e. OrderSelect(0, SELECT_BY_POS)), B is at position #1 etc
* You select order A, at position #0, and close it. This should succeed.
* OrdersTotal() decreases from 4 to 3. Order B moves to position 0, C moves to position 1 etc
* The loop counter i increases from 0 to 1
* Therefore, on the next pass round the loop the code selects and closes order C which is now at position #1
* Order B is missed out. Similarly, order D will also be missed because after C is closed, OrdersTotal() decreases from 3 to 2, and the variable i is increased from 1 to 2 and the loop ends.
The way to fix this is very simple: loop from OrdersTotal() downwards, not from 0 upwards. In other words: for (int i = OrdersTotal() - 1; i >= 0; i--)
Hello jjc, your explanation is full and made sense right away :) thanks a lot.
- Not adjusting for 4/5 digit brokers (TP, SL, AND SLIPPAGE)
- Not using magic numbers - incompatible with other EAs
- Not filtering by pair - incompatible with itself on other charts
- Not counting down.
- Not checking return codes
- Not use this
//++++ These are adjusted for 5 digit brokers. int pips2points; // slippage 3 pips 3=points 30=points double pips2dbl; // Stoploss 15 pips 0.015 0.0150 int Digits.pips; // DoubleToStr(dbl/pips2dbl, Digits.pips) int init(){ if (Digits % 2 == 1){ // DE30=1/JPY=3/EURUSD=5 https://www.mql5.com/en/forum/135345 pips2dbl = Point*10; pips2points = 10; Digits.pips = 1; } else { pips2dbl = Point; pips2points = 1; Digits.pips = 0; } // OrderSend(... Slippage.Pips * pips2points, Bid - StopLossPips * pips2dbl //---- These are adjusted for 5 digit brokers. } void ClosePosition(int OP) { for(iPos = OrdersTotal()-1; iPos >= 0 ; iPos--) if ( OrderSelect(iPos, SELECT_BY_POS) // Only my orders w/ && OrderMagicNumber() == magic.number // my magic number && OrderSymbol() == Symbol() // and my pair. && OrderType() <= OP_SELL && OrderType() != OP ){ if (OrderType() == OP_BUY) color clr = Pink; else clr = Lime if (!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3*pips2dbl, clr)) Alert("OrderClose failed: ", GetLastError()); } }
- Not adjusting for 4/5 digit brokers (TP, SL, AND SLIPPAGE)
- Not using magic numbers - incompatible with other EAs
- Not filtering by pair - incompatible with itself on other charts
- Not counting down.
- Not checking return codes
- Not use this
Hi WHRoeder,
I believe I had the filtering by pair, and I had added the magic # when I saw Roptor's post in the thread to which he referred me. Can you explain your code a little bit? especially this line
if (!OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3*pips2dbl, clr)) Alert("OrderClose failed: ", GetLastError());
Thank you,
Now, I've got this this single code and been running since then on a 1-min chart it in 2 separate platforms of 2 separate brokers, one is 4-digit and the other is 5.
void ClosePosition(int OP) { for (int i = OrdersTotal() - 1; i >= 0; i--) { OrderSelect(i, SELECT_BY_POS, MODE_TRADES); if (OrderType() <= OP_SELL && OrderType() != OP && OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { if (OrderType() == OP_BUY) OrderClose(OrderTicket(), OrderLots(), Bid, 3, Pink); else OrderClose(OrderTicket(), OrderLots(), Ask, 3, Lime); } } }
It is not only that I have not faced any issue with the 5-digit platform where every function has been working just as per expected, but surprisingly there has been an issue with the 4-digit platform. It's just the other way round I guess.
E.g I had 8 long positions and 1 short carried on from last week. The short is the last which was opened on Friday, which means the code was not able to close the 8 longs. I think they were more that 8 and it closed some of them. At the beginning of trading this week, the EA opened a second short which did not close any long. Then it opened a third short which successfully killed all the 8 longs.
From the top of my head, I thought of slippage, so I increased it from 3 to 5, and now it is running. We will see what will happen later on. But I'd like to find out what the error was for not working every time. Can you tell me what line of code we can add to this function to get the error in case it fails to close a position.
Thank you a lot.
Can you tell me what line of code we can add to this function to get the error in case it fails to close a position.
Regarding OrderClose: https://docs.mql4.com/trading/OrderClose as you can see it too returns a bool, "If the function succeeds, the return value is true." so if it's false you need to do something . . for example, print all the relevant info so you can debug the issue after the event.
From the top of my head, I thought of slippage, so I increased it from 3 to 5, and now it is running. [...]
The MT4 variables Ask and Bid are initialised at the beginning of a call to start() and do not then change during start() unless you explicitly call RefreshRates(). If you do something time-consuming in start() - such as closing orders - then the Ask and Bid prices can become stale, and you can find yourself trying to close orders at a price which is no longer valid. Widening your slippage tolerance is one answer to this. Updating the prices would be a better answer.
What you can do instead of using RefreshRates() is to use OrderClosePrice() as the price parameter for OrderClose(), instead of Ask/Bid. This also avoids the need to have separate lines of code for handling buys and sells (unless you really need different lime/pink marker colours). The OrderClosePrice() is updated whenever you do an OrderSelect(), without needing a separate use of RefreshRates().
As a further alternative, using MarketInfo(Symbol(), MODE_ASK) and MarketInfo(Symbol(), MODE_BID) always returns the latest available prices, equivalent to calling RefreshRates() and then using Ask or Bid.
That's an indirect solution to the probable problem.
The MT4 variables Ask and Bid are initialised at the beginning of a call to start() and do not then change during start() unless you explicitly call RefreshRates(). If you do something time-consuming in start() - such as closing orders - then the Ask and Bid prices can become stale, and you can find yourself trying to close orders at a price which is no longer valid. Widening your slippage tolerance is one answer to this. Updating the prices would be a better answer.
What you can do instead of using RefreshRates() is to use OrderClosePrice() as the price parameter for OrderClose(), instead of Ask/Bid. This also avoids the need to have separate lines of code for handling buys and sells (unless you really need different lime/pink marker colours). The OrderClosePrice() is updated whenever you do an OrderSelect(), without needing a separate use of RefreshRates().
As a further alternative, using MarketInfo(Symbol(), MODE_ASK) and MarketInfo(Symbol(), MODE_BID) always returns the latest available prices, equivalent to calling RefreshRates() and then using Ask or Bid.
jjc, thank you very much for the explanation. I don't really need different colours. I've changed the code in the 5-digit platform (which has no issue so far) to this single line
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 3, Yellow);
Should it do the same job?
Raptor, can you tell how you can go about the coding? Would you write it like this?
void ClosePosition(int OP) { for (int i = OrdersTotal() - 1; i >= 0; i--) { OrderSelect(i, SELECT_BY_POS, MODE_TRADES); if (OrderType() <= OP_SELL && OrderType() != OP && OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) { if (OrderType() == OP_BUY) { OrderClose(OrderTicket(), OrderLots(), Bid, 3, Pink); if (!OrderClose(OrderTicket(), OrderLots(), Bid, 3, Pink)) Print("...", GetLastError()); } else { OrderClose(OrderTicket(), OrderLots(), Ask, 3, Lime); if (!OrderClose(OrderTicket(), OrderLots(), Ask, 3, Lime)) Print("...", GetLastError()); } } } }
Raptor, can you tell how you can go about the coding? Would you write it like this?
Not far off . . . but you have 2 OrderClose calls there . . . you just need one of them, and add in a little more info to the print . .
OrderClose(OrderTicket(), OrderLots(), Ask, 3, Lime); // <--------- delete this line if (!OrderClose(OrderTicket(), OrderLots(), Ask, 3, Lime)) Print("OrderClose failed, order no. ",OrderTicket(), " Error: ", GetLastError());
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I have created this exit function to make an EA close whatever positions there when an order of the opposite direction is opened by the same EA.
In my Entry code I am calling this function like this:
I have been running this EA live to test this function, and noticed that in case we get more than one position of the same direction opened (e.g short positions), when a position of the opposite direction (e.g long position) comes, it does not sometimes closed all the short positions (in our example). So in case we have 4 short position, when a long position comes, it may close 2 of them only. Then when another long comes, it may close another short. After that, a new short may come after these 2 longs, so the last short of the first 4 will remain open as of this time!
And interestingly, in this example, first long which closes 2 short, it does not do that necessarily for the first 2 of the 4 shorts. It may close ticket # 1 and 3, and keeps # 2 and 4, Which means that the loop is somehow skipping orders!
Can someone fix this code?
Thanks a lot,
tapo