Help please with breakeven and arrays

 
Hi there,
Summary: I am a newb who needs help. My programming experience is limited, and I’m trying to learn MQL4. I’m writing an EA to help my brother test some trading strategies. He has come up with a strategy that uses a breakeven point. I’m trying to code it but having problems.
I’m hoping that some of the local programming whiz’s can point me in the right direction.
Firstly, the system makes multiple trades, and can be in several in the same time. (I think this would be a lot easier if there was only one trade at a time.)
My approach has been to keep track of the trades with an array. The array stores the variable Magic for each trade. Every time a new trade is made, Magic is incremented.
The main program loops through the array, comparing the current price to see if it has reached the breakeven point for any of the trades. If it has, then it adjusts the S/L for that trade – and then it attempts to remove that element from the array and shrink the array by 1. I am hoping that the EA will run faster in backtesting if he Array is kept to the smallest size necessary.
When an order is placed, the array is increased in size by 1, the variable Magic is put into the last position on the array and Magic is incremented ready for the next trade.
So, with this logic in mind, I started coding. Of course it hasn’t worked, but I am beating my head against a wall trying to work out why!

If anyone can tell me why this isn’t working (I expect there are several reasons) or suggest an alternative way to achieve the same goal I would be very grateful. Please don't laugh at how bad my code is ;)

There are several other functions but they are all working fine so I haven't included them.


void start()
{

SizeOfArray = ArraySize(Trades);// find out how big Trades array currently is, so the for loop runs through the whole thing

for (int i = 0; i < (SizeOfArray+1); i++)
{
OrderSelect(Trades[i],SELECT_BY_TICKET);

if ((OrderType() == OP_SELL) && (OrderOpenPrice() - Ask) >= BreakEven) //if trade was a sell, and current price varies from sell price by B/E
{
OrderModify(Trades[i],OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,CLR_NONE); // then set the Stop Loss to equal the opening price so trade will at least break even
ShrinkArray(Trades[i]); // remove the details of that trade from the array, no more work needs to be done with it
}
if ((OrderType() == OP_SELL) && (Bid - OrderOpenPrice()) >= StopLoss) //if trade was a sell, and current price varies from sell price by B/E
{
ShrinkArray(Trades[i]); // remove the details of that trade from the array, no more work needs to be done with it
}
if ((OrderType() == OP_BUY) && (Ask - OrderOpenPrice()) >= BreakEven) //if trade was a sell, and current price varies from sell price by B/E
{
OrderModify(Trades[i],OrderOpenPrice(),OrderOpenPrice(),OrderTakeProfit(),0,CLR_NONE); // then set the Stop Loss to equal the opening price so trade will at least break even
ShrinkArray(Trades[i]); // remove the details of that trade from the array, no more work needs to be done with it
}
if ((OrderType() == OP_BUY) && (OrderOpenPrice()) - Bid >= StopLoss) //if trade was a sell, and current price varies from sell price by B/E
{
ShrinkArray(Trades[i]); // remove the details of that trade from the array, no more work needs to be done with it
}
}

// Then the EA checks to see if a new candle has started, does some tests and then maybe calls the function to trade

}

int Function_Sell()
{

// this function is one of the trading fucntions, it handles the 'sells'
// Some housekeeping and setting variables for the trade


int result = OrderSend(Symbol(), OP_SELL, Lots, Bid, Deviation, SL, TP, "Adjustable MA", Magic);
if (result == -1)
{
int e = GetLastError();
Print(e);
}
else

{
int CurrentArraySize = ArraySize(Trades); // find out the size of the Trades array
ArrayResize(Trades,(CurrentArraySize + 1)); // make the array bigger by 1 space
Trades[CurrentArraySize] = Magic; // Set the new Array position to the current Magic result
Magic++; // increment Magic variable

return(result);
}
}


void ShrinkArray(int Temporary_Magic)

// this function finds the size of the Trades[] array. It then makes a temporary array 1 element smaller.
// it then tries to copy all of the elements of the Trades[] array across except for the one that is to be removed
// finally it shrinks Trades[] by 1 element and copies the temporary array back to Trades[]

