Artificial Intelligence and Machine Learning for Foreign Exchange (Fx) Trading Part 1 — Hello World

ml bull
9 min readMay 12, 2023

--

Introduction

This will be the first of several articles dedicated to understanding ML/AI and how it relates to the Foreign Exchange (Fx) Market and the complexities of prediction.

I have been trading Fx for 20 years lets be absolutely clear, you are not going to make an obscene about of money very quickly! However, there are techniques that can deliver a positive statistical return over time. The articles that purport to be able to predict stock, FX, crypto or other market returns are normally price based and largely unusable to create profitable trading strategies. This series of articles will focus PRACTICAL TRADING STRATEGIES derived from ML applied the Fx market but you could also apply these strategies to the stock, commodity or crypto markets.

A little about me. I am an engineer by training with a long software development career before moving into commercial roles all in “big tech”. I hold a Bachelor or Engineering, Master of Commerce and several ML certificates. I started exploring the Fx market 20 years ago and have used manual, automated and, for the last 5 years or so, automated ML techniques and still active trade the market today.

Over the coming weeks I hope to delve into ML techniques from logistic regression, complex time series, decision trees, anomaly prediction as well as a variety of neural nets including visual pattern recognition. We will look at the raw data, feature determination/selection, different ML libraries (SciKit Learn and TensorFlow), different development studios (Google Collab, visual studio code), processing platforms (Google Colab, your pc and cloud) as well as understanding the Fx market itself. Note all code will be in python.

What You Need to Know

You should understand the basics of the Fx market, OHLC, what it means and charts, bid/spread and understand you can BUY or SELL heavily leveraged to enter a trade. We will build the rest of your understanding over the coming weeks. On the programming side you need the basics on Python and Pandas Data frames. Some experience with colab is good but you can build that as we go and we will land on Visual Studio Code.

NOT FINANCIAL ADVICE

Also you should note this is NOT FINANCIAL ADVICE or advocating for any trading system. I have no intention of offering up the systems I actually use but instead will use Fx market to illustrate techniques in ML andsome of the tricks I have learned in the hope of you finding your own path. You should note the vast majority of retail traders in Fx LOSE MONEY!

Hello World

So, for this first article, lets start with a simple example we can build on in subsequent articles. This is the “hello world” of FX / ML using Google Colab, python and SciKit Learn.

If your unfamiliar with Colab just head to https://colab.research.google.com/ while signed into google and start a new notebook.

Firstly lets import our core datasets. The GitHub for this project (see references) contains a dataset we can use (already prepared, we will go into that another week, its for this exercise only, don’t use it for real learning). It contains the 60 minute OHLC for the AUDUSD and EURUSD pairs for about 7 years. If that’s sounds foreign we will be covering it in the coming weeks. for now just know the “close” is the price as it finishes each hour.

The code below imports the data from GitHub, manipulates the dates into the right format and gives an overview of the data.

import pandas as pd 
from datetime import datetime

url = 'https://raw.githubusercontent.com/the-ml-bull/01_hello_world/main/Fx60.csv'
dateparse = lambda x: datetime.strptime(x, '%d/%m/%Y %H:%M')

df = pd.read_csv(url, parse_dates=['date'], date_parser=dateparse)

df.head(n=10)
Output

Visualizing the Data

This next step is optional (not necessary) but helps us see whats going on. It does require you to install the mplfinance package so if your not comfortable you can just skip it. We will be dealing with these packages and charts etc. in the coming weeks.

!pip install mplfinance
import mplfinance as mpf

# create DF and copy values from main df
mpf_df = pd.DataFrame()
mpf_df[['date', 'Open', 'High', 'Low', 'Close', 'Volume']] = df[['date', 'audusd_open', 'audusd_high', 'audusd_low', 'audusd_close', 'audusd_volume']].to_numpy()

# set index to datetime index date
mpf_df['date'] = pd.to_datetime(mpf_df['date'])
mpf_df = mpf_df.set_index('date')

# set OHLC as float
mpf_df = mpf_df[['Open', 'High', 'Low', 'Close', 'Volume']].astype(float)

# Chart
mpf.plot(mpf_df, volume=True, datetime_format='%Y', type='line')

This shows the price of the AUDUSD of the study time period (about 7 years) together with the volume. Showing some big swings.

Trading Strategy

We need a “hypothesis” of how we can trade. We can then develop an algorithm for it and then test. If it shows promise, we can then optimize it. The “swings” in price carry the opportunity but in what time frame, what currency pair? How long can we tollerate -ve returns? Does every trade have to be profitable? We will get into these questions in the coming weeks but, for our “hello world” example lets assume we hypothesis is
- Use the AUDUSD pair
- The past x (choose 4 hours) hours of data hold some indicator that the price will move suddenly in the next y hours (choose 4 hours)
- so by using the last 4 hours of prices we can predict a sudden movement up (ignore down in our hello world example to keep it as simple as possible)
- We define a sudden movement as 200 points (random assignment). Note we will definate a “point” as the change in price. Eg starting at 0.68218 and closing at 0.67429 is a difference of -789 points.

Example of hypothesis

Note if you want to chart this yourself you can add the following lines to the previous code segment

from matplotlib.ticker import FormatStrFormatter
fig, axlist = mpf.plot(mpf_df['2022-12-01':'2022-12-02'], volume=True, datetime_format='%Y-%m-%d %H:%M', type='candle', returnfig=True)
axlist[0].yaxis.set_major_formatter(FormatStrFormatter('$%.5f'))
mpf.show()

ML Method — Logistic Regression

Our hypothesis requires in input of 4 hours of data to produce a binary output (that the price will go up by 200 points the next 4 hours). This is almost the definition of Logistic Regression which is an easy introduction to machine learning and what we will focus on here. In the coming weeks we will pull the curtain back on what’s happening in detail.

