

Within forecasting there’s an age old question, ‘is what I am looking at a trend?’ Within the realm of statistics there are many tools that, with various degrees of success, answer said question. Yet, no approach has been able to achieve that which started the field of data forecasting in the first place. Looking at a graph derived from the data and drawing conclusions from it.
However, thanks to Deep Learning and Artificial Neural Networks that is about to change.
Welcome Computer Vision!
I stumbled upon the research paper, “Deep Learning and Time Series-to-Image Encoding for Financial Forecasting”, written by a team of faculty and students from the Department of Mathematics and Computer Science of the University of Cagliari in Italy.
In it the team proposes a novel approach to financial forecasting: Transforming time-series into images and using Convolutional Neural Networks to identify visual patterns and thus make predictions on future market movements. A TALL order. Moreover, the aforementioned method can be applied to any forecasting problem and should, with some degree of accuracy, produce good results.
The paper is fascinating and I highly recommend you read it as it dives deeper into the mathematics behind their methodology and compares the long-term performance of this approach against a simple BUY-HOLD-SELL strategy.
Unfortunately, it does not contain any code nor provided any source for the data. So, I decided to get to the bottom of this and reverse engineer their work and share my findings.
Before diving into my process, lets address a fundamental question: How do we visualize timeseries in a meaningful way such that we can train a Deep Learning model with it?
Gramian Angular Fields (GAF) are images representing a timeseries in a non-Cartesian coordinates system (i.e. each point on the plane is referenced by a X and Y axis). Instead the coordinates are mapped by a Polar Ordinate system (i.e. each point on the plane is determined by a distance from a reference point and an angle from a reference direction). Thus each GAF represents a temporal correlation between each time point.
For more information regarding Gramian Angular Fields consider reading, Encoding Time Series as Images for Visual Inspection and Classification Using Tiled Convolutional Neural Networks by Zhiguang Wang and Tim Oates from the University of Maryland. In the paper they dive deeper into GAF and introduce the idea of encoding time-series into images for training Convolutional Neural Networks.
Now, lets take a look at the data. The folks from University of Cagliari used five minute interval S&P 500 prices ranging from 1999 to 2015. Unfortunately, I couldn’t find the same data for free so I am using 21 years worth of second by second IBM share prices.
The data was extracted from here and needs some work before we can use it, as second by second data is messy. The data also has trading activity that happened on weekends, holidays and off trading hours, which, due to its variability, will introduce noise to our model.
What libraries we’ll need:
I’ll be writing the code in Python 3.7. You’ll need to install the dependencies from the requirements.txt file (in the repo). The most notorious being Pyts (a Python package dedicated to time series classification, and used here to convert our timeseries into GAFs matrices).
Lets write some code!
What we need is a way to create GAF images and place them in directories that represent the two classes we are trying to predict: Long or Short.
I’ll start by writing helper methods. The first one reads our file and groups the data in to one-hour intervals. Using Pandas Grouper function we can group data by a given time-frequency, filling missing times with a zero and removing duplicates. This will smooth our data, remove inconsistencies and reduce memory usage.
Next, I remove weekends, holidays and non-trading hours data, note that markets open at 9:30 a.m.; however, for the sake of rounding to the hour, I captured pre-open activity starting at 9:00 a.m.
Once the data is clean I began working on generating GAF images. I constructed the method ‘set_gaf_data’. It extracts 20 days worth of data. It then aggregates the timeseries into four different time intervals (one hour, two hours, four hours and one day) and collects the last twenty rows of said aggregations. Each collection will become an unique image that shows the evolution of time that led to our trading day.
Note that, the last data-point of a trading day dictates a trading decision made: Long if next days close is higher than that of the current day, Short if either the opposite is true or if prices are the same.
The preprocessed data is passed through a wrapper method create_gaf. It’s a wrapper for an instance of the class GramianAngularField from the Pyts package.
It creates a matrix of temporal correlations for each (Xi, Xj) by first rescaling the values to numbers between -1 to1 and then computes the polar coordinates. Each collected timeseries becomes a N x N matrix where N is the number of rows in the time series (in our case 20).
The output should look like this:
Matrices are derived from the same trading day, but at different time intervals. Each is then transformed into a GAF image, put together into a larger image (where each value is then transformed into a RGB color matrix) and saved as a png files on either Long or Short folder. The results looks like this:
With this out of the way we can start working on the model.
Due to the memory constrains on my computer I am implementing a different model to the one used by the folks at the University of Cagliari to build my model. I am building a Sequential model using Keras.
I chose to build an ensembled model (train 3 models and average their scores). It contains eight 2D Convolutional layers with relu for activation functions and one dense layer to get the binary prediction. I increased my neuron counts every few layer’s, added a dropout rate of 0.4 to standardize my layers inputs and included batch normalization to the network. I came up with these values through trial and error and I encourage you to implement your own model.
Due to the limited amount of computing power, time and data, I decided that the model should not take longer than 15 minutes to train on my GPU enabled laptop (with an Nvidia GeoForce graphics card with 6GB GPU). This is reflected on the hyperparameters I selected, feel free to change them accordingly. I’ll attach a link to my repo down below.
The next step is to compile the model, I used Adam for my optimizer (the best for binary image classification). Set my learning rate to 1e-3 and set accuracy as the matric I am capturing to measure learning performance.
the metric I am capturing is accuracy.
I ran the data through a helper method I built called ensemble_data, it’s designed to split the data by the number of networks. Each network is then trained on a slightly different corpus of images. The next step using Keras ImageDataGenerator, the images are resized and split them into train, validate and test sets in memory. If you have never used it I highly recommend you do, it maps your classes by either passing the data source path or a DataFrame.
At the moment of fitting the model, to improve the performance, I set up my callback with ReduceROnPlateau which will reduce my learning rate if the model’s performance does not improve over time. I add the number of steps per epoch and the validation steps. I then trained the model. Finally, the model is saved and evaluated.
The ensembled model had an accuracy of score similar to the one to the team from Cagliari at ~52%. The results were calculated by averaging the scores of all the networks. Although it looks pretty low, being correct on a trade position anywhere above 50% of the time is considered good specially when just looking at the data in isolation.
Also, when we are talking about long-term decision making, the team from Cagliari reported that their model outperformed other trading strategies by a significant margin. Not to mention that if this method alone was able to predict the market I wouldn’t be writing about it.
While I focus on the historical IBM Price data in this paper, the model can be more sophisticated. For example, in addition to trading data you can layer onto the images data such as fundamental analysis, risk metrics, sentiment analysis, ESG scores, etc.
Computer vision has the potential to accurately spot trends and spot market movements, specially when taking into consideration that multiple sources of data can be leveraged on the same observation. Moreover it can also be applied to any forecasting problem and should deliver meaningful results.