Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -46,12 +46,12 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 46 |
# kalkulasi TP1, TP2, SL yang diperbarui berdasarkan quantiles/range prediksi
|
| 47 |
last_price = data['Close'].iloc[-1]
|
| 48 |
|
| 49 |
-
#
|
| 50 |
q05 = predictions.get('values', np.array([last_price]))
|
| 51 |
q01 = predictions.get('q01', np.array([last_price * 0.95]))
|
| 52 |
q09 = predictions.get('q09', np.array([last_price * 1.05]))
|
| 53 |
|
| 54 |
-
#
|
| 55 |
q05_max = np.max(q05) if q05.size > 0 else last_price
|
| 56 |
q09_max = np.max(q09) if q09.size > 0 else last_price * 1.05
|
| 57 |
q01_min = np.min(q01) if q01.size > 0 else last_price * 0.95
|
|
@@ -89,12 +89,13 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 89 |
empty_predictions = {
|
| 90 |
"high_30d": 0, "low_30d": 0, "change_pct": 0,
|
| 91 |
"summary": f"Prediction unavailable. Model error: {e}",
|
|
|
|
| 92 |
"q01": [], "q09": [],
|
| 93 |
"tp1": default_tp1, "tp2": default_tp2, "sl": default_sl,
|
| 94 |
}
|
| 95 |
empty_risk = {"error": "Prediction Model Failed to Load/Run. See console for details."}
|
| 96 |
|
| 97 |
-
#
|
| 98 |
return {}, {}, {}, empty_risk, None, None, None, empty_predictions
|
| 99 |
|
| 100 |
|
|
@@ -110,7 +111,7 @@ def update_analysis(symbol, prediction_days):
|
|
| 110 |
predictions,
|
| 111 |
) = analyze_stock(symbol, prediction_days)
|
| 112 |
|
| 113 |
-
#
|
| 114 |
if fig_price is None:
|
| 115 |
error_msg = f"Unable to run AI prediction or fetch data for {symbol.upper()}. Check the model logs for details."
|
| 116 |
tp_sl_info = f"<b>TP1:</b> Rp{predictions.get('tp1', 0):,.2f}<br><b>TP2:</b> Rp{predictions.get('tp2', 0):,.2f}<br><b>Stop Loss:</b> Rp{predictions.get('sl', 0):,.2f}<br><br><b>Model Insight:</b><br>{predictions.get('summary', 'Data fetching or model execution failed. Cannot proceed with analysis.')}"
|
|
@@ -122,8 +123,19 @@ def update_analysis(symbol, prediction_days):
|
|
| 122 |
None, # fig_prediction
|
| 123 |
)
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
# --- FUNDAMENTALS ---
|
| 126 |
-
# ... (code for fundamentals remains the same)
|
| 127 |
fundamentals = f"""
|
| 128 |
<h4>COMPANY FUNDAMENTALS</h4>
|
| 129 |
<b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
|
|
@@ -135,7 +147,6 @@ def update_analysis(symbol, prediction_days):
|
|
| 135 |
"""
|
| 136 |
|
| 137 |
# --- TECHNICAL SIGNAL ---
|
| 138 |
-
# ... (code for trading_signal remains the same)
|
| 139 |
details_list = "".join(
|
| 140 |
[f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
|
| 141 |
)
|
|
@@ -154,7 +165,6 @@ def update_analysis(symbol, prediction_days):
|
|
| 154 |
"""
|
| 155 |
|
| 156 |
# --- RISK METRICS ---
|
| 157 |
-
# ... (code for risk_report remains the same)
|
| 158 |
risk_details = ""
|
| 159 |
if "error" in risk_metrics:
|
| 160 |
risk_details = f"<b style='color: red;'>{risk_metrics['error']}</b>"
|
|
@@ -167,14 +177,7 @@ def update_analysis(symbol, prediction_days):
|
|
| 167 |
{risk_details}
|
| 168 |
"""
|
| 169 |
|
| 170 |
-
# --- AI FORECAST ---
|
| 171 |
-
# Perlu memastikan q01/q09 tidak kosong
|
| 172 |
-
q01_values = predictions.get('q01', [])
|
| 173 |
-
q09_values = predictions.get('q09', [])
|
| 174 |
-
|
| 175 |
-
band_min = float(min(q01_values)) if q01_values and len(q01_values) > 0 else 0
|
| 176 |
-
band_max = float(max(q09_values)) if q09_values and len(q09_values) > 0 else 0
|
| 177 |
-
|
| 178 |
prediction = f"""
|
| 179 |
<h4>{prediction_days}-DAY AI FORECAST (CHRONOS-2 + COVARIATES)</h4>
|
| 180 |
<b>Predicted Median High:</b> Rp{predictions.get('high_30d', 0):,.2f}<br>
|
|
|
|
| 46 |
# kalkulasi TP1, TP2, SL yang diperbarui berdasarkan quantiles/range prediksi
|
| 47 |
last_price = data['Close'].iloc[-1]
|
| 48 |
|
| 49 |
+
# Dapatkan array prediksi dengan fallback ke array yang berisi harga terakhir
|
| 50 |
q05 = predictions.get('values', np.array([last_price]))
|
| 51 |
q01 = predictions.get('q01', np.array([last_price * 0.95]))
|
| 52 |
q09 = predictions.get('q09', np.array([last_price * 1.05]))
|
| 53 |
|
| 54 |
+
# Robust max/min calculation
|
| 55 |
q05_max = np.max(q05) if q05.size > 0 else last_price
|
| 56 |
q09_max = np.max(q09) if q09.size > 0 else last_price * 1.05
|
| 57 |
q01_min = np.min(q01) if q01.size > 0 else last_price * 0.95
|
|
|
|
| 89 |
empty_predictions = {
|
| 90 |
"high_30d": 0, "low_30d": 0, "change_pct": 0,
|
| 91 |
"summary": f"Prediction unavailable. Model error: {e}",
|
| 92 |
+
# Menggunakan list kosong sebagai fallback jika error terjadi
|
| 93 |
"q01": [], "q09": [],
|
| 94 |
"tp1": default_tp1, "tp2": default_tp2, "sl": default_sl,
|
| 95 |
}
|
| 96 |
empty_risk = {"error": "Prediction Model Failed to Load/Run. See console for details."}
|
| 97 |
|
| 98 |
+
# Mengembalikan None untuk output plot Gradio untuk membersihkan plot
|
| 99 |
return {}, {}, {}, empty_risk, None, None, None, empty_predictions
|
| 100 |
|
| 101 |
|
|
|
|
| 111 |
predictions,
|
| 112 |
) = analyze_stock(symbol, prediction_days)
|
| 113 |
|
| 114 |
+
# Cek apakah ada plot yang None (berarti ada error)
|
| 115 |
if fig_price is None:
|
| 116 |
error_msg = f"Unable to run AI prediction or fetch data for {symbol.upper()}. Check the model logs for details."
|
| 117 |
tp_sl_info = f"<b>TP1:</b> Rp{predictions.get('tp1', 0):,.2f}<br><b>TP2:</b> Rp{predictions.get('tp2', 0):,.2f}<br><b>Stop Loss:</b> Rp{predictions.get('sl', 0):,.2f}<br><br><b>Model Insight:</b><br>{predictions.get('summary', 'Data fetching or model execution failed. Cannot proceed with analysis.')}"
|
|
|
|
| 123 |
None, # fig_prediction
|
| 124 |
)
|
| 125 |
|
| 126 |
+
# --- AI FORECAST ---
|
| 127 |
+
q01_values = predictions.get('q01', [])
|
| 128 |
+
q09_values = predictions.get('q09', [])
|
| 129 |
+
|
| 130 |
+
# FIX: Robust check untuk array NumPy/list kosong
|
| 131 |
+
# Konversi ke NumPy array dan periksa ukuran (.size > 0) untuk menghindari ValueError
|
| 132 |
+
q01_arr = np.array(q01_values)
|
| 133 |
+
q09_arr = np.array(q09_values)
|
| 134 |
+
|
| 135 |
+
band_min = float(np.min(q01_arr)) if q01_arr.size > 0 else 0
|
| 136 |
+
band_max = float(np.max(q09_arr)) if q09_arr.size > 0 else 0
|
| 137 |
+
|
| 138 |
# --- FUNDAMENTALS ---
|
|
|
|
| 139 |
fundamentals = f"""
|
| 140 |
<h4>COMPANY FUNDAMENTALS</h4>
|
| 141 |
<b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
|
|
|
|
| 147 |
"""
|
| 148 |
|
| 149 |
# --- TECHNICAL SIGNAL ---
|
|
|
|
| 150 |
details_list = "".join(
|
| 151 |
[f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
|
| 152 |
)
|
|
|
|
| 165 |
"""
|
| 166 |
|
| 167 |
# --- RISK METRICS ---
|
|
|
|
| 168 |
risk_details = ""
|
| 169 |
if "error" in risk_metrics:
|
| 170 |
risk_details = f"<b style='color: red;'>{risk_metrics['error']}</b>"
|
|
|
|
| 177 |
{risk_details}
|
| 178 |
"""
|
| 179 |
|
| 180 |
+
# --- AI FORECAST (Lanjutan) ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
prediction = f"""
|
| 182 |
<h4>{prediction_days}-DAY AI FORECAST (CHRONOS-2 + COVARIATES)</h4>
|
| 183 |
<b>Predicted Median High:</b> Rp{predictions.get('high_30d', 0):,.2f}<br>
|