I didn't check the lastest DerkWehler's version which seems a little complex, but the original version and the Omelette's ones have both the same bug.
The original version has also a recovery bug which was fixed by Omelette, but the code to fix it has itself the same bug.
Also, as Omelette said, it's NOT reliable to backtest EAs which are calling the OrderHistory, because during the backtest the history called is the real history of the account and NOT the pseudo history generated by the backtest itself. MQ is aware of this incredible bug, but don't care about it.
Now the bug itself comes from the fact that even if the History tab of the terminal is sorted by descending CloseTime, there is no guarantee that scanning the history from the last item the first order found is the last closed one. It is always needed to check this.
the initial code is
PHP Code:
int GetLotSizeFactor()
{
int histotal = OrdersHistoryTotal();
if (histotal > 0)
{
for(int cnt=histotal-1;cnt>=0;cnt--) // retrieve closed orders counting from the last.
{
if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
{
if(OrderProfit() < 0) // latest order close was a loss
{
LotSizeFactor = LotSizeFactor + 1;
return (LotSizeFactor);
}
else // latest order closed was a win
{
LotSizeFactor = LotSizeFactor - 1;
if (LotSizeFactor <= 0)
{
LotSizeFactor = 1;
}
return (LotSizeFactor);
}
}
}
}
}
return (LotSizeFactor); // no trades recorded in history just return the starting number.
}
I would sujest to replace this sub by this one:
PHP Code:
int GetLotSizeFactor()
{
int histotal = OrdersHistoryTotal();
datetime LastCloseTime;
bool LastIsLoss;
if (histotal == 0) return (LotSizeFactor); // no trades recorded in history just return the starting number.
else
{
for(int cnt=histotal-1;cnt>=0;cnt--) // retrieve the last closed order
{
if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
{
if(OrderCloseTime() > LastCloseTime)
{
LastCloseTime = OrderCloseTime();
LastIsLoss = OrderProfit() < 0;
}
}
}
}
if(LastCloseTime == 0) return (LotSizeFactor); // no trades recorded in history just return the starting number.
if(LastIsLoss) LotSizeFactor += 1;// latest order close was a loss
else LotSizeFactor -= 1;// latest order closed was a win
if (LotSizeFactor <= 0) LotSizeFactor = 1;
return (LotSizeFactor);
}
}
And it is still needed to correct the recovery code in the same manner.
The routine I would use is this one, it doesn't need to recover anything as the lot size is based on the last order directly, which I think is more reliable; it doesn't work with a size factor, but with a size unit :
PHP Code:
double GetLotSize()
{
datetime LastCloseTime;
double NewLots;
for(int cnt=OrdersHistoryTotal()-1;cnt>=0;cnt--) // retrieve the last closed order
{
if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
{
if(OrderCloseTime() > LastCloseTime)
{
LastCloseTime = OrderCloseTime();
NewLots = OrderLots() - LotsUnit*(1 - 2*(OrderProfit() < 0));
}
}
}
}
if (NewLots <= 0) return(LotsUnit);
return (NewLots);
}