Home > Coding > Predicting Stock Prices with Python and AI: My 14-Day Forecast Model (Version 4)

Predicting Stock Prices with Python and AI: My 14-Day Forecast Model (Version 4)

Hey everyone! I’ve been working on a Python script to predict stock prices over the next 14 business days, and it’s finally running smoothly. This isn’t just a basic guess—it uses a mix of technical indicators and a simple AI model to forecast prices for any stock you throw at it (like TSLA or NVDA). Want to see how it works? Let’s break it down!

What’s in the Model?

I’ve packed this script with five key indicators to give the AI some solid data to chew on:

  • 5-Day and 20-Day Moving Averages (MA5, MA20): These smooth out price trends over short (5 days) and medium (20 days) terms. MA5 catches quick shifts, while MA20 shows the bigger picture—perfect for spotting trends.
  • Relative Strength Index (RSI): RSI (14-day) measures momentum, ranging from 0 to 100. Below 30? Oversold—might bounce up. Above 70? Overbought—could dip. It’s like a speedometer for price moves.
  • Bollinger Bands (BB_Upper, BB_Lower): Built around a 20-day moving average with ±2 standard deviations, these bands track volatility. Prices near the upper band might signal a peak; near the lower, a bargain.
  • VIX (Volatility Index): The “fear gauge” from the S&P 500 options market. High VIX means market jitters, often pushing stocks down; low VIX suggests calm waters. It adds a market-wide vibe to the mix.

Together, these indicators give the model a blend of trend, momentum, volatility, and market sentiment—pretty robust for a starting point!

The AI Learning Part

The brain of this script is a Linear Regression model from scikit-learn, a classic in machine learning. Here’s how it learns:

  • Training: It takes historical data (e.g., 2024 to now) with the indicators above as inputs (features) and the next day’s closing price as the target. The model finds a “best-fit” line to predict how these features drive price changes.
  • Prediction: Starting from the last day’s data, it forecasts the next price, updates the indicators with that prediction, and repeats for 14 business days (skipping weekends and U.S. holidays via the holidays library).
  • Noise: I add a bit of randomness (np.random.normal) scaled by half the stock’s historical volatility. This mimics real market wiggles—without it, the predictions would be too smooth and boring!

Linear Regression is simple but effective—it assumes a straight-line relationship between features and price. For my NVDA run, it predicted a steady climb from $98 to $110 over two weeks, with small dips and jumps that stayed consistent across runs.

The Code

Here’s the full script—plug in any ticker and watch it go! (You’ll need yfinance, pandas, numpy, scikit-learn, matplotlib, and holidays installed.)

python:

import yfinance as yf
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import holidays

us_holidays = holidays.US()

def fetch_data(ticker):
    try:
        stock = yf.download(ticker, start="2024-01-01", end=datetime.today().strftime('%Y-%m-%d'))
        vix = yf.download("^VIX", start="2024-01-01", end=datetime.today().strftime('%Y-%m-%d'))
        if stock.empty or vix.empty:
            raise ValueError(f"Failed to fetch data for {ticker} or VIX")
        df = pd.DataFrame(index=stock.index)
        df[f'Close_{ticker}'] = stock['Close']
        df['Close_VIX'] = vix['Close']
        df = df.dropna()
        return df
    except Exception as e:
        print(f"Error fetching data: {e}")
        return None

def calculate_rsi(data, periods=14):
    delta = data.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

def prepare_data(df, ticker):
    df = df.copy()
    stock_col = f'Close_{ticker}'
    df['MA5'] = df[stock_col].rolling(window=5).mean()
    df['MA20'] = df[stock_col].rolling(window=20).mean()
    df['RSI'] = calculate_rsi(df[stock_col], periods=14)
    df['BB_Middle'] = df[stock_col].rolling(window=20).mean()
    df['BB_Std'] = df[stock_col].rolling(window=20).std()
    df['BB_Upper'] = df['BB_Middle'] + (df['BB_Std'] * 2)
    df['BB_Lower'] = df['BB_Middle'] - (df['BB_Std'] * 2)
    df = df.dropna()
    df['Target'] = df[stock_col].shift(-1)
    df = df[:-1]
    df['Returns'] = df[stock_col].pct_change()
    volatility = df['Returns'].std()
    return df, volatility

