Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import yfinance as yf | |
| from utils import ( | |
| calculate_technical_indicators, | |
| generate_trading_signals, | |
| get_fundamental_data, | |
| create_price_chart, | |
| create_technical_chart, | |
| create_prediction_chart, | |
| predict_prices, | |
| ) | |
| import numpy as np | |
| def analyze_stock(symbol, mode, pred_days): | |
| try: | |
| stock = yf.Ticker(symbol) | |
| data = stock.history(period="1y") | |
| if data.empty: | |
| msg = f"No data found for {symbol}. Check the symbol or try adding .JK (e.g., ADRO.JK)" | |
| return ( | |
| {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0}, | |
| {"overall": "N/A", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg}, | |
| None, None, None, None | |
| ) | |
| indicators = calculate_technical_indicators(data) | |
| signals = generate_trading_signals(data, indicators) | |
| fundamentals = get_fundamental_data(stock) | |
| fig_price = create_price_chart(data, indicators) | |
| fig_technical = create_technical_chart(data, indicators) | |
| if mode == "AI Prediction": | |
| prediction = predict_prices(data, prediction_days=pred_days) | |
| fig_prediction = create_prediction_chart(data, prediction) | |
| return fundamentals, signals, fig_price, fig_technical, fig_prediction, prediction | |
| else: | |
| return fundamentals, signals, fig_price, fig_technical, None, None | |
| except Exception as e: | |
| msg = f"Error analyzing {symbol}: {e}" | |
| return ( | |
| {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0}, | |
| {"overall": "Error", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg}, | |
| None, None, None, None | |
| ) | |
| def format_fundamental_output(f): | |
| return f""" | |
| <div class="card"> | |
| <h3>COMPANY FUNDAMENTALS</h3> | |
| <p><b>Name:</b> {f['name']}</p> | |
| <p><b>Current Price:</b> Rp{f['current_price']:,.2f}</p> | |
| <p><b>Market Cap:</b> {f['market_cap']:,}</p> | |
| <p><b>P/E Ratio:</b> {f['pe_ratio']:.2f}</p> | |
| <p><b>Dividend Yield:</b> {f['dividend_yield']:.2f}%</p> | |
| <p><b>Volume:</b> {f['volume']:,}</p> | |
| </div> | |
| """ | |
| def format_signal_output(s): | |
| details = s.get("details", "") | |
| detail_list = details.split("\n") if details else [] | |
| formatted_details = "<ul>" + "".join(f"<li>{d}</li>" for d in detail_list) + "</ul>" | |
| return f""" | |
| <div class="card"> | |
| <h3>TECHNICAL SIGNAL SUMMARY</h3> | |
| <p><b>Overall Trend:</b> {s.get('overall','N/A')}</p> | |
| <p><b>Signal Strength:</b> {s.get('strength',0):.2f}%</p> | |
| <p><b>Support:</b> Rp{s.get('support',0):,.2f}</p> | |
| <p><b>Resistance:</b> Rp{s.get('resistance',0):,.2f}</p> | |
| <p><b>Stop Loss:</b> Rp{s.get('stop_loss',0):,.2f}</p> | |
| <h4>Detailed Signals:</h4> | |
| {formatted_details} | |
| </div> | |
| """ | |
| def format_ai_output(p): | |
| if p is None or not isinstance(p, dict) or "values" not in p or len(p["values"]) == 0: | |
| return """ | |
| <div class="card"> | |
| <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3> | |
| <p>No AI prediction data available.</p> | |
| </div> | |
| """ | |
| tp1 = p["mean_30d"] * 0.97 | |
| tp2 = p["mean_30d"] * 1.02 | |
| sl = p["low_30d"] * 0.95 | |
| return f""" | |
| <div class="card"> | |
| <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3> | |
| <p><b>Predicted High:</b> Rp{p['high_30d']:,.2f}</p> | |
| <p><b>Predicted Low:</b> Rp{p['low_30d']:,.2f}</p> | |
| <p><b>Expected Change:</b> {p['change_pct']:.2f}%</p> | |
| <p><b>TP1:</b> Rp{tp1:,.2f}</p> | |
| <p><b>TP2:</b> Rp{tp2:,.2f}</p> | |
| <p><b>Stop Loss:</b> Rp{sl:,.2f}</p> | |
| <h4>Model Insight:</h4> | |
| <p style="font-size:13px;line-height:1.4;">{p['summary']}</p> | |
| </div> | |
| """ | |
| with gr.Blocks(css=""" | |
| body { font-family: 'Inter', sans-serif; background-color: #f9fafc; color: #222; } | |
| .gradio-container { max-width: 1300px; margin: auto; } | |
| h1 { text-align:center; color:#003366; margin-bottom:20px; } | |
| h3 { color:#003366; margin-bottom:8px; } | |
| .card { | |
| background: #ffffff; | |
| border-radius: 10px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.08); | |
| padding: 18px; | |
| margin: 5px; | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .row-flex { | |
| display: flex; | |
| flex-wrap: wrap; | |
| justify-content: space-between; | |
| gap: 10px; | |
| } | |
| ul { margin: 6px 0 0 20px; padding: 0; } | |
| li { margin-bottom: 4px; font-size: 14px; } | |
| """) as demo: | |
| gr.HTML("<h1>STOCK ANALYSIS DASHBOARD</h1>") | |
| with gr.Row(): | |
| stock_input = gr.Textbox(label="Enter Stock Symbol (e.g. BBCA.JK, ADRO.JK)", placeholder="Type stock symbol...") | |
| mode_input = gr.Radio(["Technical Analysis", "AI Prediction"], label="Select Analysis Mode", value="Technical Analysis") | |
| pred_days_input = gr.Slider(7, 60, value=30, step=1, label="Prediction Days (AI only)") | |
| analyze_button = gr.Button("Analyze", variant="primary") | |
| gr.HTML("<hr style='margin:20px 0;'>") | |
| with gr.Row(elem_classes="row-flex"): | |
| fundamentals_output = gr.HTML() | |
| signal_output = gr.HTML() | |
| ai_output = gr.HTML() | |
| gr.HTML("<hr style='margin:20px 0;'>") | |
| with gr.Row(): | |
| chart_price = gr.Plot(label="Price Chart") | |
| chart_technical = gr.Plot(label="Technical Chart") | |
| chart_prediction = gr.Plot(label="AI Prediction Chart") | |
| def run_analysis(symbol, mode, pred_days): | |
| fundamentals, signals, fig_price, fig_technical, fig_prediction, prediction = analyze_stock(symbol, mode, pred_days) | |
| return ( | |
| format_fundamental_output(fundamentals), | |
| format_signal_output(signals), | |
| format_ai_output(prediction) if mode == "AI Prediction" else "", | |
| fig_price, | |
| fig_technical, | |
| fig_prediction if mode == "AI Prediction" else None, | |
| ) | |
| analyze_button.click( | |
| fn=run_analysis, | |
| inputs=[stock_input, mode_input, pred_days_input], | |
| outputs=[fundamentals_output, signal_output, ai_output, chart_price, chart_technical, chart_prediction] | |
| ) | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |