MQL4 - automated forex trading   /  

Articles

Login | Register | Language: ru cn en
MetaTrader Market: we have 650 Expert Advisors for algorithmic trading!

Articles  Examples  FANN2MQL Neural Network Tutorial To post a new article, please log in or register


Automated trading in
and Trade on the Go!
and Trade on the Go!

This article is about
MetaTrader 4
Download MT 4 - 455 Kb

and Trade on the Go!

and Trade on the Go!

FANN2MQL Neural Network Tutorial [ ru ]

First of all:

Please install the fann2MQL Library. it is required to test this example. It can be dowloaded here.

Introduction

Until now, there was only one example of how to use the Fann2MQL Library, which allow traders to use the Open-Source Neural Network Library "FANN" in their MQL codes.

But the example, written by the creator of the Fann2MQL Library, is not easy to understand. It's not made for beginners.

So I have written another example, way easier in its concept, and fully commented.

Iit is not related to trading directly, and is not using any financial data. It is a simple static example of application.

In this example, we are gonna teach a simple neural network to recognize a simple pattern:

The pattern we will teach if composed of 3 numbers: a, b and c.

if a < b && b < c then expected output = 1
if a < b && b > c then expected output = 0
if a > b && b > c then expected output = 0
if a > b && b < c then expected output = 1

You can think of those numbers as being vector coordinates for example (vector going up or down) or market direction. In which case, the pattern could be interpreted as:

UP UP = UP

UP DOWN = DOWN

DOWN DOWN = DOWN

DOWN UP = UP


First, we will create a neural network.

Then we are going to show the network some examples of patterns, so it can learn and deduce the rules.

Finally, we are going to show the network new patterns it has never seen, and ask him what are his conclusions. If he understood the rules, then he will be able to recognize those patterns.

the commented code:

// We include the Fann2MQl library
#include <Fann2MQL.mqh>

#property copyright "Copyright © 2009, Julien Loutre"
#property link      "http://www.thetradingtheory.com"

#property  indicator_separate_window
#property  indicator_buffers 0

// the total number of layers. here, there is one input layer,
// 2 hidden layers, and one output layer = 4 layers.
int nn_layer = 4;
int nn_input = 3; // Number of input neurones. Our pattern is made of 3 numbers, 
                  // so that means 3 input neurones.
int nn_hidden1 = 8; // Number of neurones on the first hidden layer
int nn_hidden2 = 5; // number on the second hidden layer
int nn_output = 1; // number of outputs

// trainingData[][] will contain the examples 
// we're gonna use to teach the rules to the neurones.
double      trainingData[][4];  // IMPORTANT! size = nn_input + nn_output


int maxTraining = 500;  // maximum number of time we will train 
                        // the neurones with some examples
double targetMSE = 0.002; // the Mean-Square Error of the neurones we should 
                          // get at most (you will understand this lower in the code)

int ann; // This var will be the identifier of the neuronal network.

// When the indicator is removed, we delete all of the neurnal networks 
// from the memory of the computer.
int deinit() {
   f2M_destroy_all_anns();
   return(0);
}

