Learn Touch Typing

Genetic Algorithm in FOREX Trading Systems

Using Genetic Algorithm to create profitable FOREX Trading Strategy. Genetic Algorithm in Cortex Neural Networks Software Feedforward Backpropagation Neural Network Application for genetic computations based Forex trading.

This example uses the Cortex Neural Networks Software built-in scripting language, so please read the Scripting language guide first.

This example uses concepts and ideas of the previous article, so please read Neural Network Genetic Algorithm in FOREX Trading Systems first, though it is not mandatory.

About this text

First of all, please read the disclaimer. This is an example of using Cortex Neural Networks Software genetic algorithm functionality, not an example of how to do profitable trading. I am not your guru, neither should I be responsible for your losses.

Cortex Neural Networks Software has neural networks in it, and FFBP we discussed before is only one way of choosing a forex trading strategies. It is a good technique, powerful and when applied properly, very promicing. However, it has a problem - to teach tne Neural Network, we need to know the "desired output".

It is rather easy to do when we do function approximation, we just take the "real" value of a function, because we know what it should be.

When we do neural network forecasting, we use the technique (described in previous articles) of teaching the Neural Network on the history, again, if we predict, say, an exchange rate, we know (during the training) what the correct prediction is.

However, when we are building a trading system, we have no idea what the correct trading decision is, even if we know the exchange rate! As the matter of fact, we have many forex trading strategies we can use at any point of time, and we need to find a good one - how? What should we feed as the desired output of our Neural Net?

If you followed our previous article, you know, that we have cheated to deal with this problem. We teached the Neural Network to do exchange rate (or exchange rate based indicator) prediction, and then used this prediction to do trading. Then, outside the Neural Network part of the program, we made a decision on which Neural Network is the best one.

Genetic algorithms can deal with this problem directly, they CAN solve the problem stated as "find the best trading signals".

In this article we are going to use Cortex Neural Networks Software to create such a program.

Using Genetic Algorithm

Genetic Algorithms are very well developed, and very diverse. If you want to learn all about them, I suggest you use Wikipedia, as this article is only about what Cortex Neural Networks Software can do.

Having Cortex Neural Networks Software, we can create an Neural Network that takes some input, say, values of an indicator, and produces some output, say, trading signals (buy, sell, hold...) and stop loss / take profit levels for positions to be opened.

Of course, if we seed this Neural Network's weights at random, trading results will be terrible. However, let's say we created a dozen of such NNs. Then we can test performance of each of them, and choose the best one, the winner.

This was the "first generation" of NNs. To continue to the second generation, we need to allow our winner to "procreate", but to avoid getting identical copies, let's add some random noice to it's descentants' weights.

In the second generation, we have our first-generation winner and it's imperfect (mutated) copies. Let's do testing again. We will have another winner, which is BETTER then any other Neural Network in the generation.

And so on. We simply allow winners to breed, and eliminate losers, just like in real life evolution, and we will get our best-trading Neural Network, without any prior knowlege on what the trading system (genetic algorithm) should be like.

Neural Network Genetic Algorithm: Example 0

This is the first genetic algorithm example, and a very simple one. We are going to walk through it step by step, to learn all tricks that following examples will use.


The code has inline comments, so let's just focus on key moments.

PRINT("%s\r\n", "Creating initial population");

strNnFileName = strNnPath + strForexName + "_evolution_0.nn";
NewNn(arrNocLags, nNeurons);

arrNetworks[0] = OPEN_NN(strNnFileName, bIsPathRelative);

for(double nNnIdx = 1; nNnIdx < nPopulationSize; nNnIdx = nNnIdx + 1)
    arrNetworks[nNnIdx] = MUTATION_NN(arrNetworks[nNnIdx - 1], 1, 0.1);

First, we have created a neural network. It is using random weights, and was not yet teached.

Then, in cycle, we make 14 copies of it, using MUTATION_NN fumction. This function makes a copy of a source Neural Network, adding random values from 0 to (in our case) 0.1 to all weights.

We keep handles to resulting 15 NNs in an array, we can do it, as handle is just an integer number.

The reason we use 15 NNs has nothing to do with trading: Cortex Neural Networks Software can plot up to 15 lines on a chart simultaneously.