Data Preparation

Our data needs to contain the last 4 prices (x_t1, x_t2, x_t3, x_t4) as well a binary indicator that the price has gone up 200 points (y=1) or hasn’t (y=0). this means our t0 is the point we make a prediction or the “open” price at bar t=0. the close price at bar t=0 is the movement in the first bar. So the movement after 4 hours is -3 bars (t=0, t=-1, t=-2, t=-2)

import numpy as np

df = df[['date', 'audusd_open', 'audusd_close']].copy()

# x is the last 4 values so create x for each
df['x_t4'] = df['audusd_close'].shift(4)
df['x_t3'] = df['audusd_close'].shift(3)
df['x_t2'] = df['audusd_close'].shift(2)
df['x_t1'] = df['audusd_close'].shift(1)

# y is points 4 periods into the future - the open price now (not close)
df['y_future'] = df['audusd_close'].shift(-3)
df['y_change_price'] = df['y_future'] - df['audusd_open']
df['y_change_points'] = df['y_change_price'] * 100000
df['y'] = np.where(df['y_change_points'] >= 200, 1, 0)

df.head(n=30)

Using Pandas “shift” we can look forward and back in time to create the X inputs to our model and y outputs to our model. In the output you can see there are far more 0’s than 1’s. This is called an “unbalanced” dataset and will be correcting for this next week.

Datasets

Next we create a “train” and “validation” dataset. Its important our model doesn’t learn on the data we use to check how good it is so we create two very different sets to train on and to test the results on. Notice we assign 70% to the training set and it starts with the 4th sample since we need the previous 4 so fill out the timeseries. Also the last 4 (-3) cant be used since we don’t yet have the future data to calculate it.

Note often times data is randomized, either at this stage or during learning. However, we wont be doing that here due to the time series nature of this Fx(more on that next week).

from sklearn.linear_model import LogisticRegression   

x = df[['x_t4', 'x_t3', 'x_t2', 'x_t1']]
y = df['y']

# create train and val datasets. Note Fx "follows" (time series) so randomization is NOT a good idea
no_train_samples = int(len(x) * 0.7)
x_train = x[4:no_train_samples]
y_train = y[4:no_train_samples]
x_val = x[no_train_samples:-3]
y_val = y[no_train_samples:-3]

Training

So lets fit our model.

lr = LogisticRegression()
lr.fit(x_train, y_train)

How do we measure how good it is?

So how do we measure success? In logistic regression we usual use the “confusion matrix” as well as some derivatives. For this week we will be using these as then are important to understand, however, they aren’t ideal for our hypothesis and we will dig into that more next week.

In the relevant metrics are:

Loss: the raw error from the machine learning algorithm. A lower loss should correlate with a better trading outcome however, that’s not necessarily true as we shall see in later articles. The loss here of 4.46 really doesn’t mean anything but itself but it will make sense as we start “tuning” our model next week.

Score: Produced from the scikit learn framework and is the “accuracy”. As you can see at 87.61% sounds great we don’t actually predict any trades so its pretty much useless here.

TP: True Positives where we predict a big price change and that’s what happened. A big number here is really our goal
FP: False Positive where we predict a big price change but that didn’t happen. A high number here is the worst possible outcome.
TN: True negatives are where we didn’t predict a change and we were right.
FN: False Negatives are were we didn’t predict a chance and we got that wrong (there was a change).

Precision: A measure of accuracy.. i.e. If we predict it, what percentage came true. TP and Precision (and another we will introduce next week) will be our primary metrics
Recall: A measure of what we we missed out on. i.e. the percentage where we didn’t predict a big price change but there was one
F1: An overall combination measure of precision and recall.

So in this model we have

from sklearn.metrics import log_loss, confusion_matrix, precision_score, recall_score, f1_score

# predict from teh val set meas we have predictions and true values as binaries
y_pred = lr.predict(x_val)

#basic error types
log_loss_error = log_loss(y_val, y_pred)
score = lr.score(x_val, y_val)
tn, fp, fn, tp = confusion_matrix(y_val, y_pred).ravel()
precision = precision_score(y_val, y_pred, zero_division=0)
recall = recall_score(y_val, y_pred, zero_division=0)
f1 = f1_score(y_val, y_pred, zero_division=0)

# output the errors
print('Errors Loss: {:.4f}'.format(log_loss_error))
print('Errors Score: {:.2f}%'.format(score*100))
print('Errors tp: {}'.format(tp))
print('Errors fp: {}'.format(fp))
print('Errors tn: {}'.format(tn))
print('Errors fn: {}'.format(fn))
print('Errors Precision: {:.2f}%'.format(precision*100))
print('Errors Recall: {:.2f}%'.format(recall*100))
print('Errors F1: {:.2f}'.format(f1))

In this model TP and FP are 0 meaning we didn’t actually predict any occasions where the price would move. So our best possible trading result would be a $0 return (and also no losses). This, is more or less useless! It also demonstrates that a decent score and/or loss may have nothing to do with a trading return.

Summary

We have done a basic hello world type regression analysis of a simple Fx model. In truth, its a pretty poor model and not actionable in a trading strategy however, we will build on it to improve its output over the coming weeks.

Next Week

Next article we will look at our lack of predictions and why we don’t have any. We will review the handling of unbalanced data, interpretation of the results, a new custom metric, decision boundaries and a little more on Fx as a time series.

The week after we will take a look under the regression curtain to so what’s really happening before we move onto a more in-depth understanding of our features and why using price may not be ideal.

References and links

Github: https://github.com/the-ml-bull/hello_world
Twitter: @the_ml_bull
YouTube: https://youtu.be/TXETFNcJjV8

--

--