int init() {
   int i;
   double MSE;
   
   Print("=================================== START EXECUTION ================================");
   
   IndicatorBuffers(0);
   IndicatorDigits(6);
   
   // We resize the trainingData array, so we can use it.
   // We're gonna change its size one size at a time.
   ArrayResize(trainingData,1);
   
   Print("##### INIT #####");
   
   // We create a new neuronal networks
   ann = f2M_create_standard(nn_layer, nn_input, nn_hidden1, nn_hidden2, nn_output);
   
   // we check if it was created successfully. 0 = OK, -1 = error
   debug("f2M_create_standard()",ann);
   
   // We set the activation function. Don't worry about that. Just do it.
	f2M_set_act_function_hidden (ann, FANN_SIGMOID_SYMMETRIC_STEPWISE);
	f2M_set_act_function_output (ann, FANN_SIGMOID_SYMMETRIC_STEPWISE);
	
	// Some studies show that statistically, the best results are reached using this range; 
     // but you can try to change and see is it gets better or worst
	f2M_randomize_weights (ann, -0.77, 0.77);
	
	// I just print to the console the number of input and output neurones. 
      // Just to check. Just for debug purpose.
   debug("f2M_get_num_input(ann)",f2M_get_num_input(ann));
   debug("f2M_get_num_output(ann)",f2M_get_num_output(ann));
	
   
   Print("##### REGISTER DATA #####");
   
   // Now we prepare some data examples (with expected output) 
   // and we add them to the training set.
   // Once we have add all the examples we want, we're gonna send 
   // this training data set to the neurones, so they can learn.
   // prepareData() has a few arguments:
   // - Action to do (train or compute)
   // - the data (here, 3 data per set)
   // - the last argument is the expected output.
   // Here, this function takes the example data and the expected output, 
   // and add them to the learning set.
   // Check the comment associated with this function to get more details.
   //
   // here is the pattern we're going to teach:
   // There is 3 numbers. Let's call them a, b and c.
   // You can think of those numbers as being vector coordinates 
  // for example (vector going up or down)
   // if a < b && b < c then output = 1
   // if a < b && b > c then output = 0
   // if a > b && b > c then output = 0
   // if a > b && b < c then output = 1
   
   
   // UP UP = UP / if a < b && b < c then output = 1
   prepareData("train",1,2,3,1);
   prepareData("train",8,12,20,1);
   prepareData("train",4,6,8,1);
   prepareData("train",0,5,11,1);

   // UP DOWN = DOWN / if a < b && b > c then output = 0
   prepareData("train",1,2,1,0);
   prepareData("train",8,10,7,0);
   prepareData("train",7,10,7,0);
   prepareData("train",2,3,1,0);

   // DOWN DOWN = DOWN / if a > b && b > c then output = 0
   prepareData("train",8,7,6,0);
   prepareData("train",20,10,1,0);
   prepareData("train",3,2,1,0);
   prepareData("train",9,4,3,0);
   prepareData("train",7,6,5,0);

   // DOWN UP = UP / if a > b && b < c then output = 1
   prepareData("train",5,4,5,1);
   prepareData("train",2,1,6,1);
   prepareData("train",20,12,18,1);
   prepareData("train",8,2,10,1);
   
   // Now we print the full training set to the console, to check how it looks like.
   // this is just for debug purpose.
   printDataArray();
   
   
   Print("##### TRAINING #####");
   
   // We need to train the neurones many time in order 
   // for them to be good at what we ask them to do.
   // Here I will train them with the same data (our examples) over and over again, 
   // until they fully understand the rules we are trying to teach them, or until 
   // the training has been repeated 'maxTraining' number of time  
   // (in this case maxTraining = 500)
   // The better they understand the rule, the lower their mean-Square Error will be.
   // the teach() function returns this mean-Square Error (or MSE)
   // 0.1 or lower is a sufficient number for simple rules
   // 0.02 or lower is better for complex rules like the one 
   // we are trying to teach them (it's a patttern recognition. not so easy.)
   for (i=0;i<maxTraining;i++) {
      MSE = teach(); // everytime the loop run, the teach() function is activated. 
                     // Check the comments associated to this function to understand more.
      if (MSE < targetMSE) { // if the MSE is lower than what we defined (here targetMSE = 0.02)
         debug("training finished. Trainings ",i+1); // then we print in the console 
                                                     // how many training 
                                                     // it took them to understand
         i = maxTraining; // and we go out of this loop
      }
   }
   
   // we print to the console the MSE value once the training is completed
   debug("MSE",f2M_get_MSE(ann));
   
   
   Print("##### RUNNING #####");
   // And now we can ask the neurone to analyse new data that they never saw.
   // Will they recognize the patterns correctly?
   // You can see that I used the same prepareData() function here, 
   // with the first argument set to "compute".
   // The last argument which was dedicated to the expected output 
   // when we used this function for registering examples earlier,
   // is now useless, so we leave it to zero.
   // if you prefer, you can call directly the compute() function.
   // In this case, the structure is compute(inputVector[]);
   // So instead of prepareData("compute",1,3,1,0); you would do something like:
   //    double inputVector[]; // declare a new array
   //    ArrayResize(inputVector,f2M_get_num_input(ann)); 
   // resize the array to the number of neuronal input
   //    inputVector[0] = 1; // add in the array the data
   //    inputVector[1] = 3;
   //    inputVector[2] = 1;
   //    result = compute(inputVector); // call the compute() function, with the input array.
   // the prepareData() function call the compute() function, 
   // which print the result to the console, 
   // so we can check if the neurones were right or not.
   debug("1,3,1 = UP DOWN = DOWN. Should output 0.","");
   prepareData("compute",1,3,1,0);
   
   debug("1,2,3 = UP UP = UP. Should output 1.","");
   prepareData("compute",1,2,3,0);
   
   debug("3,2,1 = DOWN DOWN = DOWN. Should output 0.","");
   prepareData("compute",3,2,1,0);
   
   debug("45,2,89 = DOWN UP = UP. Should output 1.","");
   prepareData("compute",45,2,89,0);
   
   debug("1,3,23 = UP UP = UP. Should output 1.","");
   prepareData("compute",1,3,23,0);
   
   debug("7,5,6 = DOWN UP = UP. Should output 1.","");
   prepareData("compute",7,5,6,0);
   
   debug("2,8,9 = UP UP = UP. Should output 1.","");
   prepareData("compute",2,8,9,0);
   
   Print("=================================== END EXECUTION ================================");
   return(0);
}

