import gradio as gr import yfinance as yf import pandas as pd import numpy as np import torch from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, T5Tokenizer from datetime import datetime, timedelta import plotly.graph_objects as go import plotly.express as px from plotly.subplots import make_subplots import warnings warnings.filterwarnings('ignore') import spaces # Import utility functions from utils import ( get_indonesian_stocks, calculate_technical_indicators, generate_trading_signals, get_fundamental_data, format_large_number, predict_prices, create_price_chart, create_technical_chart, create_prediction_chart ) from config import IDX_STOCKS, TECHNICAL_INDICATORS, PREDICTION_CONFIG # Load Chronos-Bolt model @spaces.GPU(duration=120) def load_model(): """Load the Amazon Chronos-Bolt model for time series forecasting""" # FIX 1: Use AutoModelForSeq2SeqLM and trust_remote_code=True (correct for T5-based model) model = AutoModelForSeq2SeqLM.from_pretrained( "amazon/chronos-bolt-base", torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True ) # FIX 2: Explicitly use T5Tokenizer (slow version) with trust_remote_code=True and use_fast=False # This bypasses the faulty AutoTokenizer/fast conversion logic. tokenizer = T5Tokenizer.from_pretrained( "amazon/chronos-bolt-base", trust_remote_code=True, use_fast=False ) return model, tokenizer # Initialize model model, tokenizer = load_model() def get_stock_data(symbol, period="1y"): """Fetch historical stock data using yfinance""" try: stock = yf.Ticker(symbol) data = stock.history(period=period) if data.empty: return None, None return data, stock except Exception as e: print(f"Error fetching data for {symbol}: {e}") return None, None def analyze_stock(symbol, prediction_days=30): """Main analysis function""" # Get stock data data, stock = get_stock_data(symbol) if data is None or stock is None: return None, None, None, None, None, None # Get fundamental data fundamental_info = get_fundamental_data(stock) # Calculate technical indicators indicators = calculate_technical_indicators(data) # Generate trading signals signals = generate_trading_signals(data, indicators) # Make predictions using Chronos-Bolt predictions = predict_prices(data, model, tokenizer, prediction_days) # Create charts price_chart = create_price_chart(data, indicators) technical_chart = create_technical_chart(data, indicators) prediction_chart = create_prediction_chart(data, predictions) return fundamental_info, indicators, signals, price_chart, technical_chart, prediction_chart def create_ui(): """Create the Gradio interface""" with gr.Blocks( title="IDX Stock Analysis & Prediction", theme=gr.themes.Soft(), css=""" .header { text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 20px; } .metric-card { background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 10px 0; } .positive { color: #10b981; font-weight: bold; } .negative { color: #ef4444; font-weight: bold; } .neutral { color: #6b7280; font-weight: bold; } """ ) as demo: with gr.Row(): gr.HTML("""

📈 IDX Stock Analysis & Prediction

Advanced Technical Analysis & AI-Powered Predictions for Indonesian Stock Exchange

Built with anycoder