{
int CurrentArraySize = ArraySize(Trades); // find out the size of the Trades array
CurrentArraySize-- ;
int TemporaryArray[];
ArrayResize(TemporaryArray,CurrentArraySize);

int x = 0;

for (int i = 0; i < CurrentArraySize; i++)

{
if (Trades[i] != Temporary_Magic)
{
TemporaryArray[x] = Trades[i];
x++;
}
}

ArrayResize(Trades,CurrentArraySize);

for (int f = 0; f< CurrentArraySize; f++)
{
Trades[f] = TemporaryArray[f];
}
}
 
hi

if you trade at static lotsisizes the coud is quite easy.
i think it sould be:

double breakeven=0;
for(int i=OrdersTotal()-1;i>=0;i--){
  OrderSelect(i,SELECT_BY_POS);
  breakeven+=OrderOpenPrice();
}
breakeven=breakeven/OrdersTotal();
if you trade with variable lotsizes the code changes,
i don't understand why you are using the array.
 
zzuegg:
hi

if you trade at static lotsisizes the coud is quite easy.
i think it sould be:

if you trade with variable lotsizes the code changes,
i don't understand why you are using the array.


Hi zzuegg, thanks for taking the time to help a newb :)

I think the reason I was using an array was because I thought it was needed to keep track of what trades were open and what their Magic was. You have just shown me though, that this array is built in anyway and accessible another way.
That is awesome, and I think it is a huge help!

//runs off to try to apply new knowledge...

Cheers,
 
Just wanted to add that there is no need to increment Magicnumbers for each individual trade. The sole purpose of magic numbers is to tie each trade to an individual EA. It means that an EA will only close / modify it's own orders and not change any orders created by another EA. Each order has its on ID which can be retreived with OrderTicket() after you have selected it.

Similar to zzuegg, I use this code to find my orders

for(i=1; i<=OrdersTotal(); i++)                                            // Cycle searching in orders     
   {      if (OrderSelect(i-1,SELECT_BY_POS)==true)                           // If the next is available
             {                                                                  // Analysis of orders:
             int tip=OrderType();                                               // Order type
             
             
             if(OrderSymbol()!=symb||tip>1 || OrderMagicNumber()!=magic)
               {
               Print( "not our order");                                         // The order is not "ours"
               continue;
               }                           

             double    SL     =OrderStopLoss();    
             double    TP     =OrderTakeProfit();                                     // Take Profit  of the selected order
             double    Price  =OrderOpenPrice();                                      // Price of the selected order
             double    Lot    =OrderLots();
             int       ticket =OrderTicket();                                         // Ticket of the selected order
             datetime  time   =OrderOpenTime();                                    // get time of trade
             
// DO closing / modifying actions here
}
Hope that helps
V
 
Viffer:
Just wanted to add that there is no need to increment Magicnumbers for each individual trade. The sole purpose of magic numbers is to tie each trade to an individual EA. It means that an EA will only close / modify it's own orders and not change any orders created by another EA. Each order has its on ID which can be retreived with OrderTicket() after you have selected it.

Similar to zzuegg, I use this code to find my orders

Hope that helps
V


That surely does help. Now I have a better idea about the Magic variable, and some useful code to dissect :)

Thanks!
 
