Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import yfinance as yf | |
| from utils import ( | |
| calculate_technical_indicators, | |
| generate_trading_signals, | |
| get_fundamental_data, | |
| predict_prices, | |
| create_price_chart, | |
| create_technical_chart, | |
| create_prediction_chart, | |
| ) | |
| import warnings | |
| warnings.filterwarnings("ignore") | |
| def analyze_stock(symbol, prediction_days=30): | |
| try: | |
| if not symbol.strip(): | |
| raise ValueError("Please enter a valid stock symbol.") | |
| if not symbol.endswith(".JK"): | |
| symbol = symbol.upper() + ".JK" | |
| stock = yf.Ticker(symbol) | |
| data = stock.history(period="6mo", interval="1d") | |
| if data.empty: | |
| raise ValueError("No price data available for this stock.") | |
| indicators = calculate_technical_indicators(data) | |
| signals = generate_trading_signals(data, indicators) | |
| fundamental_info = get_fundamental_data(stock) | |
| predictions = predict_prices(data, prediction_days=prediction_days) | |
| fig_price = create_price_chart(data, indicators) | |
| fig_technical = create_technical_chart(data, indicators) | |
| fig_prediction = create_prediction_chart(data, predictions) | |
| return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction, predictions | |
| except Exception as e: | |
| print(f"Error analyzing {symbol}: {e}") | |
| empty_fig = gr.Plot.update(value=None) | |
| empty_predictions = { | |
| 'high_30d': 0, 'low_30d': 0, 'change_pct': 0, 'summary': 'Prediction unavailable.' | |
| } | |
| return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions | |
| def update_analysis(symbol, prediction_days): | |
| ( | |
| fundamental_info, | |
| indicators, | |
| signals, | |
| fig_price, | |
| fig_technical, | |
| fig_prediction, | |
| predictions, | |
| ) = analyze_stock(symbol, prediction_days) | |
| if not fundamental_info: | |
| return ( | |
| "β Unable to fetch stock data.", | |
| gr.Plot.update(value=None), | |
| gr.Plot.update(value=None), | |
| gr.Plot.update(value=None), | |
| "", | |
| "0", "0", "0", "" | |
| ) | |
| summary_text = f""" | |
| ### π’ {fundamental_info.get('name', 'N/A')} ({symbol.upper()}) | |
| **Current Price:** Rp{fundamental_info.get('current_price', 0):,.2f} | |
| **Market Cap:** {fundamental_info.get('market_cap', 0):,} | |
| **P/E Ratio:** {fundamental_info.get('pe_ratio', 0):.2f} | |
| **Dividend Yield:** {fundamental_info.get('dividend_yield', 0):.2f}% | |
| **Volume:** {fundamental_info.get('volume', 0):,} | |
| """ | |
| signal_text = f""" | |
| ### π Technical Trading Signal | |
| **Overall Signal:** {signals.get('overall', 'N/A')} | |
| **Strength:** {signals.get('strength', 0):.2f}% | |
| **Support:** {signals.get('support', 0):,.2f} | |
| **Resistance:** {signals.get('resistance', 0):,.2f} | |
| **Stop Loss:** {signals.get('stop_loss', 0):,.2f} | |
| **Signal Details:** | |
| {signals.get('details', '')} | |
| """ | |
| prediction_text = f""" | |
| ### π€ AI Forecast (Amazon Chronos-Bolt) | |
| **Predicted High (30d):** Rp{predictions.get('high_30d', 0):,.2f} | |
| **Predicted Low (30d):** Rp{predictions.get('low_30d', 0):,.2f} | |
| **Expected Change:** {predictions.get('change_pct', 0):.2f}% | |
| π§ **Model Insight:** | |
| {predictions.get('summary', 'No analysis available')} | |
| """ | |
| return ( | |
| summary_text, | |
| fig_price, | |
| fig_technical, | |
| fig_prediction, | |
| signal_text, | |
| f"{predictions.get('high_30d', 0):,.2f}", | |
| f"{predictions.get('low_30d', 0):,.2f}", | |
| f"{predictions.get('change_pct', 0):.2f}%", | |
| prediction_text, | |
| ) | |
| with gr.Blocks( | |
| title="AI Stock Forecast Dashboard", | |
| theme=gr.themes.Soft(primary_hue="blue", secondary_hue="gray"), | |
| css=""" | |
| #dashboard {padding: 20px; max-width: 1300px; margin: auto;} | |
| .gradio-container {font-family: 'Inter', sans-serif;} | |
| h1, h2, h3 {color: #1e293b;} | |
| .gr-button {font-weight: 600; border-radius: 8px;} | |
| .gr-markdown {background: #f8fafc; border-radius: 10px; padding: 15px;} | |
| """ | |
| ) as app: | |
| gr.Markdown("# β‘ AI Stock Analysis Dashboard β Chronos-Bolt Edition", elem_id="dashboard") | |
| gr.Markdown("Enter any **Indonesian stock ticker** (e.g., `BBCA`, `ADRO`, `TLKM`, `BMRI`) to get live market insights and AI-based 30-day forecasts.", elem_id="dashboard") | |
| with gr.Row(): | |
| symbol = gr.Textbox( | |
| label="Stock Symbol", | |
| value="BBCA", | |
| placeholder="Type e.g. BBCA, ADRO, TLKM ...", | |
| interactive=True, | |
| lines=1 | |
| ) | |
| prediction_days = gr.Slider( | |
| label="Prediction Period (Days)", | |
| minimum=5, | |
| maximum=60, | |
| step=5, | |
| value=30, | |
| interactive=True, | |
| ) | |
| analyze_button = gr.Button("π Analyze Stock") | |
| gr.Markdown("---") | |
| with gr.Row(): | |
| with gr.Column(): | |
| fundamentals_output = gr.Markdown(label="Fundamentals") | |
| with gr.Column(): | |
| signal_output = gr.Markdown(label="Trading Signals") | |
| gr.Markdown("---") | |
| with gr.Tab("π Charts Overview"): | |
| with gr.Row(): | |
| price_chart = gr.Plot(label="Price & Moving Averages") | |
| technical_chart = gr.Plot(label="Technical Indicators") | |
| gr.Markdown("---") | |
| prediction_chart = gr.Plot(label="AI Forecast Projection") | |
| with gr.Tab("π€ AI Forecast Results"): | |
| with gr.Row(): | |
| predicted_high = gr.Textbox(label="Predicted High (30d)") | |
| predicted_low = gr.Textbox(label="Predicted Low (30d)") | |
| predicted_change = gr.Textbox(label="Expected Change (%)") | |
| gr.Markdown("---") | |
| prediction_summary = gr.Markdown(label="Prediction Analysis") | |
| analyze_button.click( | |
| fn=update_analysis, | |
| inputs=[symbol, prediction_days], | |
| outputs=[ | |
| fundamentals_output, | |
| price_chart, | |
| technical_chart, | |
| prediction_chart, | |
| signal_output, | |
| predicted_high, | |
| predicted_low, | |
| predicted_change, | |
| prediction_summary, | |
| ], | |
| ) | |
| if __name__ == "__main__": | |
| app.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=True) | |