Using a PNN (Probabilistic Neural Network) and MetaTrader 4 (MQL4) to trade Forex


In this tutorial, I am going to implement a PNN (Probabilistic neural network) in MQL4, the MetaTrader 4 language.

The PNN will be implemented in a library, that will be used from expert advisors, for training, and for trading.

In order to optimize the PNN performance,  I am going to store the trained vectors and its associated classes (the class where the vector is classified in) in a simple array.

To simplify the PNN, the classes will be numbered from 0 to n.

The PNN implementation will have the following public functions:

  • void PNNInit(): This method will be used to reset the internal layer (remove neurons).
  • void PNNAddVector(int class, double vector[]): This method will add the vector to the internal layer and classify it in the specified class.
  • int PNNClassifyVector(double vector[]): This method will classify the specified vector and return the class.
  • void PNNSave(): This method stores the PNN status (its neurons and classes) in a file named “pnn.dat”.
  • void PNNLoad(): This method loads the PNN status from a file named “pnn.dat”.

This library must be saved in “…/experts/libraries” in the MetaTrader 4 folder.

And here is the code (the code itself is documented to explain its functionality):

//+----------------------------------------------------------+
//| A probabilistic neural network (PNN) implementation      |
//|                                                          |
//|                                                  PNN.mq4 |
//|                                     Paco Hernández Gómez |
//|                            http://www.hernandezgomez.com |
//+———————————————————-+
#property copyright “Paco Hernández Gómez”
#property link      “http://www.hernandezgomez.com”
#property library
double SIGMA = 0.1;
/**
 * Probabilistic neural network data is stored in an array
 * composed by the training vectors and its classified
 * classes.
 *
 * To optimize speed, the possible classes are numbered from
 * 0 to n, and are store in the first position of each
 * trained vector.
 *
 * pnn[x][0] = Class where the training vector is classified
 * (There are two possible classes (0 - Buy, 1 - Sell)).
 *
 * pnn[x][1..n] = Training vector components classified in
 * class pnn[x][0].
 *
 * In this example, training vectors are going to have 60
 * different components.
 */  
double pnn[0][61];
/**
 * Initialize PNN Vectors with 0 traning vectors.
 */
void PNNInit() {
   ArrayResize(pnn, 0);
}
/**
 * Add a training vector to the trained vectors set and
 * classify it to a class.
 */
void PNNAddVector(int class, double vector[]) {
   // Create a new position in the array to store the
   // new training vector and its associated class.
   int length = ArrayRange(pnn, 0);
   ArrayResize(pnn, length + 1);
  
   // Store the new training vector class
   pnn[length][0] = class;
   // Store the new training vector
   for (int i = 0; i < ArrayRange(vector, 0); i++) {
      pnn[length][i + 1] = vector[i];
   }
}
/**
 * Calculate two vectors's scalar product, needed in order to
 * classify the vector.
 */
double euclideanScalarProduct(double p[], double q[]) {
 double euclideanScalarProduct = 0;
 
   int length = ArrayRange(p, 0);
 
 for (int i = 0; i < length; i++) {
  euclideanScalarProduct += MathPow(p[i] - q[i], 2);
 }
 return (euclideanScalarProduct);
}
/**
 * Classify a vector in one class.
 */
int PNNClassifyVector(double vector[]) {
   double length = ArrayRange(vector, 0);
 double result = -99999999999999999999;
 int resultClass = -1;
   double fx[2] = {0, 0};
   double classVectorCount[2] = {0, 0};
   for (int i = 0; i < ArrayRange(pnn, 0); i++) {
 
      int class = pnn[i][0];
      double classVector[60];
      for (int j = 0; j < length; j++) {
         classVector[j] = pnn[i][j + 1];
      }
      classVectorCount[class]++;
 
      fx[class] += MathExp((-1)
         * euclideanScalarProduct(vector,
            classVector) / (2 * MathPow(SIGMA, 2)));
   }
   for (i = 0; i < ArrayRange(fx, 0); i++) {
      fx[i] *= 1 / (MathPow(2 * 3.14159265, length / 2)
         * MathPow(SIGMA, length))
         * (1 / classVectorCount[i]);
      if (fx[i] > result) {
         result = fx[i];
         resultClass = i;
      }
   }
 return (resultClass);
}
/**
 * Store the trained PNN in a file
 */
void PNNSave() {
   int handle;
  
   handle = FileOpen("pnn.dat", FILE_WRITE | FILE_BIN);
   int vectorSize = ArrayRange(pnn, 1);
   for (int i = 0; i < ArraySize(pnn); i++) {
      FileWriteDouble(handle,
         pnn[i / vectorSize][i % vectorSize]);
   }
  
   FileClose(handle);
}
/**
 * Load a trained PNN from a file
 */
void PNNLoad() {
   int handle;
  
   handle = FileOpen("pnn.dat", FILE_READ | FILE_BIN);
   int fileSize = FileSize(handle);
   ArrayResize(pnn, fileSize / (61 * 8));
   int vectorSize = ArrayRange(pnn, 1);
   for (int i = 0; i < fileSize; i++) {
      pnn[i / vectorSize][i % vectorSize] =
         FileReadDouble(handle);
   }
  
   FileClose(handle);
}

PNN.mq4  

Once we have our PNN implementation, we are going to write a trainer expert advisor.

The trainer will calculate the input vector using a trading system based on different indicators (you may try different alternatives) for each training period (in this example for each minute).

Then, when the input vector is calculated, the trainer will open a buy position and a sell position for the calculated vector.

Once the positions are opened, one position will success (in the example will finish with the take profits), and the other will fail (in the example will finish with the stop loss). The trainer will store the winning position in the PNN internal layer classified as a class 0 (Buying position) or as a class 1 (Selling position).

Finally, the trainer will save the PNN internal state in a file in order to be used in the future by the trading expert advisor. 

And here is the code (the code itself is documented to explain its functionality): 

//+----------------------------------------------------------+
//| Example training expert advisor                          |
//|                                          PNN Trainer.mq4 |
//|                                     Paco Hernández Gómez |
//|                            http://www.hernandezgomez.com |
//+———————————————————-+
#property copyright “Paco Hernández Gómez”
#property link      “http://www.hernandezgomez.com
// Import PNN library
#import "PNN.ex4"
   void PNNInit();
   void PNNLoad();
   void PNNSave();
   void PNNAddVector(int class, double vector[]);
   int PNNClassifyVector(double vector[]);
#import
/**
 * In this system there is always an open position,
 * either buy or sell.
 */
 
/**
 * Take profits at 18 pips.
 */
extern int LIMIT = 18;
/**
 * Take loses at 54 pips.
 */
extern int STOP_LOSS = 54;
/**
 * Use an array to store the opened positions that are going
 * to be used to train the PNN
 */
double data[0][63];
/**
 * Initialize the PNN
 */
int init() {
   PNNInit();
   ArrayResize(data, 0);
   return(0);
}
/**
 * Train the PNN
 */
int start() {
  
   int length = ArrayRange(data, 0);
   /**
    * In each new period, add two new vectors to the training
    * set (two new positions, one for buying and one for
    * selling.
    */
   ArrayResize(data, length + 2);  
   /**
    * Build the two new vectors with the information of the
    * trading system.
    * In this example, we are going to use last 60 periods
    * (15 minutes) close price difference with prior period
    */
   for (int i = 0; i < 60; i++) {
      data[length][i] = (iClose(Symbol(), PERIOD_M15, i)
         - iClose(Symbol(), PERIOD_M15, i + 1)) / Point;
      data[length + 1][i] = data[length][i];
   }
   /**
    * Add a buying positions (0)
    */
   data[length][60] = 0; // Compra
  
   data[length][61] = Ask; // Open position with Ask price
  
   data[length][62] = 0; // 0 indicates position is opened,
                         // 1 indicates position is closed
  
   /**
    * Add a selling position (1)
    */
   data[length + 1][60] = 1; // Venta
   data[length + 1][61] = Bid; // Open position with Bid price
   data[length + 1][62] = 0; // 0 indicates position is opened,
                             // 1 indicates position is closed
   /**
    * Iterate for all opened positions to see if they are
    * winning positions or losing positions
    */
   for (i = 0; i < length; i++) {
     
      // If position is opened
      if (data[i][62] == 0) {
        
         double vector[60];
              
         // If position is a buying position
         if (data[i][60] == 0) {
            // If position is a winner position
            if ((Bid - data[i][61]) / Point >= LIMIT) {
              
               for (int j = 0; j < 60; j++) {
                  vector[j] = data[i][j];
               }
               // Add position to the PNN training vectors set
               // and classify it as a buying position
               PNNAddVector(0, vector);
               // Mark the position as closed position
               data[i][62] = 1;
            }
            // If position is a loser position
            else if ((data[i][61] - Bid) / Point
                        >= STOP_LOSS) {
               // Discard position and mark as closed
               data[i][62] = 1;
            }
         }
        
         // If position is a selling position
         else if (data[i][60] == 1) {
        
            // If position is a winner position
            if ((data[i][61] - Ask) / Point >= LIMIT) {
              
               for (j = 0; j < 60; j++) {
                  vector[j] = data[i][j];
               }
               // Add position to the PNN training vectors
               // set and classify it as a selling position
               PNNAddVector(1, vector);
               // Mark the position as closed position
               data[i][62] = 1;
            }
            // If position is a loser position
            else if ((Ask - data[i][61]) / Point
                        >= STOP_LOSS) {
               // Discard position and mark as closed
               data[i][62] = 1;
            }
         }
      }
   }
   return(0);
}
/**
 * Store the trained PNN in a file
 */