Viffer:
for(i=1; i<=OrdersTotal(); i++)                                            // Cycle searching in orders     
   {      if (OrderSelect(i-1,SELECT_BY_POS)==true)                           // If the next is available
             {                                                                  // Analysis of orders:
             int tip=OrderType();                                               // Order type
             
             
             if(OrderSymbol()!=symb||tip>1 || OrderMagicNumber()!=magic)
               {
               Print( "not our order");                                         // The order is not "ours"
               continue;
               }                           

             double    SL     =OrderStopLoss();    
             double    TP     =OrderTakeProfit();                                     // Take Profit  of the selected order
             double    Price  =OrderOpenPrice();                                      // Price of the selected order
             double    Lot    =OrderLots();
             int       ticket =OrderTicket();                                         // Ticket of the selected order
             datetime  time   =OrderOpenTime();                                    // get time of trade
             
// DO closing / modifying actions here
}


i recommend to traverse you orders from back to front.
it makes no differences when you are modifying your orders, but on closing it does. also the frist order is at position 0 which you never get in your code.
by changing the for-loop in your example to

for(int i=OrdersTotal()-1;>=0;i--)


you gain a much more solid code.



//EDIT i have not seen the orderselect(i-1); in that case you are getting all the orders, but the problem when closing orders remains..




 
Yes, I had noticed the difference in direction too and was wondering if there was any impact. Out of interest, why is it better to traverse back when closing? As a guess, is it the US hedging rules? I've not noticed any impact but for sure I want to understand solid coding technique.
 
Viffer wrote >>
Yes, I had noticed the difference in direction too and was wondering if there was any impact. Out of interest, why is it better to traverse back when closing? As a guess, is it the US hedging rules? I've not noticed any impact but for sure I want to understand solid coding technique.


Viffer when you close an order you invalidate the meaning of the index string itself for successive orders. "i" no longer correlates to the index value in OrderTotal which represents the next successive order. The only way to do this is to make sure you are changing the index values above the realm that you intend to index in your next iteration of i...by continually going to lower and lower i's while having only changed the index of higher valued i's you are still working within a subset of indexes that are still valid. That is why you need to work in reverse order...it all has to do with numerology with indexes and arrays and nothing do with trading or regulations.
 
Ah, that makes sense. Thanks
 
Okay, I think I have probably understood about 80% of what is being said here, and the code being posted - which means I am learning heaps!

Firstly, does invalidating the index string only occur once per loop? I'm assuming so, because that would make sense - and the more I am learning the more I can see that this language makes sense. Not that this should affect my own code, as I am only hoping to change the S/L not close anything.

Secondly, what am I missing now? I have tried to lift the code posted here and put it into the EA, but when backtesting I am still not getting any breakevens happening...
I have kept some of the extra variables in my code, despite not using them, because I may want to re-use this one day and future EAs may use those variables - I also removed the test to see if the order was 'ours' partly because I didn't know what 'symb' was meant to be (I'm guessing whatever current symbol I am trading) and I concluded that it was unlikly to come across other trades when just running this EA for backtesting. Murphy's Law says I have most likely removed somethng I didn't understand and that is why things aren't working!

for (int i=OrdersTotal()-1; i >= 0; i--) // Cycle searching in orders (Backwards)
{ OrderSelect(i-1,SELECT_BY_POS);


double SL =OrderStopLoss();
double TP =OrderTakeProfit(); // Take Profit of the selected order
double Price =OrderOpenPrice(); // Price of the selected order
double Lot =OrderLots();
int ticket =OrderTicket(); // Ticket of the selected order
datetime time =OrderOpenTime(); // get time of trade

if (((Ask - Price) >= BreakEven || (Price - Bid) >= BreakEven) && (OrderOpenPrice() != OrderStopLoss())) // if OrderOpenPrice is exceeded by BreakEven in either direction and the order hasn't already been modified
{
OrderModify(ticket,Price,Price,TP,OrderExpiration(),CLR_NONE); // then set the S/L to equal the OrderOpenPrice
}

}
 
rush:
Firstly, does invalidating the index string only occur once per loop?
As you can tell, I'm still learning too, but I think it invalidates every loop for the whole tick. If you have 3 orders (0,1 & 2) and want to close 1 & 2. Running up when i=1, you close #1 and increment i =2. the array however changes the index values to 0 and 1 for the two orders that are left. you now try and select for i=2 which doesn't exist so the loop exits. you need to wait for the next tick to reset the loop to find and close the second order. That's my newly aquired understanding anyway.

rush wrote >>
I didn't know what 'symb' was meant to be (I'm guessing whatever current symbol I am trading)

Sorry, yes, I didn't notice that. I declare symb=symbol() elsewhere.
Reason: