omniverse1 commited on
Commit
c54bdd8
·
verified ·
1 Parent(s): 3686f17

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -74
app.py CHANGED
@@ -24,7 +24,8 @@ def analyze_stock(symbol, prediction_days=30):
24
  symbol = symbol.upper() + ".JK"
25
 
26
  stock = yf.Ticker(symbol)
27
- data = stock.history(period="6mo", interval="1d")
 
28
 
29
  if data.empty:
30
  raise ValueError("No price data available for this stock.")
@@ -57,8 +58,12 @@ def analyze_stock(symbol, prediction_days=30):
57
  "high_30d": 0,
58
  "low_30d": 0,
59
  "change_pct": 0,
60
- "summary": "Prediction unavailable.",
 
 
 
61
  }
 
62
  return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions
63
 
64
 
@@ -73,112 +78,165 @@ def update_analysis(symbol, prediction_days):
73
  predictions,
74
  ) = analyze_stock(symbol, prediction_days)
75
 
76
- if not fundamental_info:
 
 
77
  return (
78
- "Unable to fetch stock data.",
 
 
79
  gr.Plot.update(value=None),
80
  gr.Plot.update(value=None),
81
  gr.Plot.update(value=None),
82
  )
83
 
84
- fundamentals = f"""
85
- <h4>COMPANY FUNDAMENTALS</h4>
86
- <b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
87
- <b>Current Price:</b> Rp{fundamental_info.get('current_price', 0):,.2f}<br>
88
- <b>Market Cap:</b> {fundamental_info.get('market_cap', 0):,}<br>
89
- <b>P/E Ratio:</b> {fundamental_info.get('pe_ratio', 0):.2f}<br>
90
- <b>Dividend Yield:</b> {fundamental_info.get('dividend_yield', 0):.2f}%<br>
91
- <b>Volume:</b> {fundamental_info.get('volume', 0):,}<br>
 
92
  """
93
 
 
94
  details_list = "".join(
95
  [f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
96
  )
97
 
98
- trading_signal = f"""
99
- <h4>TECHNICAL SIGNAL SUMMARY</h4>
100
- <b>Overall Trend:</b> {signals.get('overall', 'N/A')}<br>
101
- <b>Signal Strength:</b> {signals.get('strength', 0):.2f}%<br>
102
- <b>Support:</b> Rp{signals.get('support', 0):,.2f}<br>
103
- <b>Resistance:</b> Rp{signals.get('resistance', 0):,.2f}<br>
104
- <b>Stop Loss:</b> Rp{signals.get('stop_loss', 0):,.2f}<br><br>
105
- <b>Detailed Signals:</b>
 
106
  <ul style="margin-top: 8px; padding-left: 20px; line-height: 1.6;">
107
  {details_list}
108
  </ul>
109
  """
110
 
111
- prediction = f"""
112
- <h4>30-DAY AI FORECAST (CHRONOS-BOLT)</h4>
113
- <b>Predicted High:</b> Rp{predictions.get('high_30d', 0):,.2f}<br>
114
- <b>Predicted Low:</b> Rp{predictions.get('low_30d', 0):,.2f}<br>
115
- <b>Expected Change:</b> {predictions.get('change_pct', 0):.2f}%<br><br>
116
- <b>TP1:</b> Rp{predictions.get('tp1', 0):,.2f}<br>
117
- <b>TP2:</b> Rp{predictions.get('tp2', 0):,.2f}<br>
118
- <b>Stop Loss:</b> Rp{predictions.get('sl', 0):,.2f}<br><br>
119
- <b>Model Insight:</b><br>{predictions.get('summary', 'No analysis available')}
 
 
 
 
 
120
  """
121
 
122
- # Karena custom CSS dihapus, kita akan menggunakan div sederhana tanpa class 'panel-box' dan 'triple-panel'
123
- # Gradio secara otomatis akan menata elemen-elemen ini dengan lebih standar
124
  return (
125
- f"""
126
- <div style="display: flex; flex-direction: row; gap: 16px;">
127
- <div style="flex: 1; min-width: 30%; border: 1px solid #ccc; padding: 10px; border-radius: 5px;">{fundamentals}</div>
128
- <div style="flex: 1; min-width: 30%; border: 1px solid #ccc; padding: 10px; border-radius: 5px;">{trading_signal}</div>
129
- <div style="flex: 1; min-width: 30%; border: 1px solid #ccc; padding: 10px; border-radius: 5px;">{prediction}</div>
130
- </div>
131
- """,
132
  fig_price,
133
  fig_technical,
134
  fig_prediction,
135
  )
136
 
137
 
138
- # --- Perubahan utama di sini ---
139
  with gr.Blocks(
140
- title="REXPRO FINANCIAL AI DASHBOARD"
141
- # Parameter theme dan css dihapus untuk kembali ke default Gradio
142
  ) as app:
143
  gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD")
144
  gr.Markdown(
145
- "Comprehensive stock analytics powered by **AI forecasting and technical analysis.**"
146
  )
147
-
148
- with gr.Row():
149
- symbol = gr.Textbox(
150
- label="STOCK SYMBOL (IDX)",
151
- value="BBCA",
152
- placeholder="Example: BBCA, TLKM, ADRO, BMRI",
153
- interactive=True,
154
- )
155
- prediction_days = gr.Slider(
156
- label="FORECAST PERIOD (DAYS)",
157
- minimum=5,
158
- maximum=60,
159
- step=5,
160
- value=30,
161
- interactive=True,
162
- )
163
- analyze_button = gr.Button("RUN ANALYSIS")
164
-
165
- gr.Markdown("---")
166
- # Bagian report_section diubah agar lebih kompatibel dengan tema default,
167
- # menggunakan sedikit inline CSS untuk meniru tata letak tiga kolom dasar.
168
- report_section = gr.HTML()
169
- gr.Markdown("---")
170
-
171
- with gr.Tab("MARKET CHARTS"):
172
- with gr.Row():
173
- price_chart = gr.Plot(label="PRICE & MOVING AVERAGES")
174
- technical_chart = gr.Plot(label="TECHNICAL INDICATORS OVERVIEW")
175
- gr.Markdown("---")
176
- prediction_chart = gr.Plot(label="AI FORECAST PROJECTION")
177
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  analyze_button.click(
179
  fn=update_analysis,
180
  inputs=[symbol, prediction_days],
181
- outputs=[report_section, price_chart, technical_chart, prediction_chart],
 
 
 
 
 
 
 
182
  )
183
 
184
  if __name__ == "__main__":
 
24
  symbol = symbol.upper() + ".JK"
25
 
26
  stock = yf.Ticker(symbol)
27
+ # Fetching data for a slightly longer period for better analysis base
28
+ data = stock.history(period="1y", interval="1d")
29
 
30
  if data.empty:
31
  raise ValueError("No price data available for this stock.")
 
58
  "high_30d": 0,
59
  "low_30d": 0,
60
  "change_pct": 0,
61
+ "summary": f"Error: {e}",
62
+ "tp1": 0,
63
+ "tp2": 0,
64
+ "sl": 0,
65
  }
