MR.B

 

I'm wondering if someone can verify the strategy of an EA I've had built. It's called 'MR. B' as an acronym for MFI, RSI, and Bollinger Bands. It's supposed to be a simple EA that enters trades when any two of the three indicators confirm trading conditions (according to the threshold levels I've designated) and exit trades when any two of the three can no longer confirm trading conditions. I've recently begun demo testing it and currently it's losing big time so I'm wondering if it's truly a fault of the strategy or if there's been a failure to properly implement the strategy.

extern int MagicNumber= 1234;
extern double Risk= 1;
extern int RSI_PERIOD= 30;
extern int MFI_PERIOD= 30;
extern int BOLINGER_PERIOD= 30;
extern int BOLINGER_DEVIATION= 2;
extern double RSI_LONG_THRESHOLD= 33.33;
extern double MFI_LONG_THRESHOLD= 33.33;
extern double RSI_SHORT_THRESHOLD= 66.66;
extern double MFI_SHORT_THRESHOLD= 66.66;

//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----

//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----

//----
return(0);
}

int GetLotDigits()
{
int lotDigits;
double l= MarketInfo(Symbol(),MODE_MINLOT);
lotDigits= 0;
while(l<1)
{
l=l*10;
lotDigits++;
}
return(lotDigits);
}

double CalcLots(double risk, double SL1, int opType)
{
double PointValueDollar;
double SLDiffPoints;
double vol;

double TICK_VALUE= MarketInfo(Symbol(), MODE_TICKVALUE);

if(opType==OP_BUY)
SLDiffPoints= (Ask-SL1)/Point;
else if(opType==OP_SELL)
SLDiffPoints= (SL1-Bid)/Point;


SLDiffPoints= SLDiffPoints;
if(0!=SLDiffPoints)
{
PointValueDollar = (AccountEquity() * (risk / 100) / (SLDiffPoints)) ;
vol= PointValueDollar/TICK_VALUE;
//Log("PointValueDollar="+PointValueDollar+", vol="+vol, LOG_TRACE);
vol= NormalizeDouble(vol, GetLotDigits());
if(vol<MarketInfo(Symbol(),MODE_MINLOT))
vol= MarketInfo(Symbol(),MODE_MINLOT);
}
else
vol= MarketInfo(Symbol(),MODE_MINLOT);
return(vol);
}

bool CloseAllTrades(int op_type)
{
int rc= true;
int cnt;
for(cnt=OrdersTotal()-1;cnt>=0;cnt--)
{
if(OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
if (OrderMagicNumber()==MagicNumber && OrderType()==op_type)
{
rc= rc && OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(),
MarketInfo(OrderSymbol(),MODE_SPREAD), Yellow);
}
}
return(rc);
}

//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
double rsi= iRSI(Symbol(), 0, RSI_PERIOD, PRICE_TYPICAL, 1);
double mfi= iMFI(Symbol(), 0, MFI_PERIOD, 1);
double bb_down= iBands(Symbol(), 0, BOLINGER_PERIOD, BOLINGER_DEVIATION, 0, PRICE_TYPICAL, MODE_LOWER, 0);
double bb_up= iBands(Symbol(), 0, BOLINGER_PERIOD, BOLINGER_DEVIATION, 0, PRICE_TYPICAL, MODE_UPPER, 0);
int i;
static datetime lastTradeTime = 0;

double profit= 0;
for(i=OrdersHistoryTotal()-1; i>=0; i--)
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
if(iBarShift(Symbol(), PERIOD_W1, OrderOpenTime())==0)
profit+= OrderProfit()+OrderSwap();

Comment("Account balance made this week: %"+DoubleToStr(profit/AccountBalance(),2));

int count;

