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,
calculate_advanced_risk_metrics
)
import warnings
import numpy as np
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="1y", 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)
risk_metrics = calculate_advanced_risk_metrics(data.copy())
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 yang diperbarui berdasarkan quantiles/range prediksi
last_price = data['Close'].iloc[-1]
# Dapatkan array prediksi dengan fallback ke array yang berisi harga terakhir
q05 = predictions.get('values', np.array([last_price]))
q01 = predictions.get('q01', np.array([last_price * 0.95]))
q09 = predictions.get('q09', np.array([last_price * 1.05]))
# Robust max/min calculation
q05_max = np.max(q05) if q05.size > 0 else last_price
q09_max = np.max(q09) if q09.size > 0 else last_price * 1.05
q01_min = np.min(q01) if q01.size > 0 else last_price * 0.95
# Target/SL calculation
tp1 = (last_price + q05_max) / 2
tp2 = q09_max
sl = q01_min
if tp1 > tp2:
tp1, tp2 = tp2, tp1
if sl > last_price:
sl = last_price * 0.95 # Fallback
predictions["tp1"] = tp1
predictions["tp2"] = tp2
predictions["sl"] = sl
return fundamental_info, indicators, signals, risk_metrics, fig_price, fig_technical, fig_prediction, predictions
except Exception as e:
print(f"Error analyzing {symbol}: {e}")
try:
stock = yf.Ticker(symbol)
data = stock.history(period="1d", interval="1d")
last_price = data['Close'].iloc[-1] if not data.empty else 0
except:
last_price = 0
default_tp1 = last_price * 1.01
default_tp2 = last_price * 1.02
default_sl = last_price * 0.95
empty_predictions = {
"high_30d": 0, "low_30d": 0, "change_pct": 0,
"summary": f"Prediction unavailable. Model error: {e}",
# Menggunakan list kosong sebagai fallback jika error terjadi
"q01": [], "q09": [],
"tp1": default_tp1, "tp2": default_tp2, "sl": default_sl,
}
empty_risk = {"error": "Prediction Model Failed to Load/Run. See console for details."}
# Mengembalikan None untuk output plot Gradio untuk membersihkan plot
return {}, {}, {}, empty_risk, None, None, None, empty_predictions
def update_analysis(symbol, prediction_days):
(
fundamental_info,
indicators,
signals,
risk_metrics,
fig_price,
fig_technical,
fig_prediction,
predictions,
) = analyze_stock(symbol, prediction_days)
# Cek apakah ada plot yang None (berarti ada error)
if fig_price is None:
error_msg = f"Unable to run AI prediction or fetch data for {symbol.upper()}. Check the model logs for details."
tp_sl_info = f"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', 'Data fetching or model execution failed. Cannot proceed with analysis.')}"
return (
f"""