int start() {
   return(0);
}

/*************************
** printDataArray()
** Print the datas used for training the neurones
** This is useless. Just created for debug purpose.
*************************/
void printDataArray() {
   int i,j;
   int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1;
   string lineBuffer = "";
   for (i=0;i<bufferSize;i++) {
      for (j=0;j<(f2M_get_num_input(ann)+f2M_get_num_output(ann));j++) {
         lineBuffer = StringConcatenate(lineBuffer, trainingData[i][j], ",");
      }
      debug("DataArray["+i+"]", lineBuffer);
      lineBuffer = "";
   }
}


/*************************
** prepareData()
** Prepare the data for either training or computing.
** It takes the data, put them in an array, 
** and send them to the training or running function
** Update according to the number of input/output your code needs.
*************************/
void prepareData(string action, double a, double b, double c, double output) {
   double inputVector[];
   double outputVector[];
   // we resize the arrays to the right size
   ArrayResize(inputVector,f2M_get_num_input(ann));
   ArrayResize(outputVector,f2M_get_num_output(ann));
   
   inputVector[0] = a;
   inputVector[1] = b;
   inputVector[2] = c;
   outputVector[0] = output;
   if (action == "train") {
      addTrainingData(inputVector,outputVector);
   }
   if (action == "compute") {
      compute(inputVector);
   }
   // if you have more input than 3, just change the structure of this function.
}


/*************************
** addTrainingData()
** Add a single set of training data 
**(data example + expected output) to the global training set
*************************/
void addTrainingData(double inputArray[], double outputArray[]) {
   int j;
   int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1;
   
   //register the input data to the main array
   for (j=0;j<f2M_get_num_input(ann);j++) {
      trainingData[bufferSize][j] = inputArray[j];
   }
   for (j=0;j<f2M_get_num_output(ann);j++) {
      trainingData[bufferSize][f2M_get_num_input(ann)+j] = outputArray[j];
   }
   
   ArrayResize(trainingData,bufferSize+2);
}


/*************************
** teach()
** Get all the trainign data and use them to train the neurones one time.
** In order to properly train the neurones, you need to run ,
** this function many time until the Mean-Square Error get low enough.
*************************/
double teach() {
   int i,j;
   double MSE;
   double inputVector[];
   double outputVector[];
   ArrayResize(inputVector,f2M_get_num_input(ann));
   ArrayResize(outputVector,f2M_get_num_output(ann));
   int call;
   int bufferSize = ArraySize(trainingData)/(f2M_get_num_input(ann)+f2M_get_num_output(ann))-1;
   for (i=0;i<bufferSize;i++) {
      for (j=0;j<f2M_get_num_input(ann);j++) {
         inputVector[j] = trainingData[i][j];
      }
      outputVector[0] = trainingData[i][3];
      //f2M_train() is showing the neurones only one example at a time.
      call = f2M_train(ann, inputVector, outputVector);
   }
   // Once we have show them an example, 
   // we check if how good they are by checking their MSE. 
   // If it's low, they learn good!
   MSE = f2M_get_MSE(ann);
   return(MSE);
}