double nLearn = 12000;
for(double nGeneration = 1; nGeneration < 100000; 
    nGeneration = nGeneration + 1)
    double nStart = nRemoveFirst + 
        RAND(nExtractRecords - nLearn - nRemoveFirst);
    dMaxDrawDown = Test(nStart, nStart + nLearn);

We can use different approaches to the testing. First, we can use the learning set, all of it at once. Second, we can test on, say, 12000 resords (out of 100000), and walk through the learning set, from beginning to the end. That will make learnigs different, as we will look for Neural Network's that are profitable on any given part of data, not just on the entire set. The second approach can give us problems, if data change, from the beginning to the end. Then the network will evolve, obtaining ability to trade at the end of data set, and losing ability to trade at its beginning.

To solve that problem, we are going to take random 12000 records fragments from data, and feed it to the Neural Network.


for(double nGeneration = 1; nGeneration < 100000; 
    nGeneration = nGeneration + 1)

is simply a endless cycle, as 100000 cycles will never be reached at our speed.

Below we add one child for each network, with slightly different weights. Note, that 0.1 for mutation tange is not the only choice, as the matter of fact, even this parameter can be optimized using genetic algorithm.

for(nNnIdx = nPopulationSize; 
    nNnIdx < 2 * nPopulationSize; nNnIdx = nNnIdx + 1)	
    arrNetworks[nNnIdx] = MUTATION_NN(
        arrNetworks[nNnIdx - nPopulationSize], 1, 0.1);

Newly created NNs are added after 15 existing ones. This way we have 30 NNs in an array, 15 old and 15 new. Then we are going to do the next cycle of testing, and to kill losers, from both generations.

To do testing, we apply Neural Network to our data, to produce outputs, and then call Test function, that uses these outputs to simulate trading. Results of trading are used to deside, which NNs are best.

Note the code:

double nStart = nRemoveFirst + 
    RAND(nExtractRecords - nLearn - nRemoveFirst);

dMaxDrawDown = Test(nStart, nStart + nLearn);

We use an interval of nLearn records, from nStart to nStart + nLearn, where nStart is a random point within learning set.

The code below is a trick. The reason we use it is to illustrate the fact, that genetic algorithm can create genetic algorithm, but it will not necessarily will be the best one, and also, to suggest, that we can improve result, if we imply some limitations to the learning process.

It is possible, that our trading system works very well on long trades, and very poor on short, or vice versa. If, say, long trades are VERY good, this genetic algorithm may win, even with large losses on short trades.

To avoid it, we assign more weight to long trades in odd and to short trades in even cycles. This is just an example, there is no guarantee, that it will improve something. More about it below, in discussion about corrections. Technically, you don't have to do it, or can make it differently.

double dBalance;
if(nGeneration % 2 == 0)
    dBalance = arrBalanceBuy[ARRAY_SIZE(arrBalanceBuy) - 1] +
        0.6 * arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1];
    dBalance = arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1] + 
        0.6 * arrBalanceBuy[ARRAY_SIZE(arrBalanceBuy) - 1];

Add profit to a sorted array. It returns an insertion position, then we use this position to add Neural Network handle, learning and testing profits to non-sorted arrays. Now we have data for current Neural Network at the same array index as its profit.

The idea is to arrive to array of NNs, sorted by profitability. As array is sortes by profit, to remove 1/2 of networks, that are less profitable, we just need to remove NNs 0 to 14

double nPos;
for(nNnIdx = 0; nNnIdx < 2 * nPopulationSize; 
    nNnIdx = nNnIdx + 1)
    nPos = ARRAY_ADD(arrProfits, 
        arrProfitsTmp[nNnIdx] * arrCorrections[nNnIdx]);
    ARRAY_INSERT(arrNetworks, arrNetworksTmp[nNnIdx], nPos); 
        arrLearnProfitsTmp[nNnIdx], nPos);
    ARRAY_INSERT(arrTestProfits, arrTestProfitsTmp[nNnIdx], nPos);

for(nNnIdx = nPopulationSize - 1; nNnIdx >= 0; nNnIdx = nNnIdx - 1)
    ARRAY_REMOVE(arrNetworks, nNnIdx);

Trading decisions are based on value of Neural Network signal, from this point of view the program is identical to examples from previous article.

FOREX Trading Strategy: Discussing example 0

First of all, let's take a look at charts. The first chart for profit during the first iteration is not good at all, as should be expected, the Neural Network loses money (image evolution_00_gen_0.png copied after first iteration from "images" folder):

