Automated forex trading – building a bot from the ground up

Before I begin, I should probably give a disclaimer:

Statistically you are likely to lose all the money that you invest in forex, stocks or shares – regardless of whether you traded manually or attempted automated trading.  Hell, even rats outperform the average human and they’re only getting better.

Introduction

This article focuses on building a (useless) automated forex trading robot that runs without any human intervention between hitting START and hitting STOP.  Non-interactive trading is especially dangerous, as a bogus assumption or even the slightest error in your design or implementation can blow up in your face.  Trading algorithms are typically used to make recommendations to human traders, rather than being let loose directly on the market – hence why they are typically known as “expert assistants” in the software that I use (MetaTrader 4).

Typical expert assistants (EAs) are intelligently designed from the beginning using elements of probability theory, machine learning, advanced mathematical transformations, game theory and various other areas of mathematics.  Rather than getting dirty with technical details, our EA will be “evolved” in steps by adding layers of simple and intuitive rules to an initial EA which I can only describe as Artificial Stupidity:

Artificial Stupidity

[plain]
/* Stupid trader */

parameters min_age, max_age

on_new_bar:
if orders_open = 0:
create new order:
buy or sell = random
close at = current time + random(min_age, max_age);
[/plain]

This trader simply creates random orders when no pending orders exist, takes a random position and then closes them a random interval later. Naively one might expect such a trader to break even in the long run, but it will actually accumulate losses due to the spread and eventually become bankrupt.

A stupid trading robot that “can’t fail” at first glance

Now we can try adding a simple rule:

[plain]
/* Slightly less stupid trader */

on_new_bar:
if orders_open = 0:
create new order:
buy or sell = random
else if current_order is in profit:
close current_order
[/plain]

This rule states that an order should be closed as soon as it becomes profitable. If we only complete orders when they become profitable then we should be guaranteed to beat the market right? To show why this doesn’t work, imagine we tweaked the algorithm a bit:

[plain]
else if current_order is in profit BY 10000000%:
close current_order
[/plain]

We now only close an order if it is in profit by a really large amount. The end result is that the EA will never close an order, so when the trading session ends then the orders will automatically be closed at whatever the prices are at that time – which will result in a loss more often than not. Hence, sometimes it is advantageous to close at a loss, rather than to wait for an order to become profitable. This is as the loss could continue to worsen while we wait for a profit that may never materialise. Of course you could play for the long-term and hold onto a lossy order for years until markets crash/boom and put you into profit, but you might as well trade manually if you want to go long-term, since you will have ample time to validate the sanity of any suggestions from the EA against press releases, news reports, signals, etc.

So, back to our original “stupid” algorithm which behaves purely randomly. What rules can we add to it which intuitively should increase the percentage of positions that it wins on?

Some almost-intelligent rules

Minimum delay before closing an order

Instantly closing an order after opening it (even theoretically before the market changes at all) will result in a loss due to the market spread (and possibly broker fees too).  Therefore, enforcing a minimum delay between opening an order and closing it should allow the market time to move enough for the spread loss to be overcome – assuming it moves in favour of our position.

This rule will not make our EA profitable but merely less terrible as it won’t be creating orders as rapidly, so will not lose so much to the spread or fees.

Maximum delay before closing an order

Keep an order open for too long and you incur swap fees.  Additionally, keeping a lossy order open in the hope that it might recover and break even / make profit is a waste of time since if you are falling victim to a trend – it may be better instead to accept defeat, close the lossy order and take an opposing position in the hope that the trend continues enough for you to beat the spread.  Setting a maximum lifetime for orders is a very crude and reckless way to avoid such a situation, and as with minimum łifetime – it will not improve profits but merely offers the possibility of reducing losses (without any guarantee).

“Break even” stop loss when profit exceeds a threshold

