Yassine-Ammani's picture
Update app.py
cf30647 verified
Raw History Blame Contribute Delete
7.08 kB
import gradio as gr
import numpy as np
import tensorflow as tf
from tensorflow import keras
import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta
# Load the model
model = keras.models.load_model('gru_model.h5')
def prepare_data(df):
"""
Prepare stock data for the model - using percentage changes
Expected features: Open, High, Low, Close, Volume
"""
# Select required columns
features = ['Open', 'High', 'Low', 'Close', 'Volume']
data = df[features].copy()
# Calculate percentage changes for prices (more stable normalization)
price_cols = ['Open', 'High', 'Low', 'Close']
for col in price_cols:
data[col] = data[col].pct_change().fillna(0)
# Normalize volume using rolling window
data['Volume'] = (data['Volume'] - data['Volume'].rolling(20, min_periods=1).mean()) / data['Volume'].rolling(20, min_periods=1).std()
data['Volume'] = data['Volume'].fillna(0)
# Clip extreme values to prevent outliers
data = data.clip(-3, 3)
return data.values, df['Close'].values
def predict_stock_symbol(symbol, days_to_predict=10):
"""
Fetch stock data and make prediction with proper price conversion
"""
try:
# Clean symbol
symbol = symbol.strip().upper()
# Fetch stock data (get more than 60 days to ensure we have enough)
end_date = datetime.now()
start_date = end_date - timedelta(days=120) # Get 120 days to be safe
stock = yf.Ticker(symbol)
df = stock.history(start=start_date, end=end_date)
if df.empty:
return f"❌ Error: No data found for symbol '{symbol}'. Please check the symbol."
if len(df) < 65: # Need extra days for percentage change calculation
return f"❌ Error: Not enough data. Found {len(df)} days, need at least 65 days."
# Prepare data
normalized_data, close_prices = prepare_data(df)
# Get last 60 days for prediction
last_60_days = normalized_data[-60:]
# Reshape for model input (1, 60, 5)
input_data = last_60_days.reshape(1, 60, 5)
# Make prediction
prediction = model.predict(input_data, verbose=0)
predicted_values = prediction[0]
# Get context for interpretation
last_close = close_prices[-1]
recent_closes = close_prices[-10:] # Last 10 closes for trend
avg_recent_change = np.mean(np.diff(recent_closes) / recent_closes[:-1]) * 100
# Interpret predictions as potential future close prices
# Assume predictions represent relative price movements
interpreted_prices = []
current_price = last_close
for i, pred_val in enumerate(predicted_values):
# Convert normalized prediction to price change
# Adjust this scaling based on your model's training
price_change_pct = (pred_val - 1.0) * 5 # Scale factor - adjust as needed
new_price = current_price * (1 + price_change_pct / 100)
interpreted_prices.append(new_price)
current_price = new_price # Use for next prediction
# Format results
result = f"📊 **Prediction for {symbol}**\n\n"
result += f"📈 Current Close Price: **${last_close:.2f}**\n"
result += f"📊 Recent Trend: {avg_recent_change:+.2f}% avg daily change\n"
result += f"📅 Data Period: {df.index[0].strftime('%Y-%m-%d')} to {df.index[-1].strftime('%Y-%m-%d')}\n"
result += f"📊 Total Days Used: {len(df)}\n\n"
result += f"🔮 **Price Predictions (Next 10 periods):**\n"
for i, (raw_val, price) in enumerate(zip(predicted_values, interpreted_prices), 1):
change_pct = ((price - last_close) / last_close) * 100
result += f" Day {i}: **${price:.2f}** ({change_pct:+.1f}%) [raw: {raw_val:.3f}]\n"
# Summary statistics
avg_predicted = np.mean(interpreted_prices)
total_change = ((interpreted_prices[-1] - last_close) / last_close) * 100
result += f"\n📈 **Summary:**\n"
result += f"• Average Predicted Price: **${avg_predicted:.2f}**\n"
result += f"• Total 10-Day Change: **{total_change:+.1f}%**\n"
result += f"• Prediction Range: ${min(interpreted_prices):.2f} - ${max(interpreted_prices):.2f}\n"
result += f"\n⚠️ **Disclaimer:** Model predictions are experimental. Scaling factor may need adjustment based on training data."
return result
except Exception as e:
return f"❌ Error: {str(e)}"
def get_stock_info(symbol):
"""
Get basic stock information
"""
try:
symbol = symbol.strip().upper()
stock = yf.Ticker(symbol)
info = stock.info
name = info.get('longName', 'N/A')
sector = info.get('sector', 'N/A')
country = info.get('country', 'N/A')
return f"📋 **Stock Info:**\n• Name: {name}\n• Sector: {sector}\n• Country: {country}"
except:
return "ℹ️ Stock info not available"
# Create Gradio interface
with gr.Blocks(title="Stock Symbol GRU Predictor", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 📈 Stock Symbol GRU Predictor")
gr.Markdown("Enter a stock symbol to fetch historical data and get GRU model predictions.")
with gr.Row():
with gr.Column(scale=2):
symbol_input = gr.Textbox(
label="Stock Symbol",
placeholder="e.g., AAPL, RNO.PA, TSLA, MSFT",
value="RNO.PA"
)
predict_btn = gr.Button("🔮 Predict", variant="primary", size="lg")
info_btn = gr.Button("ℹ️ Get Stock Info", variant="secondary")
with gr.Column(scale=3):
output = gr.Textbox(
label="Prediction Results",
lines=15,
max_lines=20
)
info_output = gr.Textbox(
label="Stock Information",
lines=4
)
# Event handlers
predict_btn.click(predict_stock_symbol, inputs=symbol_input, outputs=output)
info_btn.click(get_stock_info, inputs=symbol_input, outputs=info_output)
# Example symbols
gr.Markdown("""
### 📋 Example Symbols:
• **US Stocks**: AAPL, MSFT, GOOGL, TSLA, AMZN
• **European**: RNO.PA (Renault), AIR.PA (Airbus), SAP (SAP SE)
• **Indices**: ^GSPC (S&P 500), ^IXIC (NASDAQ)
### 🔧 How it works:
1. Fetches last 90 days of stock data
2. Uses last 60 days as model input
3. Normalizes data (prices relative to first close, volume min-max)
4. Generates 10 prediction values using your GRU model
### ⚠️ Disclaimer:
This is for educational purposes only. Not financial advice.
""")
if __name__ == "__main__":
demo.launch()