Forecasting Stock Market Trends: A Mixture Model Approach with TensorFlow Probability | by Kaneel Senevirathne | Oct, 2023


This image was generated by an AI

Disclaimer: This article presents quantitative research I conducted in the past. Please note that the model has not been backtested or used in real-time trading. I am sharing this quantitative research solely for educational and entertainment purposes. If you choose to trade, please do so at your own discretion and risk.

Welcome to a journey through the fascinating world of quantitative research and stock market forecasting. In this blog, we’ll delve into a unique research project from my archives. I’m excited to share the insights and findings from this project, but I want to emphasize that this model remains untested in real-time trading. It’s important to treat this information as an educational exercise rather than financial advice. So, let’s embark on this data-driven adventure, explore the potential of mixture models in stock market trend forecasting.

In our attempt to forecast stock market trends, we turn to the time-tested technique of Exponentially Weighted Moving Averages (EMA) (Figure 1). Traders have relied on EMAs for years to discern market trends. Traditionally, various EMA rolling periods are combined to gauge market direction. In this exploration, we leverage EMA signals with 60 and 90-period windows. But our approach take a distinctive path by employing a Mixture Model, offering a unique perspective on predicting the trends of the S&P 500 spanning from 2021 to 2023. Furthermore, instead of relying scikit-learn’s built in Gaussian Mixture Model (GMM), we leverage Tensorflow Probability (TFP) to explore more versatile and adaptable modeling techniques. It’s important to note that this article provides a high-level overview of our methods. If you’re eager to dive into the details, the complete code and notebook are accessible for your perusal.

Figure 1: S&P 500 hourly chart between 2021–10 and 2023–10 and short (60) and long (90) EMA values.

To gauge the accuracy of our model, the initial step is to label the trends. As depicted in Figure 2, we’ve annotated the S&P 500 data spanning from October 2021 to October 2023. In this annotation, the green data points represent upward trends, defined here as a time period when the S&P 500 advances by at least 20 points or more. Conversely, the red data points denote downward trends, indicating when the S&P 500 retreats by 20 points or more. This labeling process lays the groundwork for our model evaluation.

Figure 2: Annotated trends. Green resembles uptrends and red resembles downtrends.

Now that we’ve established data for our evaluation methodology, our next step is data preparation for the model. In this phase, we’ll employ the “rate of change of the EMA difference (ROC MA DIFF)” as our predictor variable. This entails calculating the difference between the short and long EMA values and then determining the rate of change of this differential value. Figure 3 provides a visual representation of this variable’s behavior for the S&P 500 during the period from 2021 to 2023. This variable will play a crucial role in our model’s predictive power.

Figure 3: The plot above is S&P 500 price and short and long ema values. The plot below is the “rate of change of the EMA difference”. The green dots represent this value when S&P is trending up, and red dots represent this value when S&P is trending down.

Directing our attention to the lower section of Figure 3, we can observe the dynamic nature of the ROC MA DIFF (Rate of Change of Moving Average Difference) over time. Notably, it becomes apparent that this value typically assumes positive values during periods characterized by upward trends and, conversely, tends to be negative during downtrends. To gain a more evident perspective on this distinction, let’s visualize the data using a histogram.

Figure 4: MA DIFF ROC values color coded based on the trend. Here 1’s represent ‘uptrends’ and 2’s represent ‘downtrends’.

Examining the histogram of MA DIFF ROC in Figure 4, a distinction emerges between uptrends (labeled as 1) and downtrends (labeled as 2). One approach to classifying these trends could involve a visual inspection and the manual assignment of a boundary. In this context, a potential boundary might be -0.02, where downtrends are predicted when MA DIFF ROC falls below this threshold, and uptrends are predicted otherwise. However, a more sophisticated and data-driven method involves employing a mixture distribution. This approach empowers the model to autonomously determine class assignments, enhancing the accuracy and robustness of our trend prediction.

Next, our data undergoes division into distinct training and testing sets. In this particular setup, we allocate data from the span of 2021 to 2023 as our training dataset, while the remainder serves as our testing dataset. When it comes to implementing the mixture distribution, we turn to TensorFlow Probability (TFP). One notable advantage of using TFP lies in its versatility, allowing us to employ a variety of probability distributions beyond Gaussian distributions. This stands in contrast to scikit-learn’s Gaussian Mixture Model, which relies on normal distributions for each class. As an illustrative example, within TFP, we have the flexibility to use distributions like two skew normal distributions to effectively represent the two distinct classes, deviating from the conventional choice of two Gaussian distributions. This adaptability amplifies our capacity to model complex data patterns accurately. (However, if you look closely at the data, the two distinct distributions looks gaussian. Thus the scikit-learn’s GMM model, outperforms the TFP model I built here. You can check the performance of the GMM in my notebook towards the end.)

Below is a code snippet on how to build a mixture model in TFP. You can see the full code in my notebook.

# Initial values for means and scales
mu1 = tf.Variable(-0.04, dtype=tf.float32, name="mu1")
scal1 = tf.Variable(0.01, dtype=tf.float32, name="scal1")
mu2 = tf.Variable(0.02, dtype=tf.float32, name="mu2")
scal2 = tf.Variable(0.01, dtype=tf.float32, name="scal2")

#create a categorical distribution for the probabilities
p = tf.Variable([0.5, 0.5], dtype = tf.float32, name = 'probs')
p1 = tf.Variable(tf.nn.softmax(p), name = 'prob1')
cat_dist = tfd.Categorical(probs = p1)

#mixture model
components = [tfd.Normal(mu1, scal1), tfd.Normal(mu2, scal2)]
mixture_model = tfd.Mixture(cat=cat_dist, components=components)

#negative log likelihood
def negative_log_likelihood(data):
return -tf.reduce_mean(mixture_model.log_prob(data))

#assign the optimizer
optimizer = tf.optimizers.Adam(learning_rate = 0.01)

#train the model
for i in range(1000):
with tf.GradientTape() as tape:
tape.watch([p1, mu1, scal1, mu2, scal2])
loss = negative_log_likelihood(data)

gradients = tape.gradient(loss, [p1, mu1, scal1, mu2, scal2])
optimizer.apply_gradients(zip(gradients, [p1, mu1, scal1, mu2, scal2]))

Figure 5: Trained distributions by TFP. The blue represents the mixture model which captures the data. The red and green represents the two gaussian distributions trained by TFP. The black is training data.

Figure 5 illustrates the trained distributions generated by our mixture model. In this instance, we employed a mixture model consisting of two Gaussian components with variable probabilities. The blue line in the figure represents the combined model, while the green and red dashed lines signify the two Gaussian components trained by TFP. This model is subsequently applied to the test data, and the outcomes are depicted in Figure 6.

Figure 6: Predicted test results by the mixture model. Green dots represent uptrends, red dots represent downtrends.

Despite Figure 6 showing a good amount of correct predictions, a more rigorous evaluation of the models performance yields different insights. The annotated data reveals a testing accuracy of 0.61, indicating that while the model’s predictions are moderately accurate, there is room for improvement. It’s crucial to highlight that this level of accuracy, while not unfavorable, could result in false positives. In real-time trading scenarios, such false predictions combined with unaccounted slippage could result in financial losses, underscoring the need for continued refinement and fine-tuning of the model.

In this blog post, through the world of quantitative research and stock market forecasting, we’ve unearthed the power and potential of data-driven insights. From our foundation in Exponentially Weighted Moving Averages (EMA) to the innovative TensorFlow Probability (TFP) mixture models, we’ve explored the dynamic interplay of data and models. While the journey has showcased promising results, we must remain vigilant. The achieved testing accuracy is certainly commendable. However, it serves as a reminder of the intricate balance within the landscape of machine learning and financial markets. This balance encompasses the challenge of making accurate predictions while also being mindful of the potential for encountering false positives. In these domains, where precision is paramount, it’s essential to navigate this equilibrium thoughtfully and with a keen eye on risk management. In the unpredictable realm of real-time trading, this balance can be the fine line between success and losses.

Thank you very much for reading! Let me know if you have any comments.



Source link

Be the first to comment

Leave a Reply

Your email address will not be published.


*