When the profit on an order exceeds a certain threshold, we set a stop loss at the point of breaking even – so should the market reverse direction, we avoid a loss* on this order.  By reducing losses, we increase the chance of making profit but this rule will not affect orders that never exceed the threshold – so if the threshold is too high or all of our orders die at birth, then this rule will have no effect.

Partial close when profit exceeds threshold

When the profit on an order exceeds a certain threshold, we close a fraction of the order instantly.  This threshold may be different to the one used in the “break even” rule.  While that rule attempts to reduce losses, this one tries to increase profits.  It may occasionally reduce profits during trends, by partially closing orders that are near certain to become more profitable if left open just a bit longer.  As with the previous rule, it will not have any effect unless orders do regularly exceed the set threshold.

Optimisation

“What parameters should I use?”

What values do we use for the order lifetime limits?  Or for the profit thresholds?  We could meticulously analyse historic data and try to calculate gradients, least-squares fits, Fourier spectra, etc…  but the results are only as good as the model and our model is less mathematically rigorous than a drunken poker match.  Instead, we can let an artificial intelligence loose on the historic data, and have it estimate the ideal parameters for our rules.

The Terminator

Artificial intelligence is a large subject in itself, and there are many models (primarily within the subfield of Machine Learning*) that could be applied to our optimisation problem – gradient descent, neural networks, and evolutionary algorithms are all popular options for this kind of problem.  The MetaTrader 4 trading platform uses a subtype of the latter category, a genetic algorithm, to optimise parameters for EAs.

* for more information, see my incomplete and probably erroneous notes based on a Coursera course, available here.

Hasta la vista, baby

We let the AI train our EA on the historic data, and several minutes later it returns with a list of parameter vectors that produced obscenely high profits.  Too good to be true?  Not at all – if you sent the EA back in time and started running it at that exact moment and it had no significant effect on the evolution of the market during its execution time then in all likelihood you would become obscenely rich.  Start it an hour too late or early though and you’ll probably be bankrupt within the hour.

Variance and cross-validation

To anyone familiar with machine learning, this is due to overfitting or variance.  The AI has learnt the random, noisy fluctuations in the data in addition to the general behaviour – and expects the same noise in new data fed to it.  To prevent this, we test the outcome from our AI against new datasets that weren’t used during training – the cross-validation datasets.  If the EA ha similar performance in the cross-validation as it did with the training data then our EA is probably well-trained or horribly biased.  Either way, it is still very unlikely that it will be profitable to use this EA.  Bias (or underfitting) occurs when the AI hasn’t learnt enough from the training data or when the training data is not a close enough representation of the problem.  Consequently, the results of the AI are biased based on what little information (if any) it has learnt or by the actual design of the AI itself.

Bias will result in an EA that generally makes losses in any situation whilst variance will result in an EA that can “make” extremely high returns on the historic training data, but fails rapidly when run on slightly different historic datasets or on live data (or on pretty much any dataset besides the training data).  It’s a chaotic solver for an ill-posed problem, so imagine butterflies and hurricanes, but where the butterflies are zombies and the hurricanes spray Plutonium.

The resulting performance

As Nostradamus predicted, EAs based on the preceding rules will make you homeless at record speed.  You can slightly delay this by optimising your EA properly though 😉

More rules and source code


I originally wrote this EA so that I could get used to the MetaTrader 4 scripting language (MQL4).  As I was also new to Forex, I started with the random trader then attempted to give it intelligence one little rule at a time.  I added considerably more rules than are described above, and the source code is available here and I urge you NOT to use it with real money as it WILL cause you extreme losses.

The extra rules include:

  • No trading in December-January (always makes losses during this spell on training data)
  • Stop completely if equity drops a certain amount below the initial value (not reliable)
  • Coarse-grained trailing stop loss (not reliable).

At some point, I will add some nice diagrams to this post (such as the bias/variance diagram from my Machine Learning notes) and in introduction to some of the terminology (ask, bid, spread, long, short, trend, range, open/high/low/close, etc).