Expansion of the Functions of the Nanpin Martin EA (Introduction of Cocomo Method, Changing Martin Multiplier, etc.)

MT4

In the logic of the Grid Martingale EA, the setting of the grid width and the martingale multiplier, which determines how much to increase the lot size, are the basic settings.

While the Martingale method typically uses a multiplier of 2, the Grid Martingale EA often employs a multiplier of 1.5.

In addition, there is a method called the “Cocomo” method, which involves a more complex calculation rather than simply multiplying the previous lot size by a constant.

This article will introduce how to expand the lot size setting function of the Grid Martingale EA, including the introduction of the Cocomo method.

We aim to explain the meaning of the code as thoroughly as possible for beginners, so even those who are new to this can challenge themselves to create an EA.

    Base Model of the EA

    Here, we refer to the EA created in the following article as the “base model,” and we will be adding additional functionality to it.

    This article explains how to create a very basic grid martingale EA from scratch, so if you haven’t seen it yet, please take a look.

    Setting Input Parameters

    In the base model, we had set the following input parameters.

    input double first_lot = 0.01; // Initial lot size input
    double nanpin_range = 200; // Grid range input
    double profit_target = 1.00; // Profit target input
    int magic_number = 10001; // Magic number static
    int ticket_number; // Ticket number
    double slippage = 10; // Slippage

    We will add an additional input parameter for lot size patterns here.

    input int lot_type = 1;// Lot size pattern (1: martingale 1.5x, 2: martingale 2x, 3: Cocomo method)

    Lot Size Pattern (lot_type)

    We have set a variable to switch between lot size settings for grid orders.

    Here, we have set up three patterns to choose from:

    1. Martingale 1.5x
    2. Martingale 2x
    3. Cocomo method

      Loop Processing

      With the necessary additional processing completed beforehand, we will now move on to adding functionality within the loop processing.

      void OnTick()

      void OnTick()
       {

      From here on out, the following content will be added within the void OnTick() function.

      Variable Definitions

      In the base model, the following variables were defined:

      int cnt;
      int current_buy_position; // latest buy position
      int current_sell_position; // latest sell position
      int buy_position; // buy position count
      int sell_position; // sell position count
      double buy_profit; // unrealized profit/loss on buy positions
      double sell_profit; // unrealized profit/loss on sell positions

      We will add the following 5 definitions here:

      double current_buy_lot; // lot size of the latest buy position
      double current_sell_lot; // lot size of the latest sell position
      double pre_buy_lot; // lot size of the previous buy position
      double pre_sell_lot; // lot size of the previous sell position
      double nanpin_lot; // lot size of the averaging down order

      current_buy_lot、current_sell_lot

      current_buy_lot is a variable that records the lot size of the latest buy position. For example, if there are three buy positions, it represents the lot size of the third buy position. current_sell_lot is the same.

      pre_buy_lot、pre_sell_lot

      pre_buy_lot is a variable that records the lot size of the second latest buy position. For example, if there are three buy positions, it represents the lot size of the second buy position. pre_sell_lot is the same.

      nanpin_lot

      To handle different cases when placing averaging down orders, we will prepare a variable called nanpin_lot.

      Position Check

      We will add a function to check the lot size of each position.

      Before the addition

      In the base model, the following code was used:

      buy_position=0;// initialize buy position count
      sell_position=0;// initialize sell position count
      current_buy_position=-1;// initialize latest buy position
      current_sell_position=-1;// initialize latest sell position
      
      for(cnt=0;cnt<OrdersTotal();cnt++)// check positions
      {
        if(OrderSelect(cnt,SELECT_BY_POS)==false)continue;
        if(OrderMagicNumber()!=magic_number)continue;
        if(OrderType()==OP_BUY)
        {
          current_buy_position=cnt;
          buy_position+=1;
          buy_profit=buy_profit+OrderProfit();
        };
      
        if(OrderType()==OP_SELL)
        {
          current_sell_position=cnt;
          sell_position+=1;
          sell_profit=sell_profit+OrderProfit();
        };
      
      }

      After the addition

      We will make the following changes. (“//added” indicates the added lines.)

      buy_position=0;//initialize buy position count
      sell_position=0;//initialize sell position count
      current_buy_position=-1;//initialize latest buy position
      current_sell_position=-1;//initialize latest sell position
      
      current_buy_lot=0;//initialize lot size of the latest buy position //added
      current_sell_lot=0;//initialize lot size of the latest sell position //added
      pre_buy_lot=0;//initialize lot size of the previous buy position //added
      pre_sell_lot=0;//initialize lot size of the previous sell position //added
      
      for(cnt=0;cnt<OrdersTotal();cnt++)//check positions
      {
        if(OrderSelect(cnt,SELECT_BY_POS)==false)continue;
        if(OrderMagicNumber()!=magic_number)continue;
        if(OrderType()==OP_BUY)
        {
          current_buy_position=cnt;
          buy_position+=1;
          buy_profit=buy_profit+OrderProfit();
      
             pre_buy_lot=current_buy_lot; //added
             current_buy_lot=OrderLots(); //added
        };
      
        if(OrderType()==OP_SELL)
        {
          current_sell_position=cnt;
          sell_position+=1;
          sell_profit=sell_profit+OrderProfit();
      
             pre_sell_lot=current_sell_lot; //added
             current_sell_lot=OrderLots(); //added
        };
      
      }

      To explain the added lines, we are checking each position one by one, and if it is a buy position:

      • We record the lot size of the previous buy position in pre_buy_lot before overwriting it with the lot size of the latest buy position in current_buy_lot.
      • We record the lot size of the latest buy position in current_buy_lot before overwriting the previous value.

      This process is done for each buy position. The recorded values of pre_buy_lot and current_buy_lot will remain after checking all buy positions.

      Additional Entry (Martingale) Orders

      Next, we will add a function for averaging down orders.

      Before the addition

      In the base model, the following code was used:

      if(buy_position>0) //If holding one or more buy positions
           {
            OrderSelect(current_buy_position,SELECT_BY_POS); //Select the latest buy position
            if(Ask<(OrderOpenPrice()-nanpin_range*Point)) //Check if the current price has reached the Martingale range   
              {
               ticket_number=OrderSend(
                                Symbol(), //Currency pair
                                OP_BUY,  //Buy:OP_BUY, Sell:OP_SELL
                                round(OrderLots()*1.5*100)/100, //Lot size
                                Ask, //Order price
                                slippage, //Slippage
                                0,  //Stop-loss
                                0,  //Take-profit
                                "nanpin_buy",  //Order comment
                                magic_number,  //Magic number
                                0,  //Order expiration time
                                Blue  //Arrow color
                             );
              }
           }
      if(sell_position>0) //If holding one or more sell positions
           {
            OrderSelect(current_sell_position,SELECT_BY_POS); //Select the latest sell position
            if(Bid>(OrderOpenPrice()+nanpin_range*Point)) //Check if the current price has reached the Martingale range
              {
               ticket_number=OrderSend(
                                Symbol(), //Currency pair
                                OP_SELL, //Buy:OP_BUY, Sell:OP_SELL
                                round(OrderLots()*1.5*100)/100, //Lot size
                                Bid, //Order price
                                slippage, //Slippage
                                0, //Stop-loss
                                0, //Take-profit
                                "nanpin_sell", //Order comment
                                magic_number, //Magic number
                                0, //Order expiration time
                                Red //Arrow color
                             );
              }
      
           }

      Lot size selection

      Regarding the lot size, we directly wrote it in the OrderSend function as follows:

      round(OrderLots()*1.5*100)/100, //Lot size

      We will now use the nanpin_lot variable that we added in the variable definitions to set the lot size as follows:

      //Lot size selection
      if(lot_type==1){nanpin_lot = round(OrderLots()*1.5*100)/100;} //Martingale multiplier: 1.5x
      if(lot_type==2){nanpin_lot = round(OrderLots()*2*100)/100;} //Martingale multiplier: 2x
      if(lot_type==3){nanpin_lot = pre_buy_lot+current_buy_lot;} //Cocomo method

      Then, we simply replace the lot size part in the OrderSend function with nanpin_lot.

      Regarding the Martingale multiplier of 2x, there is no need for further explanation, so I will briefly explain the Cocomo method.

      This method determines the next lot size by adding the latest lot size to the previous lot size.

      For example, if you have one buy position with a lot size of 0.01, pre_buy_lot would be 0.00 and current_buy_lot would be 0.01, so nanpin_lot would be 0.01.

      The logic for the Cocomo method is as follows:

      • If pre_buy_lot is 0.01 and current_buy_lot is 0.01, then nanpin_lot is 0.02.
      • If pre_buy_lot is 0.01 and current_buy_lot is 0.02, then nanpin_lot is 0.03.
      • If pre_buy_lot is 0.02 and current_buy_lot is 0.03, then nanpin_lot is 0.05.

        And so on.

        After the addition

        The updated code with the added features is as follows:

        if(buy_position>0) //If holding one or more buy positions
             {
              OrderSelect(current_buy_position,SELECT_BY_POS); //Select the latest buy position
              if(Ask<(OrderOpenPrice()-nanpin_range*Point)) //Check if the current price has reached the Martingale range   
                {
                 //Lot size selection
                 if(lot_type==1){nanpin_lot = round(OrderLots()*1.5*100)/100;} //Martingale multiplier: 1.5x
                 if(lot_type==2){nanpin_lot = round(OrderLots()*2*100)/100;} //Martingale multiplier: 2x
                 if(lot_type==3){nanpin_lot = pre_buy_lot+current_buy_lot;} //Cocomo method
                 ticket_number=OrderSend(
                                  Symbol(), //Currency pair
                                  OP_BUY,  //Buy:OP_BUY, Sell:OP_SELL
                                  nanpin_lot, //Lot size
                                  Ask, //Order price
                                  slippage, //Slippage
                                  0,  //Stop-loss
                                  0,  //Take-profit
                                  "nanpin_buy",  //Order comment
                                  magic_number,  //Magic number
                                  0,  //Order expiration time
                                  Blue  //Arrow color
                               );
                }
             }
        if(sell_position>0) //If holding one or more sell positions
             {
              OrderSelect(current_sell_position,SELECT_BY_POS); //Select the latest sell position
              if(Bid>(OrderOpenPrice()+nanpin_range*Point)) //Check if the current price has reached the Martingale range
                {
                 //Lot size selection
                 if(lot_type==1){nanpin_lot = round(OrderLots()*1.5*100)/100;} //Martingale multiplier: 1.5x
                 if(lot_type==2){nanpin_lot = round(OrderLots()*2*100)/100;} //Martingale multiplier: 2x
                 if(lot_type==3){nanpin_lot = pre_sell_lot+current_sell_lot;} //Cocomo method
                 ticket_number=OrderSend(
                                  Symbol(), //Currency pair
                                  OP_SELL, //Buy:OP_BUY, Sell:OP_SELL
                                  nanpin_lot, //Lot size
                                  Bid, //Order price
                                  slippage, //Slippage
                                  0, //Stop-loss
                                  0, //Take-profit
                                  "nanpin_sell", //Order comment
                                  magic_number, //Magic number
                                  0, //Order expiration time
                                  Red //Arrow color
                               );
                }
        
             }

        Conclusion

        That concludes the addition of the functionality to modify the lot size for the martingale strategy.

        Other Articles on Creating EAs

        Adding Trading Time Limits and Forced Closure Functionality

        Adding the ability to change take profit patterns

        Creating an FX Automated Trading Tool (Bot) in Python

        Here, we will introduce how to create an FX automated trading tool (bot) using Python.

        Comments

        Copied title and URL