The image for profit on cycle 15 is better, sometimes, genetic algorithm can learn really fast:

However, notice the saturation on a profit curve.

It is interesting also to look at the way individual profits change, keeping in mind, that curve number, say, 3 is not always for the same Neural Network, as they are being born and terminated all the time:

Also note, that out little forex automated trading system performs poor on short trades, and much better on longs, which may or may not be related to the fact, that dollar was falling compared to euro during that period. It also may have something to do with parameters of our indicator (maybe, we need different period for shorts) or the choice of indicators.

Here is the history after 92 and 248 cycles:

To our surprise, genetic algorithm failed completely. Let's try to figure out why, and how to help the situation.

First of all, isn't each generation supposed to be better than the previuos one? The answer is no, at least not within the model we used. If we took ENTIRE learning set at once, and used it repeatedly to teach our NNs, then yes, they will improve on each generation. But instead, we took random fragments (12000 records in time), and used them.

Two questions: why the system failed on random fragments of learning set, and why haven't we used entire learning set? Well... To answer the second question, I did. NNs performed greatly - on learning set. And they failed on testing set, for same reason it failes when we used FFPB learning. To put it differently, our NNs got overspecialized, they learned how to survive in the environment they are used to, but not outside it. This happens a lot in nature.

The approach we took instead was intended to compensate for that, by forcing NNs to perform good on any random fragment of the dataset, so that hopefully, they could also perform on an unfamiliar testing set. Instead, they failed both on testing and on learning set.

Imagine animals, living in a desert. A lot of sun, no snow at all. This is a metafor for rizing market, as for our NNs data play the role of environment. Animals learned to live in a desert.

Imagine animals, that live in a cold climate. Snow and no sun at all. Well, they adjusted.

However, in our experiment, we randomly placed our NNs in a desert, in snow, in the water, on the trees... by presenting them with different fragments of data (randomly rising, falling, flat...). Animals died.

Or, to put it differently, we selected the best Neural Network for random data set 1, which, say, was for rising market. Then we presented, to the winners and their children, a falling market's data. NNs performed poorly, we took best of poor performers, perhaps, one of the mutant children, that lost ability to trade on rising market, but got some ability to deal with falling one.

Then we turned the table again, and again, we got best performer - but best among poor performers. We simply didn't give our NNs any chances to become universal.

There are techniques allowing genetic algorithm to learn new information without loosing performance on old information (after all, animals can live in summer and in winter, right? So evolution IS able to handle repeating changes). We may discuss these techniques later, though this article is more about using Cortex Neural Networks Software, than about building a successfull forex automated trading system.

Neural Network Genetic Algorithm: Example 1

Now it is time to talk about corrections. A simple genetic algorithm we created during the previous step has two major flaws. First, it failed to trade with profit. It is ok, we can try to use partially trained system (it was profitable at the beginning). The second flaw is more serious: we have no control over things, that this system does. For example, it may learn to be profitable, but with huge drawdowns.

It is a well known fact, that in real life, evolution can optimize more than one parameter simultaneously. For example, we can get an animal, that can run fast AND be resistant to cold. Why not to try doing the same in our forex automated trading system?

That's when we use corrections, which are nothing but the set of additional punishments. Say, our system trades with drawdown 0.5, while we want to confirm it to 0 - 0.3 interval. To "tell" the system that it made a mistake, we decrease its profit (one used to determine, which genetic algorithm won) to the degree, that is proportional to the size of DD. Then, the evolution algorithm takes care of the rest.

There are few more factors, that we want to take into consideration: we may want to have more or less equal number of buy and sell operations, we want to have more of profitable operations, then of failures, we may want the profit chart to be linear and so on.

In evolution_01.tsc we implement a simple set of corrections. First of all, we use some large number for an initial correction value. We multiply it to a small (usually, between 0 and 1) values, depending on the "punishment" we want to apply. Then we multiply our profit to this correction. As the result, profit is corrected, to reflect how much the genetic algorithm corresponds to our other criteria. Then we use the result to find a winner Neural Network.

// Initial large value, that we are going to decrease 
// with each punishment
double dCorrection = 10000000;