66
+ # Mengembalikan string kosong untuk data yang akan ditampilkan di Markdown
67
  return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions
68
 
69
 
 
78
  predictions,
79
  ) = analyze_stock(symbol, prediction_days)
80
 
81
+ if not fundamental_info and "Error" in predictions.get("summary", ""):
82
+ # Jika terjadi error, kembalikan hasil error ke semua output
83
+ error_msg = f"**ERROR:** {predictions.get('summary')}"
84
  return (
85
+ gr.Markdown.update(value=error_msg),
86
+ gr.Markdown.update(value=error_msg),
87
+ gr.Markdown.update(value=error_msg),
88
  gr.Plot.update(value=None),
89
  gr.Plot.update(value=None),
90
  gr.Plot.update(value=None),
91
  )
92
 
93
+ # --- Formatting Fundamental Data ---
94
+ fundamentals_text = f"""
95
+ ### COMPANY FUNDAMENTALS
96
+ - **Name:** {fundamental_info.get('name', 'N/A')} ({symbol.upper()})
97
+ - **Current Price:** Rp{fundamental_info.get('current_price', 0):,.2f}
98
+ - **Market Cap:** {fundamental_info.get('market_cap', 0):,}
99
+ - **P/E Ratio:** {fundamental_info.get('pe_ratio', 0):.2f}
100
+ - **Dividend Yield:** {fundamental_info.get('dividend_yield', 0):.2f}%
101
+ - **Volume:** {fundamental_info.get('volume', 0):,}
102
  """
103
 