{
count= 0;
if(rsi<RSI_LONG_THRESHOLD)
count++;

if(mfi<MFI_LONG_THRESHOLD)
count++;

if(Low[0]<bb_down)
count++;

if(count>=2)
{
CloseAllTrades(OP_SELL);
if(lastTradeTime!=Time[0])
if(-1!=OrderSend(Symbol(), OP_BUY, CalcLots(Risk, Bid-(bb_up-bb_down), OP_BUY), Ask, MarketInfo(Symbol(), MODE_SPREAD), 0,
0, WindowExpertName(), MagicNumber, 0, Green))
lastTradeTime= Time[0];
}

count= 0;
if(rsi>RSI_SHORT_THRESHOLD)
count++;
if(mfi>MFI_SHORT_THRESHOLD)
count++;
if(High[0]>bb_up)
count++;

if(count>=2)
{
CloseAllTrades(OP_BUY);
if(lastTradeTime!=Time[0])
if(-1!=OrderSend(Symbol(), OP_SELL, CalcLots(Risk, Bid+(bb_up-bb_down), OP_SELL), Bid, MarketInfo(Symbol(), MODE_SPREAD), 0,
0, WindowExpertName(), MagicNumber, 0, Red))
lastTradeTime= Time[0];
}
}
//----
return(0);
}
//+------------------------------------------------------------------+

 

i dont c any problem in the code u can make a visual backtest & c what is going on

& for the next time

 
qjol:

i dont c any problem in the code u can make a visual backtest & c what is going on

& for the next time


Thank you very much for confirming that the strategy is being properly implemented. This lets me know that it's the strategy itself that's at fault.
 

FWIW when using RSI for entry signal you typically want the signal to be taken when the RSI value crosses "back" over the threshold.

For example, the "go long" signal would be taken to be the event in which the RSI value crosses above a threshold value from below.


Threshold=33.
Bar N: RSI() = 29. // we are below the threshold value for going long, do nothing

Bar N+1: RSI() = 32. // we are below the threshold value for going long, do nothing

Bar N+2: RSI() = 34. // we are above the threshold value for going long and the prior value was below the threshold, now go long

And likewise we consider the signal from RSI for remaining in the long to be valid until RSI crosses back below the low threshold (33 in this case) or crosses the upper threshold from below (if upper threshold if 67 then we close the long as soon as RSI()>67, but we don't open a short until RSI() crosses back below 67)

 

Okay, something is definitely wrong with this EA as I've noticed that it never stops trading. I've raised the thresholds to conventional levels and observe continuing trade activity even when thresholds aren't being reached.

 
  1. Already said, use SRC
  2. No check for already open orders. Opens new once per bar.
  3. int GetLotDigits()
    {
       int lotDigits;
       double l= MarketInfo(Symbol(),MODE_MINLOT);
       lotDigits= 0;
       while(l<1)
       {
          l=l*10;
          lotDigits++;
       }
       return(lotDigits);
    }
    Lot size doesn't need to be normalized to minlot. It needs to be a multiple of lotStep and at least minlot. LotStep could be 1/10 of minlot (IBFX use to have minLot=0.1, lotStep=0.01) and not necessary ending in 1 (0.1 or 0.01) A 0.05 lotStep would break your code.
    double minLot  = MarketInfo(Symbol(), MODE_MINLOT),
           LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
    size = MathFloor(size/LotStep)*LotStep;
    if (size < minLot){ // Insufficient margin.
    

    double TICK_VALUE= MarketInfo(Symbol(), MODE_TICKVALUE);
    double PointValuePerLot() { // Value in account currency of a Point of Symbol.
        /* In tester I had a sale: open=1.35883 close=1.35736 (0.00147)
         * gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
         * IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
         * IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
         *                                  $1.00/point or $10.00/pip.
         *
         * https://www.mql5.com/en/forum/127584 CB: MODE_TICKSIZE will usually return the
         * same value as MODE_POINT (or Point for the current symbol), however, an
         * example of where to use MODE_TICKSIZE would be as part of a ratio with
         * MODE_TICKVALUE when performing money management calculations which need
         * to take account of the pair and the account currency. The reason I use
         * this ratio is that although TV and TS may constantly be returned as
         * something like 7.00 and 0.00001 respectively, I've seen this
         * (intermittently) change to 14.00 and 0.00002 respectively (just example
         * tick values to illustrate). */
        return(  MarketInfo(Symbol(), MODE_TICKVALUE)
               / MarketInfo(Symbol(), MODE_TICKSIZE) ); // Not Point.
    }