""") with gr.Row(): with gr.Column(scale=2): stock_selector = gr.Dropdown( choices=list(IDX_STOCKS.keys()), value="BBCA.JK", label="📊 Select Indonesian Stock", info="Choose from top IDX stocks" ) with gr.Row(): prediction_days = gr.Slider( minimum=7, maximum=90, value=30, step=7, label="🔮 Prediction Days" ) analyze_btn = gr.Button( "🚀 Analyze Stock", variant="primary", size="lg" ) # Results sections with gr.Tabs() as tabs: # Tab 1: Stock Overview & Fundamentals with gr.TabItem("📊 Stock Overview"): with gr.Row(): company_name = gr.Textbox(label="Company Name", interactive=False) current_price = gr.Number(label="Current Price (IDR)", interactive=False) market_cap = gr.Textbox(label="Market Cap", interactive=False) with gr.Row(): pe_ratio = gr.Number(label="P/E Ratio", interactive=False) dividend_yield = gr.Number(label="Dividend Yield (%)", interactive=False) volume = gr.Number(label="Volume", interactive=False) fundamentals_text = gr.Textbox( label="📋 Company Information", lines=8, interactive=False ) # Tab 2: Technical Analysis with gr.TabItem("📈 Technical Analysis"): price_chart = gr.Plot(label="Price & Technical Indicators") technical_chart = gr.Plot(label="Technical Indicators Analysis") with gr.Row(): rsi_value = gr.Number(label="RSI (14)", interactive=False) macd_signal = gr.Textbox(label="MACD Signal", interactive=False) bb_position = gr.Textbox(label="Bollinger Band Position", interactive=False) # Tab 3: Trading Signals with gr.TabItem("🎯 Trading Signals"): with gr.Row(): overall_signal = gr.Textbox(label="🚦 Overall Signal", interactive=False, scale=2) signal_strength = gr.Slider( minimum=0, maximum=100, label="Signal Strength", interactive=False ) signals_text = gr.Textbox( label="📝 Detailed Signals", lines=10, interactive=False ) with gr.Row(): support_level = gr.Number(label="Support Level", interactive=False) resistance_level = gr.Number(label="Resistance Level", interactive=False) stop_loss = gr.Number(label="Recommended Stop Loss", interactive=False) # Tab 4: AI Predictions with gr.TabItem("🤖 AI Predictions"): prediction_chart = gr.Plot(label="Price Forecast (Chronos-Bolt)") with gr.Row(): predicted_high = gr.Number(label="Predicted High (30d)", interactive=False) predicted_low = gr.Number(label="Predicted Low (30d)", interactive=False) predicted_change = gr.Number(label="Expected Change (%)", interactive=False) prediction_summary = gr.Textbox( label="📊 Prediction Analysis", lines=5, interactive=False ) # Event handlers def update_analysis(symbol, pred_days): fundamental_info, indicators, signals, price_chart, technical_chart, prediction_chart = analyze_stock(symbol, pred_days) if fundamental_info is None: return { company_name: "Error loading data", current_price: 0, market_cap: "N/A", pe_ratio: 0, dividend_yield: 0, volume: 0, fundamentals_text: "Unable to fetch stock data. Please try another symbol.", rsi_value: 0, macd_signal: "N/A", bb_position: "N/A", overall_signal: "N/A", signal_strength: 0, signals_text: "No signals available", support_level: 0, resistance_level: 0, stop_loss: 0, predicted_high: 0, predicted_low: 0, predicted_change: 0, prediction_summary: "No predictions available", price_chart: None, technical_chart: None, prediction_chart: None } # Format outputs return { company_name: fundamental_info.get('name', 'N/A'), current_price: fundamental_info.get('current_price', 0), market_cap: format_large_number(fundamental_info.get('market_cap', 0)), pe_ratio: fundamental_info.get('pe_ratio', 0), dividend_yield: fundamental_info.get('dividend_yield', 0), volume: fundamental_info.get('volume', 0), fundamentals_text: fundamental_info.get('info', ''), rsi_value: indicators.get('rsi', {}).get('current', 0), macd_signal: indicators.get('macd', {}).get('signal', 'N/A'), bb_position: indicators.get('bollinger', {}).get('position', 'N/A'), overall_signal: signals.get('overall', 'HOLD'), signal_strength: signals.get('strength', 50), signals_text: signals.get('details', ''), support_level: signals.get('support', 0), resistance_level: signals.get('resistance', 0), stop_loss: signals.get('stop_loss', 0), predicted_high: indicators.get('predictions', {}).get('high_30d', 0), predicted_low: indicators.get('predictions', {}).get('low_30d', 0), predicted_change: indicators.get('predictions', {}).get('change_pct', 0), prediction_summary: indicators.get('predictions', {}).get('summary', ''), price_chart: price_chart, technical_chart: technical_chart, prediction_chart: prediction_chart } analyze_btn.click( fn=update_analysis, inputs=[stock_selector, prediction_days], outputs=[ company_name, current_price, market_cap, pe_ratio, dividend_yield, volume, fundamentals_text, rsi_value, macd_signal, bb_position, overall_signal, signal_strength, signals_text, support_level, resistance_level, stop_loss, predicted_high, predicted_low, predicted_change, prediction_summary, price_chart, technical_chart, prediction_chart ] ) # Load initial analysis demo.load( fn=update_analysis, inputs=[stock_selector, prediction_days], outputs=[ company_name, current_price, market_cap, pe_ratio, dividend_yield, volume, fundamentals_text, rsi_value, macd_signal, bb_position, overall_signal, signal_strength, signals_text, support_level, resistance_level, stop_loss, predicted_high, predicted_low, predicted_change, prediction_summary, price_chart, technical_chart, prediction_chart ] ) return demo if __name__ == "__main__": demo = create_ui() demo.launch()