int deinit() {
   PNNSave();
}

PNN Trainer.mq4 

Once we have our trainer, we are going to execute it using the MetaTrader 4 tester.

Using MetaTrader 4 tester to train the PNN

Now, we have trained our PNN using a example system based on last 60 periods close prices differences.

Let’s code the trading system expert advisor using PNN to decide if we open buy positions or sell positions.

For each period, the expert advisor calculates the input vector and ask the PNN to classify it. Depending on the result, the expert advisor will open a buy position or a sell position.

Let’s see the code: 

//+----------------------------------------------------------+
//| Example system using probabilistic neural network (PNN)  |
//|                                                          |
//|                                         PNN System 1.mq4 |
//|                                     Paco Hernández Gómez |
//|                            http://www.hernandezgomez.com |
//+———————————————————-+
#property copyright “Paco Hernández Gómez”
#property link      “http://www.hernandezgomez.com
// Import PNN library
#import "PNN.ex4"
   void PNNInit();
   void PNNLoad();
   void PNNSave();
   void PNNAddVector(int class, double vector[]);
   int PNNClassifyVector(double vector[]);
#import
/**
 * In this system there is always an open position,
 * either buy or sell.
 */
 
/**
 * Take profits at 18 pips.
 */
extern int LIMIT = 18;
/**
 * Take loses at 54 pips.
 */
extern int STOP_LOSS = 54;
/**
 * Load the trained PNN
 */
int init() {
   PNNLoad();
   return(0);
}
/**
 * Operate the system using the PNN
 */
int start() {
  
   int total;
   total = OrdersTotal();
   // If there is not an opened position
   if (total == 0) {
      double data[60];
      // Calculate the vector to classify using the trading
      // system criteria
      for (int i = 0; i < 60; i++) {
         data[i] = (iClose(Symbol(), PERIOD_M15, i)
            - iClose(Symbol(), PERIOD_M15, i + 1)) / Point;
      }
      // Use the PNN to classify the vector
      int class = PNNClassifyVector(data);
     
      // If PNN classifies the vector as a buying position
      if (class == 0) {
         // Open a new buying position
         OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3,
            Ask - STOP_LOSS * Point, Ask + LIMIT * Point,
            NULL, 16384, 0, Green);
      }
      // If PNN classifies the vector as a selling position
      else if (class == 1) {
         // Open a new selling position
         OrderSend(Symbol(), OP_SELL, 0.1, Bid, 3,
            Bid + STOP_LOSS * Point, Bid - LIMIT * Point,
            NULL, 16384, 0, Red);
      }
   }
   return(0);
}

PNN System 1.mq4

Now, we can test our expert advisor using the MetaTrader 4 tester.

Using MetaTrader 4 to test our based PNN expert advisor

As you can see, the expert advisor is collecting 2,350 pips in one week for the trained period!!

2,350 pips in the trained period!!

But this only demonstrates the big potential that the Forex market has. Wow.

Here is the complete report using 0.1 lots positions without any money management strategy.

Full report for the trained period

As you can see, using the PNN, it is possible to win more than 90% of the positions during the trained period.

This indicates that the PNN has learned the trained period, but depending on the real edge of the system you select (and the correlation between the past and the future for this system), the system will work in other periods or not.

In this tutorial, we have learnt how to code a PNN in MQL4 and how to train, and use it to trade.

That’s all folks. ;-)
 

Trading foreign exchange on margin carries a high level of risk, and may not be suitable for all investors. The high degree of leverage can work against you as well as for you. Before deciding to trade foreign exchange you should carefully consider your investment objectives, level of experience, and risk appetite.

Any opinions, news, research, analyses, prices, or other information contained on this website is provided as general market commentary, and does not constitute investment advice. Paco Hernández Gómez will not accept liability for any loss or damage, including without limitation to, any loss of profit, which may arise directly or indirectly from use of or reliance on such information.

Previous Articles

Implementing a PNN (Probabilistic Neural Network) in Java


Calling Java methods from Flex using mx:RemoteObject and Red5


The simplest profitable Foreign Exchange market system ;-)


Welcome to Paco Hernández Gómez's site

Thank you for taking the time to visit my site! Take a second to peek around and check out some of my previous posts. Of course, I would love to find out what you think as well, so make sure to comment. See you around!

www.alpari-forex.com

Archives

View Paco Hernández Gómez's profile on LinkedIn
Add to Technorati Favorites


Watch the latest videos on YouTube.com