104
+ # --- Formatting Technical Signals ---
105
  details_list = "".join(
106
  [f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
107
  )
108
 
109
+ trading_signal_text = f"""
110
+ ### TECHNICAL SIGNAL SUMMARY
111
+ - **Overall Trend:** **{signals.get('overall', 'N/A')}**
112
+ - **Signal Strength:** {signals.get('strength', 0):.2f}%
113
+ - **Support:** Rp{signals.get('support', 0):,.2f}
114
+ - **Resistance:** Rp{signals.get('resistance', 0):,.2f}
115
+ - **Stop Loss:** Rp{signals.get('stop_loss', 0):,.2f}
116
+
117
+ #### Detailed Signals:
118
  <ul style="margin-top: 8px; padding-left: 20px; line-height: 1.6;">
119
  {details_list}
120
  </ul>
121
  """
122
 
123
+ # --- Formatting Prediction Data ---
124
+ prediction_text = f"""
125
+ ### 30-DAY AI FORECAST
126
+ - **Predicted High:** Rp{predictions.get('high_30d', 0):,.2f}
127
+ - **Predicted Low:** Rp{predictions.get('low_30d', 0):,.2f}
128
+ - **Expected Change:** **{predictions.get('change_pct', 0):.2f}%**
129
+
130
+ #### Trading Targets
131
+ - **TP1 (Target Price 1):** Rp{predictions.get('tp1', 0):,.2f}
132
+ - **TP2 (Target Price 2):** Rp{predictions.get('tp2', 0):,.2f}
133
+ - **Stop Loss:** Rp{predictions.get('sl', 0):,.2f}
134
+
135
+ #### Model Insight
136
+ > {predictions.get('summary', 'No analysis available')}
137
  """
138
 
 
 
139
  return (
140
+ gr.Markdown.update(value=fundamentals_text),
141
+ gr.Markdown.update(value=trading_signal_text),
142
+ gr.Markdown.update(value=prediction_text),
 
 
 
 
143
  fig_price,
144
  fig_technical,
145
  fig_prediction,
146
  )
147
 
148
 
149
+ # --- STRUKTUR UI BARU ---
150
  with gr.Blocks(
151
+ title="REXPRO FINANCIAL AI DASHBOARD",
152
+ # Menggunakan tema standar Gradio. Perbaikan layout yang membuat professional.
153
  ) as app:
154
  gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD")
155
  gr.Markdown(
156
+ "Aplikasi Analisis Saham Komprehensif IDX, didukung oleh **Peramalan AI (CHRONOS-BOLT)** dan Analisis Teknikal."
157
  )
158
+
159
+ # 1. Row Kontrol Utama
160
+ with gr.Row(variant="panel"): # Menggunakan panel untuk membedakan area kontrol
161
+ with gr.Column(scale=1):
162
+ symbol = gr.Textbox(
163
+ label="MASUKKAN SIMBOL SAHAM (IDX)",
164
+ value="BBCA",
165
+ placeholder="Contoh: BBCA, TLKM, ADRO, BMRI",
166
+ interactive=True,
167
+ show_label=True
168
+ )
169
+ with gr.Column(scale=1):
170
+ prediction_days = gr.Slider(
171
+ label="PERIODE PERAMALAN (HARI)",
172
+ minimum=5,
173
+ maximum=60,
174
+ step=5,
175
+ value=30,
176
+ interactive=True,
177
+ show_label=True
178
+ )
179
+ with gr.Column(min_width=150, scale=0):
180
+ # Tombol diletakkan di bawah input untuk tampilan yang lebih rapi
181
+ analyze_button = gr.Button("RUN ANALYSIS", size="lg")
182
+
183
+ # 2. Tab untuk Hasil
184
+ with gr.Tabs():
185
+ # Tab 1: Ringkasan Analisis (Textual)
186
+ with gr.TabItem("RINGKASAN & TARGET"):
187
+ # Menggunakan gr.Row untuk membuat 3 "kartu" atau kolom hasil
188
+ with gr.Row():
189
+ # Grup untuk Fundamental
190
+ with gr.Group():
191
+ fundamentals_output = gr.Markdown(
192
+ "Hasil Fundamental akan muncul di sini.",
193
+ elem_classes=["card"]
194
+ )
195
+ # Grup untuk Sinyal Teknikal
196
+ with gr.Group():
197
+ trading_signal_output = gr.Markdown(
198
+ "Ringkasan Sinyal Teknikal akan muncul di sini.",
199
+ elem_classes=["card"]
200
+ )
201
+ # Grup untuk Prediksi AI & Target
202
+ with gr.Group():
203
+ prediction_output = gr.Markdown(
204
+ "Hasil Peramalan AI & Target Trading akan muncul di sini.",
205
+ elem_classes=["card"]
206
+ )
207
+
208
+ # Tab 2: Grafik Analisis
209
+ with gr.TabItem("VISUALISASI GRAFIK"):
210
+ gr.Markdown("## Grafik Analisis Saham")
211
+
212
+ with gr.Row():
213
+ # Grafik 1: Harga & MA
214
+ with gr.Column(scale=1):
215
+ price_chart = gr.Plot(label="1. HARGA & RATA-RATA BERGERAK (MA)", height=450)
216
+
217
+ # Grafik 2: Indikator Teknikal
218
+ with gr.Column(scale=1):
219
+ technical_chart = gr.Plot(label="2. INDIKATOR TEKNIKAL UTAMA (RSI/MACD)", height=450)
220
+
221
+ gr.Markdown("---")
222
+
223
+ with gr.Row():
224
+ # Grafik 3: Prediksi AI
225
+ prediction_chart = gr.Plot(label="3. PROYEKSI PERAMALAN AI", height=500)
226
+
227
+
228
+ # Definisi Event Handler
229
  analyze_button.click(
230
  fn=update_analysis,
231
  inputs=[symbol, prediction_days],
232
+ outputs=[
233
+ fundamentals_output,
234
+ trading_signal_output,
235
+ prediction_output,
236
+ price_chart,
237
+ technical_chart,
238
+ prediction_chart,
239
+ ],
240
  )
241
 
242
  if __name__ == "__main__":