// If there are trades, else (see below) set correction to
// some really small value
if(nTradeNumberBuy != 0 && nTradeNumberSell != 0 && 
    arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1] != 0 &&
    arrBalanceBuy[ARRAY_SIZE(arrBalanceSell) - 1] != 0)
    // We want NN to give output in 0-1 range, so punish it,
    // if the output is in 0.00001 - 0.00002 range
    dCorrection = dCorrection * (dAdviceMax - dAdviceMin);
    // We want long and short operations to be roughly
    // equally profitable, no more, than 3 times different
    if(ABS(arrBalanceBuy[ARRAY_SIZE(arrBalanceBuy) - 1]) / 
        ABS(arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1]) > 3 ||
        ABS(arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1]) / 
        ABS(arrBalanceBuy[ARRAY_SIZE(arrBalanceBuy) - 1]) > 3)
        dCorrection = dCorrection * 0.1;

	// We want positive profit							
    if(arrBalanceBuy[ARRAY_SIZE(arrBalanceBuy) - 1] < 0 
        || arrBalanceSell[ARRAY_SIZE(arrBalanceSell) - 1] < 0)
        dCorrection = dCorrection * 0.1;
    // We want drawdown below 0.5, also, if between 
    // 0.5 and 0.3, the punishment should linearly fall
    // - we punish more, when approaching 0.5, and less
    // when approaching 0.3
    if(dMaxDrawDown > 0.5)
        dCorrection = dCorrection * 0.1;
        if(dMaxDrawDown >= 0.3)
            dCorrection = dCorrection * (2.35 - 4.5 * dMaxDrawDown);
    // NN can produce erradic values for stops. In Test function,
    // we have a simple test logic, that, if value is out of range,
    // confines it to range's high or low ends. In the same time, 
    // nCorrectStops counter is used, to count wrong stops, here
    // we use it to punish the NN
    if(nCorrectStops != 0)
        dCorrection = dCorrection * nCorrectStops 
            / (nCorrectStops + nIncorrectStops);
        dCorrection = dCorrection 
            / (nCorrectStops + nIncorrectStops);

    // We want number of trades to be above 30. We punish
    // differently, if it is very small (<10), small (<20)
    // and not large enough (20 < n < 30) 
    if(nTradeNumberSell < 10)
        dCorrection = dCorrection * (nTradeNumberSell * 0.1 + 0.000001);
    if(nTradeNumberBuy < 10)
        dCorrection = dCorrection * (nTradeNumberBuy * 0.1 + 0.000001);
    if(nTradeNumber < 30)
        dCorrection = dCorrection * (nTradeNumber * 0.033 + 0.000001);
	// Make sure correction is positive
    dCorrection = ABS(dCorrection * dSuccessRatio);
else	// No trades, nothing to process, so punish as much as we can
    dCorrection = 0.00000001;

FOREX Trading Strategy: Discussing example 1

Example 1 works much better, than example 0. During first 100 cycles, it learned a lot, and profit charts look reassuring. However, as in example 0, long trades are much more profitable, which most likely means that there is a problem in our approach. Nevertheless, the system found a balance between couple of contradictory initial conditions:

There is some positive dynamics both in learning set and, more important, in testing set.



As for further learning, at cycle 278 we can see, that our system got overtrained. It means, we still have progress on learning set:

But testing set shows weakness:

This is a common problem with NNs: when we teach it on learning set, it learns to deal with it, and sometimes, it learns too well - to the degree, when it looses performance on testing set.

To deal with that problem, a "traditional" solution is used: we keep looking for the Neural Network, that performs best on testing set, and save it, overwriting previous best one, every time new peak is reached. This is the same approach, we used in FFBP training, except, this time we have to do it ourselves (adding code, that looks for a best Neural Network on a testing set, and calling SAVE_NN, or exporting weights of Neural Network to a file). This way, when you stop your training, you'll have the best performer ON TESTING SET saved and waiting for you.

Note also, that it is not the max. profit you are after, but optimal performance, so consider using corrections, when looking for a best performer on a testing set.

Genetic Algorithm for FOREX Technical Analysis: Where now?

After you got your winner Neural Network, you can follow the steps, described in previous article, to export weights of that Neural Network, and then to use them in your real time trading platform, like Meta Trader, Trade Station and so on.

Alternatively, you can focus on other ways of optimizing the Neural Network, unlike with FFBP algorithm, here you can get avay from using learning and testing sets, and move sequential learning.

(C), all rights reserved

Please read the disclaimer