/*************************
** compute()
** Compute a set of data and returns the computed result
*************************/
double compute(double inputVector[]) {
   int j;
   int out;
   double output;
   ArrayResize(inputVector,f2M_get_num_input(ann));
   
   // We sent new data to the neurones.
   out = f2M_run(ann, inputVector);
   // and check what they say about it using f2M_get_output().
   output = f2M_get_output(ann, 0);
   debug("Computing()",MathRound(output));
   return(output);
}


/*************************
** debug()
** Print data to the console
*************************/
void debug(string a, string b) {
   Print(a+" ==> "+b);
}

The output


Output of the Neural network in the console.

Conclusion

Also you can read the article "Using Neural Networks In MetaTrader" written by Mariusz Woloszyn, author of the Fann2MQL Library.

It took me 4 days to understand how to use Fann in MetaTrader, by analyzing the little documentation that is available here and on google.

I hope this example will be useful for you, and that it will avoid you to loose too much time experimenting. More articles will follow in the next few weeks.

If you have questions please ask, and I will answer.

Attachments:
ASNN 1 learner.mq4 (11.7 Kb)
Created: 2009.11.26  Author: Julien
Warning: All rights to these materials are reserved by MetaQuotes Software Corp. Copying or reprinting of these materials in whole or in part is prohibited.
Fallacies, Part 2. Statistics Is a Pseudo-Science, or a Chronicle of Nosediving Bread And Butter
Fallacies, Part 2. Statistics Is a Pseudo-Science, or a Chronicle of Nosediving Bread And Butter

Numerous attempts to apply statistical methods to the objective reality, i.e. to financial series, crash when met with the nonstationarity of processes, "fat tails" of accompanying probability distributions, and insufficient volume of financial data. In this publication I will try to refer not to the financial series as such, but to their subjective presentation - in this case, to the way a trader tries to halter the series, i.e. to the trading system. The eduction of statistical regularities of the trading results process is a rather enthralling task. In some cases quite true conclusions about the model of this process can be made, and these can be applied to the trading system.

Fractal Analysis of Joint Currency Movements
Fractal Analysis of Joint Currency Movements

How independent are currency quotes? Are their movements coordinated or does the movement of one currency suggest nothing of the movement of another? The article describes an effort to tackle this issue using nonlinear dynamics and fractal geometry methods.

19 comments: 1 2   To add comments, please, log in or register

Hallo,

is it possible to get 2 and 3 as output for 0 and 1?

When I train it, everything seems to be OK.

But when I compute it, the output every time returns 1.

EURUSD,M15: Computing() ==> 1.00000000

EURUSD,M15: Computing() ==> 1.00000000 2011.12.08 08:34:41 ASNN 1 learner(1) EURUSD,M15: 45,2,89 = DOWN UP = UP. Should output 2. ==>

EURUSD,M15: Computing() ==> 1.00000000

EURUSD,M15: Computing() ==> 1.00000000 2011.12.08 08:34:41 ASNN 1 learner(1) EURUSD,M15: 3,2,1 = DOWN DOWN = DOWN. Should output 3. ==>


2011.12.08 08:48 Kaffeetrinker

hey, i've got a problem, when i change the number of output, it doesn't work.
Even if i change the structure of the preparData function, the output number still 1
Can someone help me please ?

2010.10.07 12:07 francos

hallo julien .

about the example :

how do you select the hidden layers = 8 and hidden layers2 = 5 ?

it is because of 2 power 3 ? this is all the data space ?

second question : do you have to write the comute() and teach() ?

do we have a standart library with template in order to use it without writing the algoritm ?

or we can choise in the library to add or inprove a template function in order to teach the system better ?

2010.10.01 17:16 gabriel3
Hello, I had 2 quick questions I was hoping you could clarify on your code. I am slightly familiar with NN. I was wondering if you could explain how you decided to use 2 hidden layers and why you chose 8 and 5 neurones for each layer. Is there a rule of thumb based on inputs/outputs you use. Also, I saw you wrote this as an indicator, could it be adapted and run as an expert and still print the same results in the print log. Thanks, Chris
2010.08.31 21:49 Freebird83