def train_model(df, ticker):
    X = df[[f'Close_{ticker}', 'MA5', 'MA20', 'RSI', 'BB_Upper', 'BB_Lower', 'Close_VIX']]
    y = df['Target']
    model = LinearRegression()
    model.fit(X, y)
    return model

def is_business_day(date):
    return date.weekday() < 5 and date not in us_holidays

def predict_next_14_business_days(model, df, volatility, ticker):
    last_data = df.tail(1)[[f'Close_{ticker}', 'MA5', 'MA20', 'RSI', 'BB_Upper', 'BB_Lower', 'Close_VIX']].values[0]
    predictions = []
    future_dates = []
    days_ahead = 0
    business_days_count = 0
    last_vix = last_data[6]

    while business_days_count < 14:
        next_date = datetime.today() + timedelta(days=days_ahead + 1)
        if is_business_day(next_date):
            next_price = model.predict([last_data])[0]
            noise = np.random.normal(0, 0.5 * volatility * last_data[0])
            next_price += noise
            predictions.append(max(next_price, 0))
            future_dates.append(next_date)

            new_close = next_price
            new_ma5 = (last_data[0] * 4 + new_close) / 5
            new_ma20 = (last_data[2] * 19 + new_close) / 20
            delta = new_close - last_data[0]
            new_rsi = min(max(last_data[3] + (delta * 2), 0), 100)
            new_bb_std = df['BB_Std'].iloc[-1]
            new_bb_upper = new_ma20 + (new_bb_std * 2)
            new_bb_lower = new_ma20 - (new_bb_std * 2)

            last_data = [new_close, new_ma5, new_ma20, new_rsi, new_bb_upper, new_bb_lower, last_vix]
            business_days_count += 1
        days_ahead += 1

    return future_dates, predictions

def plot_results(historical_df, future_dates, predictions, ticker):
    plt.figure(figsize=(12, 6))
    plt.plot(historical_df.index, historical_df[f'Close_{ticker}'], label=f'Historical {ticker} Close', color='blue')
    plt.plot(future_dates, predictions, label=f'Predicted {ticker} Close', color='red', linestyle='--')
    plt.title(f'{ticker} Stock Price Prediction with VIX (Next 14 Business Days)')
    plt.xlabel('Date')
    plt.ylabel('Price (USD)')
    plt.legend()
    plt.grid()
    plt.show()

if __name__ == "__main__":
    ticker = input("Enter stock ticker (e.g., TSLA, AAPL): ").strip().upper()
    data = fetch_data(ticker)
    if data is not None:
        prepared_data, volatility = prepare_data(data, ticker)
        model = train_model(prepared_data, ticker)
        future_dates, predictions = predict_next_14_business_days(model, prepared_data, volatility, ticker)

        print(f"Predicted {ticker} Stock Prices for the Next 14 Business Days:")
        for date, price in zip(future_dates, predictions):
            print(f"{date.strftime('%Y-%m-%d')}: ${price:.2f}")

        plot_results(prepared_data, future_dates, predictions, ticker)
    else:
        print("Failed to proceed due to data fetch error.")

How to Run It

Install the dependencies:

bash

pip install yfinance pandas numpy scikit-learn matplotlib holidays

Type a ticker (e.g., NVDA), and it’ll spit out a 14-day forecast with a plot. For NVDA, mine went from $98 to $110—stable but with enough wiggle to feel real.

What’s Next?

The model’s pretty stable now, thanks to toned-down noise (half the volatility). Want more market-like chaos? Bump the noise to full volatility (1.0 * volatility). I’m also thinking of swapping Linear Regression for a Random Forest or LSTM to catch trickier patterns—any AI upgrades you’d suggest? Drop a comment with your thoughts or your own predictions—I’d love to hear how it works for you!

Leave a Comment