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);
}
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();
}
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); }
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
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!



