Martingale with step

 

Hello guys, nice to meet you, sory for my bad english, i just started to code EA two weeks ago, and i need some help with my martingale strategy, i've been struggling for almost a week now.  Short story, my code is execute an order when MA is cross, either up or down, and when order hit stop loss it will open reverse order immediately with increase lot size.  below is my code.

#property version   "1.00"
#property strict

// Private Vars
double Buy_Stop_Loss = 0;
double Buy_Take_Profit = 0;

double Sell_Stop_Loss = 0;
double Sell_Take_Profit = 0;

int order = 0;

// Public Vars
extern int MagicNumber = 666666;

extern string SlowMA = "==SLOW MA SETTINGS=="; //SLOW MA SETTINGS
extern int SlowMAPeriod = 0; //Slow MA Period
extern int SlowMAShift = 0; //Slow MA Shift
extern ENUM_MA_METHOD Slow_MA_Methode = MODE_SMA; //Slow MA Methode
extern ENUM_APPLIED_PRICE Slow_MA_AppliedPrice = PRICE_CLOSE; //Slow MA Applied Price

extern string FastMA = "==FAST MA SETTINGS=="; //FAST MA SETTINGS
extern int FastMAPeriod = 0; //Fast MA Period
extern int FastMAShift = 0; //Fast MA Shift
extern ENUM_MA_METHOD Fast_MA_Methode = MODE_SMA; //Fast MA Methode
extern ENUM_APPLIED_PRICE Fast_MA_AppliedPrice = PRICE_CLOSE; //Fast MA Applied Price

// extern double Lots = 0.01;
extern string MoneyManagement = "==MONEY MANAGEMENT SETTINGS=="; //MONEY MANAGEMENT SETTINGS
extern double Initial_Lot = 0.01; //Lot Size Setting
extern double StopLoss = 0; //Stop Loss Setting
extern double TakeProfit = 0; //Take Profit Setting
extern int StartMarti = 0; //Marti Starter
extern double MartiMultiplier = 0; //Marti Multiplier
extern int Slippage = 5; //Slippage Setting

int OnInit()
{
   if (SlowMAPeriod == 0 || FastMAPeriod == 0)
   {
      Alert("MA Period still empty");
      return (INIT_FAILED);
   }
   else if (StopLoss == 0 || TakeProfit == 0)
   {
      Alert("Stop Loss & Take Profit still empty");
      return (INIT_FAILED);
   }
   else if (StartMarti == 0 || MartiMultiplier == 0)
   {
      Alert("Start Marti & Marti Multiplier still empty");
      return (INIT_FAILED);
   }

   return(INIT_SUCCEEDED);
}

void OnTick()
{
   Buy_Stop_Loss = Ask - StopLoss * Point;
   Buy_Take_Profit = Ask + TakeProfit * Point;

   Sell_Stop_Loss = Bid + StopLoss * Point;
   Sell_Take_Profit = Bid - TakeProfit * Point;

   double Last_Fast_MA = iMA(NULL, 0, FastMAPeriod, FastMAShift, Fast_MA_Methode, Fast_MA_AppliedPrice, 2);
   double Last_slow_MA = iMA(NULL, 0, SlowMAPeriod, SlowMAShift, Slow_MA_Methode, Slow_MA_AppliedPrice, 2);

   double First_Fast_MA = iMA(NULL, 0, FastMAPeriod, FastMAShift, Fast_MA_Methode, Fast_MA_AppliedPrice, 1);
   double First_Slow_MA = iMA(NULL, 0, SlowMAPeriod, SlowMAShift, Slow_MA_Methode, Slow_MA_AppliedPrice, 1);

   if (SlowMAPeriod < FastMAPeriod) {
      if ((Last_Fast_MA < Last_slow_MA) && (First_Fast_MA > First_Slow_MA)) 
      {
         DrawSellSign("signSell");
         SendSellOrder();
      }
      else if ((Last_Fast_MA > Last_slow_MA) && (First_Fast_MA < First_Slow_MA))
      {
         DrawBuySign("signBuy");
         SendBuyOrder();
      }
   }
   else {
      if ((Last_Fast_MA > Last_slow_MA) && (First_Fast_MA < First_Slow_MA)) 
      {
         DrawSellSign("signSell");
         SendSellOrder();
      }
      else if ((Last_Fast_MA < Last_slow_MA) && (First_Fast_MA > First_Slow_MA))
      {
         DrawBuySign("signBuy");
         SendBuyOrder();
      }
   }

   MartiExecute(lotSize);
   
}

// OPEN POSITION
void SendBuyOrder() {
   if (OrdersTotal() < 1)
   {
      order = OrderSend(Symbol(), OP_BUY, LotNormalize(Initial_Lot), Ask, Slippage, Buy_Stop_Loss, Buy_Take_Profit, "Order Buy Send", MagicNumber, 0, clrBlue);
   }
}

void SendSellOrder() {
   if (OrdersTotal() < 1) {
      order = OrderSend(Symbol(), OP_SELL, LotNormalize(Initial_Lot), Bid, Slippage, Sell_Stop_Loss, Sell_Take_Profit, "Order Sell Send", MagicNumber, 0, clrRed);
   }
}

