Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -9,11 +9,10 @@ from utils import (
|
|
| 9 |
create_price_chart,
|
| 10 |
create_technical_chart,
|
| 11 |
create_prediction_chart,
|
| 12 |
-
# Import fungsi baru
|
| 13 |
calculate_advanced_risk_metrics
|
| 14 |
)
|
| 15 |
import warnings
|
| 16 |
-
import numpy as np
|
| 17 |
|
| 18 |
warnings.filterwarnings("ignore")
|
| 19 |
|
|
@@ -27,21 +26,17 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 27 |
symbol = symbol.upper() + ".JK"
|
| 28 |
|
| 29 |
stock = yf.Ticker(symbol)
|
| 30 |
-
# Menggunakan periode 1 tahun untuk metrik risiko yang lebih relevan
|
| 31 |
data = stock.history(period="1y", interval="1d")
|
| 32 |
|
| 33 |
if data.empty:
|
| 34 |
raise ValueError("No price data available for this stock.")
|
| 35 |
|
| 36 |
-
# Menghitung Indikator Teknikal (Ini juga akan mengisi kolom RSI/MACD ke 'data')
|
| 37 |
indicators = calculate_technical_indicators(data)
|
| 38 |
signals = generate_trading_signals(data, indicators)
|
| 39 |
fundamental_info = get_fundamental_data(stock)
|
| 40 |
|
| 41 |
-
# Menghitung Metrik Risiko Tingkat Lanjut
|
| 42 |
risk_metrics = calculate_advanced_risk_metrics(data.copy())
|
| 43 |
|
| 44 |
-
# Prediksi Chronos-2 dengan Covariates
|
| 45 |
predictions = predict_prices(data, prediction_days=prediction_days)
|
| 46 |
|
| 47 |
fig_price = create_price_chart(data, indicators)
|
|
@@ -51,19 +46,21 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 51 |
# kalkulasi TP1, TP2, SL yang diperbarui berdasarkan quantiles/range prediksi
|
| 52 |
last_price = data['Close'].iloc[-1]
|
| 53 |
|
| 54 |
-
#
|
| 55 |
-
q05 = predictions.get('values', [last_price])
|
| 56 |
-
q01 = predictions.get('q01', [last_price * 0.95])
|
| 57 |
-
q09 = predictions.get('q09', [last_price * 1.05])
|
| 58 |
|
| 59 |
-
#
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
# Pastikan TP1 < TP2 dan SL lebih rendah dari TP
|
| 67 |
if tp1 > tp2:
|
| 68 |
tp1, tp2 = tp2, tp1
|
| 69 |
if sl > last_price:
|
|
@@ -73,12 +70,10 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 73 |
predictions["tp2"] = tp2
|
| 74 |
predictions["sl"] = sl
|
| 75 |
|
| 76 |
-
# Menambahkan risk_metrics ke return
|
| 77 |
return fundamental_info, indicators, signals, risk_metrics, fig_price, fig_technical, fig_prediction, predictions
|
| 78 |
|
| 79 |
except Exception as e:
|
| 80 |
print(f"Error analyzing {symbol}: {e}")
|
| 81 |
-
empty_fig = gr.Plot.update(value=None)
|
| 82 |
|
| 83 |
try:
|
| 84 |
stock = yf.Ticker(symbol)
|
|
@@ -97,8 +92,10 @@ def analyze_stock(symbol, prediction_days=30):
|
|
| 97 |
"q01": [], "q09": [],
|
| 98 |
"tp1": default_tp1, "tp2": default_tp2, "sl": default_sl,
|
| 99 |
}
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
| 102 |
|
| 103 |
|
| 104 |
def update_analysis(symbol, prediction_days):
|
|
@@ -106,25 +103,27 @@ def update_analysis(symbol, prediction_days):
|
|
| 106 |
fundamental_info,
|
| 107 |
indicators,
|
| 108 |
signals,
|
| 109 |
-
risk_metrics,
|
| 110 |
fig_price,
|
| 111 |
fig_technical,
|
| 112 |
fig_prediction,
|
| 113 |
predictions,
|
| 114 |
) = analyze_stock(symbol, prediction_days)
|
| 115 |
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
|
|
|
| 119 |
|
| 120 |
return (
|
| 121 |
f"""<div style="color: red; padding: 10px; border: 1px solid red; border-radius: 5px;">{error_msg}</div><br>{tp_sl_info}""",
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
)
|
| 126 |
|
| 127 |
# --- FUNDAMENTALS ---
|
|
|
|
| 128 |
fundamentals = f"""
|
| 129 |
<h4>COMPANY FUNDAMENTALS</h4>
|
| 130 |
<b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
|
|
@@ -136,6 +135,7 @@ def update_analysis(symbol, prediction_days):
|
|
| 136 |
"""
|
| 137 |
|
| 138 |
# --- TECHNICAL SIGNAL ---
|
|
|
|
| 139 |
details_list = "".join(
|
| 140 |
[f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
|
| 141 |
)
|
|
@@ -154,6 +154,7 @@ def update_analysis(symbol, prediction_days):
|
|
| 154 |
"""
|
| 155 |
|
| 156 |
# --- RISK METRICS ---
|
|
|
|
| 157 |
risk_details = ""
|
| 158 |
if "error" in risk_metrics:
|
| 159 |
risk_details = f"<b style='color: red;'>{risk_metrics['error']}</b>"
|
|
@@ -167,8 +168,12 @@ def update_analysis(symbol, prediction_days):
|
|
| 167 |
"""
|
| 168 |
|
| 169 |
# --- AI FORECAST ---
|
| 170 |
-
|
| 171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
prediction = f"""
|
| 174 |
<h4>{prediction_days}-DAY AI FORECAST (CHRONOS-2 + COVARIATES)</h4>
|
|
|
|
| 9 |
create_price_chart,
|
| 10 |
create_technical_chart,
|
| 11 |
create_prediction_chart,
|
|
|
|
| 12 |
calculate_advanced_risk_metrics
|
| 13 |
)
|
| 14 |
import warnings
|
| 15 |
+
import numpy as np
|
| 16 |
|
| 17 |
warnings.filterwarnings("ignore")
|
| 18 |
|
|
|
|
| 26 |
symbol = symbol.upper() + ".JK"
|
| 27 |
|
| 28 |
stock = yf.Ticker(symbol)
|
|
|
|
| 29 |
data = stock.history(period="1y", interval="1d")
|
| 30 |
|
| 31 |
if data.empty:
|
| 32 |
raise ValueError("No price data available for this stock.")
|
| 33 |
|
|
|
|
| 34 |
indicators = calculate_technical_indicators(data)
|
| 35 |
signals = generate_trading_signals(data, indicators)
|
| 36 |
fundamental_info = get_fundamental_data(stock)
|
| 37 |
|
|
|
|
| 38 |
risk_metrics = calculate_advanced_risk_metrics(data.copy())
|
| 39 |
|
|
|
|
| 40 |
predictions = predict_prices(data, prediction_days=prediction_days)
|
| 41 |
|
| 42 |
fig_price = create_price_chart(data, indicators)
|
|
|
|
| 46 |
# kalkulasi TP1, TP2, SL yang diperbarui berdasarkan quantiles/range prediksi
|
| 47 |
last_price = data['Close'].iloc[-1]
|
| 48 |
|
| 49 |
+
# FIX 3: 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 |
+
# FIX 3: 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
|
| 58 |
+
|
| 59 |
+
# Target/SL calculation
|
| 60 |
+
tp1 = (last_price + q05_max) / 2
|
| 61 |
+
tp2 = q09_max
|
| 62 |
+
sl = q01_min
|
| 63 |
|
|
|
|
| 64 |
if tp1 > tp2:
|
| 65 |
tp1, tp2 = tp2, tp1
|
| 66 |
if sl > last_price:
|
|
|
|
| 70 |
predictions["tp2"] = tp2
|
| 71 |
predictions["sl"] = sl
|
| 72 |
|
|
|
|
| 73 |
return fundamental_info, indicators, signals, risk_metrics, fig_price, fig_technical, fig_prediction, predictions
|
| 74 |
|
| 75 |
except Exception as e:
|
| 76 |
print(f"Error analyzing {symbol}: {e}")
|
|
|
|
| 77 |
|
| 78 |
try:
|
| 79 |
stock = yf.Ticker(symbol)
|
|
|
|
| 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 |
+
# FIX 4: Mengembalikan None untuk output plot Gradio untuk membersihkan plot
|
| 98 |
+
return {}, {}, {}, empty_risk, None, None, None, empty_predictions
|
| 99 |
|
| 100 |
|
| 101 |
def update_analysis(symbol, prediction_days):
|
|
|
|
| 103 |
fundamental_info,
|
| 104 |
indicators,
|
| 105 |
signals,
|
| 106 |
+
risk_metrics,
|
| 107 |
fig_price,
|
| 108 |
fig_technical,
|
| 109 |
fig_prediction,
|
| 110 |
predictions,
|
| 111 |
) = analyze_stock(symbol, prediction_days)
|
| 112 |
|
| 113 |
+
# FIX 4: Cek apakah ada plot yang None (berarti ada error)
|
| 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.')}"
|
| 117 |
|
| 118 |
return (
|
| 119 |
f"""<div style="color: red; padding: 10px; border: 1px solid red; border-radius: 5px;">{error_msg}</div><br>{tp_sl_info}""",
|
| 120 |
+
None, # fig_price
|
| 121 |
+
None, # fig_technical
|
| 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 |
"""
|
| 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 |
"""
|
| 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>"
|
|
|
|
| 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>
|