http://pixiefx.web.fc2.com/index.html

http://www.ustream.tv/channel/fx-on-com-perrier

This is a great trading system.

2010.07.20 09:34 mar5555

It's very good, thanks Julien. Btw for currency prediciton using neural network, do you have any experience what usually used as inputs and target?


2010.05.27 13:33 gsosay

Ya Julien, I haven't seen any NN implemented successfully yet.

Best Forex Robot


Forex Robot

2010.05.06 04:09 Beakon
Hi Julien,

Thanks for clearing the stuff.
My question is: has anyone seen any really working NN implementation in any trading software? My experience shows they're not better than moving average crossover....

2010.03.22 15:08 alxalx
albert wrote:

Julien, you've done a serious work. I tried to use this indicator and I stumbled over several problems. I'll be much obliged to you if make some clarifications.

After successfully installing Fann2MQL Library, I ran the indicator and it resulted in the same output as yours, from where we can deduct that for UP signal it should signal "1" and for DOWN it should signal "0". When I tried to read the Indicator Buffer through iCustom() function called from an EA it didn't read any of these choices. That was the first problem.

In my second attempt to get a feedback from the indicator or the library, I tried to call the function compute(inputVector) and receive back the result of a prediction via Global Variable like that:

void prepareData(string action, double a, double b, double c, double output) {
double inputVector[];
double outputVector[];
// we resize the arrays to the right size
ArrayResize(inputVector,f2M_get_num_input(ann));
ArrayResize(outputVector,f2M_get_num_output(ann));

inputVector[0] = a;
inputVector[1] = b;
inputVector[2] = c;
outputVector[0] = output;
if (action == "train") {
addTrainingData(inputVector,outputVector) }
if (action == "compute") {
GlobalVariableSet("Prediction",compute(inputVector));}


After that I received the result of the prediction by reading the same variable through an EA, but the result was invariably "0". So my question is how can I get a prediction result from the indicator if not from the IndicatorBuffer? Any idea will be blessed.

Thank you in advance for your attention.

Albert


This source is not meant to be used.

A neural network is only working if it has been trained. Usually, you train the network, you save the network ( f2M_save() ), then when you want to use the network with a real application, you load the network ( f2M_load() ) and send him the input data.

This example is training and using the network at once, without saving nor loading it. Also, the basic patterns I defined here are random, not related to any financial pattern.

As a result, you won't be able to use this source to predict any financial data.


If you want to use a ANN to recognize patterns you need:

1) define the patterns

2) teach the patterns

3) save the neural network

4) load the pattern on another indicator

5) send input data

6) get your prediction


What do you want to forecast? What kind of pattern?

2009.11.30 18:07 zenhop

Julien, you've done a serious work. I tried to use this indicator and I stumbled over several problems. I'll be much obliged to you if make some clarifications.

After successfully installing Fann2MQL Library, I ran the indicator and it resulted in the same output as yours, from where we can deduct that for UP signal it should signal "1" and for DOWN it should signal "0". When I tried to read the Indicator Buffer through iCustom() function called from an EA it didn't read any of these choices. That was the first problem.

In my second attempt to get a feedback from the indicator or the library, I tried to call the function compute(inputVector) and receive back the result of a prediction via Global Variable like that:

void prepareData(string action, double a, double b, double c, double output) {
double inputVector[];
double outputVector[];
// we resize the arrays to the right size
ArrayResize(inputVector,f2M_get_num_input(ann));
ArrayResize(outputVector,f2M_get_num_output(ann));

inputVector[0] = a;
inputVector[1] = b;
inputVector[2] = c;
outputVector[0] = output;
if (action == "train") {
addTrainingData(inputVector,outputVector) }
if (action == "compute") {
GlobalVariableSet("Prediction",compute(inputVector));}


After that I received the result of the prediction by reading the same variable through an EA, but the result was invariably "0". So my question is how can I get a prediction result from the indicator if not from the IndicatorBuffer? Any idea will be blessed.

Thank you in advance for your attention.

Albert

2009.11.30 16:10 albert
19 comments: 1 2