// Lot Calculation
double LotNormalize(double initialLot) {
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   double lotToUse = lotStep * NormalizeDouble(initialLot / lotStep, 0);
   lotToUse = MathMax(MathMin(maxLot, lotToUse), minLot); 
   return(lotToUse);
}

int setLossCount()
{
   int lossCount = 0;

   for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
   {
      if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == true && OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
      {
         if (OrderClosePrice() == OrderStopLoss())
         {
            lossCount++;
         }
         else if (OrderClosePrice() == OrderTakeProfit())
         {
            lossCount = 0;
         }
      }
   }
   return(lossCount);
}

void MartiExecute(double &lotSize)
{
   int closedOrdersTotal = OrdersHistoryTotal();
   int getLossCount = setLossCount();
   int currentLossCount = 0;
   
   if (closedOrdersTotal > 0)
   {
      if (OrderSelect(closedOrdersTotal - 1, SELECT_BY_POS, MODE_HISTORY) == true)
      {
         if (OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
         {
            double lotSizeXX = OrderLots();
            bool divisor = getLossCount % StartMarti == 0;
            if (getLossCount != -1 && getLossCount >= StartMarti && getLossCount % StartMarti == 0)
            {
               lotSizeXX *= MartiMultiplier;
            }
            
            if (OrderClosePrice() == OrderStopLoss())
            {
               if (OrderType() == OP_BUY)
               {
                  order = OrdersTotal() < 1 && OrderSend(Symbol(), OP_SELL, LotNormalize(lotSizeXX), Bid, Slippage, Sell_Stop_Loss, Sell_Take_Profit, "Order Sell Send", MagicNumber, 0, clrRed);
               }
               if (OrderType() == OP_SELL)
               {
                  order = OrdersTotal() < 1 && OrderSend(Symbol(), OP_BUY, LotNormalize(lotSizeXX), Ask, Slippage, Buy_Stop_Loss, Buy_Take_Profit, "Order Buy Send", MagicNumber, 0, clrBlue);
               }
            }
         }
      }
   }
}

// DRAW OBJECT
void DrawBuySign(string objectName) {
   ObjectCreate(objectName, OBJ_ARROW_BUY, 0, 0, 0);
   ObjectSet(objectName, OBJPROP_ARROWCODE, 233);
   ObjectSet(objectName, OBJPROP_COLOR, Blue);
   ObjectSet(objectName, OBJPROP_WIDTH, 3);
   ObjectSet(objectName, OBJPROP_TIME1, Time[0]);
   ObjectSet(objectName, OBJPROP_PRICE1, Low[0] - 10 * _Point);
}

void DrawSellSign(string objectName) {
   ObjectCreate(objectName, OBJ_ARROW_SELL, 0, 0, 0);
   ObjectSet(objectName, OBJPROP_ARROWCODE, 234);
   ObjectSet(objectName, OBJPROP_COLOR, Red);
   ObjectSet(objectName, OBJPROP_WIDTH, 3);
   ObjectSet(objectName, OBJPROP_TIME1, Time[0]);
   ObjectSet(objectName, OBJPROP_PRICE1, High[0] + 10 * _Point);
}

it works for the first order with startMarti set to 1 and martiMultiplier set to 2, so the it will open order like 0.01, 0.02, 0.04, 0.08, but if i increase the start marti example 2, it should be like 0.01, 0.01, 0.02, 0.02, 0.04, 0.04, 0.08 and so on, but the results is when it hit take profit for the first time, the first order is right with lot 0.01 for the second order it directly increase to 0.02, below is my results for the EA 

as you can see at order #12 it hit stop loss then at order #13 should open with 0.01 lot.  can somebody tell me what did i do wrong, or my logic is still wrong, or somebody can teach me more?


thanks before, appreciate you guys answer

 
nzrfrz: i need some help with my martingale strategy,

Martingale is not a strategy. It's a betting system.

Hedging, grid trading, same as Martingale.
          Martingale, Hedging and Grid : MHG - General - MQL5 programming forum (2016)

Martingale, guaranteed to blow your account eventually. If your strategy is not profitable without, it is definitely not profitable with.
          Martingale vs. Non Martingale (Simplified RoR vs Profit and the Illusions) - MQL5 programming forum (2015)

Why it won't work:
          Calculate Loss from Lot Pips - MQL5 programming forum (2017)
          THIS Trading Strategy is a LIE... I took 100,000 TRADES with the Martingale Strategy - YouTube (2020)

 
William Roeder #:

Martingale is not a strategy. It's a betting system.

Hedging, grid trading, same as Martingale.
          Martingale, Hedging and Grid : MHG - General - MQL5 programming forum (2016)

Martingale, guaranteed to blow your account eventually. If your strategy is not profitable without, it is definitely not profitable with.
          Martingale vs. Non Martingale (Simplified RoR vs Profit and the Illusions) - MQL5 programming forum (2015)

Why it won't work:
          Calculate Loss from Lot Pips - MQL5 programming forum (2017)
          THIS Trading Strategy is a LIE... I took 100,000 TRADES with the Martingale Strategy - YouTube (2020)

thank you for replying, now i know the term of martingale, i just wondering why my code is getting result like that, i'm just a coder so the trading strategy is up to the person who asked me to make this EA, thanks btw
William Roeder
William Roeder
  • www.mql5.com
Trader's profile
 
I think that it has something to do with your counting of orders … you are counting ++ or — if OrdersStopLoss() == OrderClosedPrice(). You have 2 doubles which are rarely equal… change that 
 
Daniel Cioca #:
I think that it has something to do with your counting of orders … you are counting ++ or — if OrdersStopLoss() == OrderClosedPrice(). You have 2 doubles which are rarely equal… change that 
i try to change this 
for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
to this 
for (int i = 0; i < OrdersHistoryTotal(); i++)

and this is the resuls

i think its work now, need to check further more, but thanks for give me a hint, really appreciate it, many thanks 

 

Paste these macros at the top of the mq5 file:

    #define nearlyEqual(x, y)   MathAbs(x - y) < 1.0e-8
    #define EQ(x, y)   (x == y || nearlyEqual(x, y))    /* Is Equal */
    #define NE(x, y)   (x != y && !nearlyEqual(x, y))   /* Is Not Equal */
    #define GT(x, y)   (x >  y && !nearlyEqual(x, y))   /* Is Greater Than */
    #define LT(x, y)   (x <  y && !nearlyEqual(x, y))   /* Is Less Than */
    #define GTE(x, y)  (x >= y || nearlyEqual(x, y))    /* Is Greater Than or Equal */ 
    #define LTE(x, y)  (x <= y || nearlyEqual(x, y))    /* Is Less Than or Equal */

old code that needs to be changed:

      if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == true && OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
      {
         if (OrderClosePrice() == OrderStopLoss())
         {
            lossCount++;
         }
         else if (OrderClosePrice() == OrderTakeProfit())
         {
            lossCount = 0;
         }
      }

to a new code that to handles the comparisons of doubles, nicely:

      if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == true && OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
      {
         if ((OrderType == OP_BUY && LTE(OrderClosePrice(), OrderStopLoss()))
          || (OrderType == OP_SELL && GTE(OrderClosePrice(), OrderStopLoss())))
         {
            lossCount++;
         }
         else if ((OrderType == OP_BUY && GTE(OrderClosePrice(), OrderTakeProfit()))
               || (OrderType == OP_SELL && LTE(OrderClosePrice(), OrderTakeProfit())))
         {
            lossCount = 0;
         }
      }

see https://www.mql5.com/en/code/25723
 
  1.          else if ((OrderType == OP_BUY && GTE(OrderClosePrice(), OrderTakeProfit()))
    

    TP/SL become market orders when hit. That comparison may not work. Perhaps, try isTP = |OCP-OTP| < |OCP-OSL|

  2. Why did you post your MT4 question in the MT5 EA section instead of the MQL4 section, (bottom of the Root page)?
              General rules and best pratices of the Forum. - General - MQL5 programming forum? (2017)
    Next time, post in the correct place. The moderators will likely move this thread there soon.

 
William Roeder #:
  1. TP/SL become market orders when hit. That comparison may not work. Perhaps, try isTP = |OCP-OTP| < |OCP-OSL|

Market orders such as TP and SL are subject to slippage. Therefore, a buy order has its OderClosePrice() >= OrderTakeProft(), if it has positive slippage (it can give false results with negative slippage).

isTP = |OCP-OTP| < |OCP-OSL| is also not precise! The latter condition might also be fulfilled for any manually-closed order (i.e. a non-specific test).

NB: on MT4 it is difficult to differentiae between orders closed by TP or SL from manually closed orders. 

Edited: I think this will be a better test:

         else if ((OrderType() == OP_BUY && GTE(OrderClosePrice(), OrderTakeProfit()))
               || (OrderType() == OP_SELL && LTE(OrderClosePrice(), OrderTakeProfit()))
               || (StringFind(OrderComment(), "TP") > 0))
         {
            lossCount = 0;
         }
 
amrali #:

Market orders such as TP and SL are subject to slippage. Therefore, a buy order has its OderClosePrice() >= OrderTakeProft(), if it has positive slippage (it can give false results with negative slippage).

isTP = |OCP-OTP| < |OCP-OSL| is also not precise! The latter condition might also be fulfilled for any manually-closed order (i.e. a non-specific test).

NB: on MT4 it is difficult to differentiae between orders closed by TP or SL from manually closed orders. 

Edited: I think this will be a better test:

OrderType == OP_BUY && GTE(OrderClosePrice(), OrderTakeProfit())

And what about the slippage you talked about ? The close price can be smaller than the TP.

 
Alain Verleyen #:

And what about the slippage you talked about ? The close price can be smaller than the TP.

Yes sure, it can give false results with negative slippage.
 
amrali #:
Yes sure, it can give false results with negative slippage.

At least William version would deal with such slippage, most of the time.

It's not an easy issue to solve in a general way.

Reason: