This is the Python and JavaScript version of the Stock price forecasting with Deep Learning: throwing power at the problem (and why it won’t make you rich) post. Read the post for more details.

Contents:

Interactive dashboard

Stock Forecasting Dashboard

Stock price forecasting with Deep Learning: throwing power at the problem (and why it won't make you rich)

Observed and Forecast Values

Observed vs Forecast

Forecasting Residuals

Correct Guesses Distribution

Python code

!pip install nnetsauce
import matplotlib.pyplot as plt
import nnetsauce as ns
import pandas as pd
tscv = ns.utils.model_selection.TimeSeriesSplit()
stocks = pd.read_csv("https://raw.githubusercontent.com/Techtonique/datasets/refs/heads/main/time_series/multivariate/EuStockMarkets.csv")
stocks.head()
DAX SMI CAC FTSE
0 1628.75 1678.10 1772.80 2443.60
1 1613.63 1688.50 1750.50 2460.20
2 1606.51 1678.60 1718.00 2448.20
3 1621.04 1684.10 1708.10 2470.40
4 1618.16 1686.60 1723.10 2484.70
from tqdm import tqdm

n = stocks.shape[0]
half_n = n//2

for stock_index in range(stocks.shape[1]):

  tscv_obj = tscv.split(stocks,
                        initial_window=half_n,
                        horizon=1,
                        fixed_window=False)

  iterator = tqdm(tscv_obj, total=tscv.n_splits)
  observed = [] # observed stock prices for the next day
  forecasts = [] # random walk forecasts
  correct_guesses = [] # correctly guessing the direction of stock price?

  for i, (train_index, test_index) in enumerate(iterator):
      observed.append(stocks.iloc[test_index[0], stock_index]) # observed stock price for the next day
      forecasts.append(stocks.iloc[train_index[-1], stock_index]) # random walk forecast
      if i == 0:
          continue
      correct_guesses.append(1 if ((observed[-1]-observed[-2])*(forecasts[-1]-forecasts[-2]) > 0) else 0)

  fig, axes = plt.subplots(2, 2, figsize=(15, 10))

  # Plot 1: Observed vs. Forecast Line Plot
  axes[0, 0].plot(observed, label='Observed')
  axes[0, 0].plot(forecasts, label='Forecast')
  axes[0, 0].set_xlabel('Time')
  axes[0, 0].set_ylabel('Stock Price')
  axes[0, 0].set_title('Observed vs. Forecast')
  axes[0, 0].legend()


  # Plot 2: Observed vs. Forecast Scatter Plot
  axes[0, 1].scatter(observed, forecasts, alpha=0.5)
  axes[0, 1].plot([min(observed), max(observed)], [min(observed), max(observed)], color='red', linestyle='--', label='x=y')
  axes[0, 1].set_xlabel('Observed Values')
  axes[0, 1].set_ylabel('Forecast Values')
  axes[0, 1].set_title('Observed vs. Forecast Scatterplot')
  axes[0, 1].legend()


  # Plot 3: Residuals Plot
  residuals = [observed[i] - forecasts[i] for i in range(len(observed))]
  axes[1, 0].plot(residuals)
  axes[1, 0].axhline(y=0, color='r', linestyle='--')
  axes[1, 0].set_xlabel('Time')
  axes[1, 0].set_ylabel('Residuals (Observed - Forecast)')
  axes[1, 0].set_title('Observed - Forecast Residuals')


  # Plot 4: Percentage of Correct/Incorrect Direction Guesses
  percentage_1 = (sum(correct_guesses) / len(correct_guesses)) * 100 if correct_guesses else 0
  percentage_0 = 100 - percentage_1
  categories = ['Correct Direction', 'Incorrect Direction']
  percentages = [percentage_1, percentage_0]

  axes[1, 1].bar(categories, percentages, color=['green', 'red'])
  axes[1, 1].set_xlabel('Prediction Accuracy')
  axes[1, 1].set_ylabel('Percentage')
  axes[1, 1].set_title('Percentage of Correct and Incorrect Direction Guesses')
  axes[1, 1].set_ylim(0, 100)

  for i, v in enumerate(percentages):
      axes[1, 1].text(i, v + 2, f'{v:.1f}%', ha='center', va='bottom')

  plt.tight_layout()  # Adjust layout to prevent overlapping
  plt.show()
930it [00:00, 10694.50it/s]          

xxx

100%|██████████| 930/930 [00:00<00:00, 12536.57it/s]

xxx

100%|██████████| 930/930 [00:00<00:00, 6134.14it/s]

xxx

100%|██████████| 930/930 [00:00<00:00, 8359.88it/s]

xxx

Comments powered by Talkyard.