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) # kalkulasi TP1, TP2, SL last_price = data['Close'].iloc[-1] tp1 = last_price * (1 + (predictions.get("change_pct", 0) / 200)) tp2 = last_price * (1 + (predictions.get("change_pct", 0) / 100)) sl = last_price * 0.95 predictions["tp1"] = tp1 predictions["tp2"] = tp2 predictions["sl"] = sl 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), ) fundamentals = f"""

COMPANY FUNDAMENTALS

Name: {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):,}
""" details_list = "".join( [f"
  • {line.strip()}
  • " for line in signals.get("details", "").split("\n") if line.strip()] ) trading_signal = f"""

    TECHNICAL SIGNAL SUMMARY

    Overall Trend: {signals.get('overall', 'N/A')}
    Signal Strength: {signals.get('strength', 0):.2f}%
    Support: Rp{signals.get('support', 0):,.2f}
    Resistance: Rp{signals.get('resistance', 0):,.2f}
    Stop Loss: Rp{signals.get('stop_loss', 0):,.2f}

    Detailed Signals: """ prediction = f"""

    30-DAY AI FORECAST (CHRONOS-BOLT)

    Predicted High: Rp{predictions.get('high_30d', 0):,.2f}
    Predicted Low: Rp{predictions.get('low_30d', 0):,.2f}
    Expected Change: {predictions.get('change_pct', 0):.2f}%

    TP1: Rp{predictions.get('tp1', 0):,.2f}
    TP2: Rp{predictions.get('tp2', 0):,.2f}
    Stop Loss: Rp{predictions.get('sl', 0):,.2f}

    Model Insight:
    {predictions.get('summary', 'No analysis available')} """ # Karena custom CSS dihapus, kita akan menggunakan div sederhana tanpa class 'panel-box' dan 'triple-panel' # Gradio secara otomatis akan menata elemen-elemen ini dengan lebih standar return ( f"""
    {fundamentals}
    {trading_signal}
    {prediction}
    """, fig_price, fig_technical, fig_prediction, ) # --- Perubahan utama di sini --- with gr.Blocks( title="REXPRO FINANCIAL AI DASHBOARD" # Parameter theme dan css dihapus untuk kembali ke default Gradio ) as app: gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD") gr.Markdown( "Comprehensive stock analytics powered by **AI forecasting and technical analysis.**" ) with gr.Row(): symbol = gr.Textbox( label="STOCK SYMBOL (IDX)", value="BBCA", placeholder="Example: BBCA, TLKM, ADRO, BMRI", interactive=True, ) prediction_days = gr.Slider( label="FORECAST PERIOD (DAYS)", minimum=5, maximum=60, step=5, value=30, interactive=True, ) analyze_button = gr.Button("RUN ANALYSIS") gr.Markdown("---") # Bagian report_section diubah agar lebih kompatibel dengan tema default, # menggunakan sedikit inline CSS untuk meniru tata letak tiga kolom dasar. report_section = gr.HTML() gr.Markdown("---") with gr.Tab("MARKET CHARTS"): with gr.Row(): price_chart = gr.Plot(label="PRICE & MOVING AVERAGES") technical_chart = gr.Plot(label="TECHNICAL INDICATORS OVERVIEW") gr.Markdown("---") prediction_chart = gr.Plot(label="AI FORECAST PROJECTION") analyze_button.click( fn=update_analysis, inputs=[symbol, prediction_days], outputs=[report_section, price_chart, technical_chart, prediction_chart], ) if __name__ == "__main__": app.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=True)