Can a Machine Learning Model Read Stock Charts and Predict Prices? | by Viraf | Towards Data Science

Note from Towards Data Science’s editors: While we allow independent authors to publish articles in accordance with our rules and guidelines, we do not endorse each author’s contribution. You should not rely on an author’s works without seeking professional advice. See our Reader Terms for details.
Most of the ML models out there are trying to predict stock prices (or the changes in stock prices) using historical price data and other technical indicators — i.e., NUMERIC INPUTS. But, I asked myself, why can’t an ML model replicate precisely how a human trades in the stock markets?
Any average person would open up the stock price charts (candlestick charts), and try to find some patterns in the price data. Maybe next, apply some technical indicators, peek a look at the company fundamentals, and finally make a decision on the next movement of the stock price as a combined output of all the charted and numeric inputs. What if an ML model could also make these conclusions from visual information?
So let’s pass the price history time series as visual information to a CNN model as input. Will the model recognize the patterns in the visual data like a human does? Will this model perform better than a model that takes numeric data as input? Well, let’s find out!
Before we start, in my last article, we explore why using LSTMs blindly to predict stock prices is going to land you in trouble. You can read that here. Already read that? Good, now we can proceed.
And next, a disclaimer. None of this is financial advice, nor should you implement it directly in practice. Consider this as an experiment and nothing more. Cool, now this aside, we can get on with our experimenting!
Instead of predicting stock prices, we shall predict the direction of price movement for the next day, i.e., whether the stock price will go up or down or sideways. Let’s get started!
The flow of this article is as follows:
Get historical stock data in python.
Convert the price data to a visual representation
Build and train a model with Tensorflow Keras.
Predict and interpret the results.
There are multiple options to get access to historical stock prices in python, but one of the most straightforward libraries is yfinance. Quite convenient and free, it gets the job done by scraping data from yahoo finance.
!pip install yfinance## Import the required librariesimport yfinance as yfimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom pandas.plotting import register_matplotlib_convertersregister_matplotlib_converters()
For this article, I will take up the stock prices of ‘Reliance,’ the largest corporation in the Indian stock markets, but feel free to try this out for any other instrument as well.
The following piece of code downloads stock price data for Reliance a period of around 18 years (I am intentionally avoiding the COVID period) with a resolution of 1 day and stores it in a pandas dataframe. You can vary these parameters as you deem fit for your experiments.
Printing out the head of the pandas dataframe, you can see the various parameters like ‘Open’, ‘Close’, ‘High’, ‘Low’, ‘Volume’ available for the stock data.
Plotting out the ‘Close’ price to visualize the data, see how nicely the stock has risen in the last few years.
Now we shall add some additional features to our data. First, calculate the percentage change from the previous day close. Next based this change, generate a signal which is:
0 (if the change is lesser than -2.5%)
1 (if the change is between -2.5% and -1%)
2 (if the change is between -1% and 1%)
3 (if the change is between 1% and 2.5%)
4 (if the change is greater than 2.5%)
The dataframe now looks like:
Now, this is completely arbitrary, you can vary it as you please. You can break the change into an even more/lesser number of parts (adjust the last layer of the model accordingly).
Now, this step is very important, since it will decide what the model sees. For this article, I want to keep the images as close as possible to the candlestick charts a human trader sees. A constraint is that every input image has to be of the same dimensions and must contain sufficient information for the model to make conclusions from.
We shall have a lookback period, for example, the past 50 days (10 trading weeks), which shall be represented. For simplicity, for each of these 50 days, the open and close, and the direction of the price movement will be encoded.
Since images of the same dimension will be fed to the neural network, it might not understand where this image stands in the entirety of the 15 years. For example, in 2002, the prices are at ~80–90 whereas they slowly rise with time to ~1800. Although price patterns may (or may not) be independent of the absolute stock prices, I wanted to encode some of this information as well in the images. So, to give the image some context to the past prices and their absolute price levels, the 50-day price representations will be scaled in a bigger time window which considers additional previous price values.
The code for generating this visual representation is:
Note: This is a visual representation very close to what we see on the candlestick charts (that was the whole point). However, you can use your imagination (and some discretion) to create a completely different visual representation with other encoded parameters as well. Because the way a CNN model sees and learns from an image might (or might not) be very different from how we do!
Next, let’s create a data generator that will iterate through the 15 years of data and create pairs of images and the corresponding next-day-predictions.
This data generates image-prediction batches like
Since we have inputs as images and require outputs as one of three classes (up, down, no movement), our model will have a few convolutional layers, followed by a few dense layers and finally a softmax function.
Let’s initiate the generator objects and start the training.
Post-training, the losses can be plotted as:
plt.plot(history.history['loss'], label='train')plt.plot(history.history['val_loss'], label='val')plt.legend()plt.show()
Let’s now see the accuracy on the test data.
## Evaluating the performance of the modelprint(model.evaluate(test_gen,steps = (len(data)-split_test)//batch_size))>>> loss: 1.3830 - accuracy: 0.4375
Well, given 5 possible outcomes, the accuracy of randomly guessing one would be 0.2. So this model seems to have performed quite well comparatively. Or has it?
Plotting out the predicted outputs, it’s clear what has happened. The model has not learned anything useful yet, so it ends up predicting “2” as every output resulting in relatively high accuracy.
Let’s train the model some more then. But now, the validation loss increases greatly. Plus, testing gives an accuracy of less than 0.3. Not very encouraging, the model has probably overfitted on the training data. A very clear reason for this is the small size of training data compared to the model size.
Although the performance was not extremely encouraging, this was quite an innovative approach of looking at the age-old problem of predicting stock prices. A few more ideas on these lines are giving multi-timeframe inputs (say, weekly data as inputs as well), or additionally providing technical indicators as numeric data (in parallel with visual charts), or transform the price data into other visual domains (doesn’t have to be the charts as we see them), etc. What else do you think we can do to improve this model? Do you have any other interesting ideas?
After trying out all these ideas, the question remains — is feeding visual data providing any edge that numeric data cannot? What do you think?
You can find the entire code in my GitHub repository.
Finally, I am not saying I am an expert in these fields — I am just putting forward my explorations on this topic, so feel free to point out my errors or add anything I missed. I would love to hear your feedback.
Do you want to be rich overnight using ML in stocks? This article is (NOT) for you!
towardsdatascience.com
Or check out some of my other machine learning articles. I’m sure you’ll find them useful...