omniverse1 commited on
Commit
daab9d7
·
verified ·
1 Parent(s): 37a2367

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -109
app.py CHANGED
@@ -24,7 +24,7 @@ def analyze_stock(symbol, prediction_days=30):
24
  symbol = symbol.upper() + ".JK"
25
 
26
  stock = yf.Ticker(symbol)
27
- data = stock.history(period="1y", interval="1d")
28
 
29
  if data.empty:
30
  raise ValueError("No price data available for this stock.")
@@ -38,6 +38,7 @@ def analyze_stock(symbol, prediction_days=30):
38
  fig_technical = create_technical_chart(data, indicators)
39
  fig_prediction = create_prediction_chart(data, predictions)
40
 
 
41
  last_price = data['Close'].iloc[-1]
42
  tp1 = last_price * (1 + (predictions.get("change_pct", 0) / 200))
43
  tp2 = last_price * (1 + (predictions.get("change_pct", 0) / 100))
@@ -56,10 +57,7 @@ def analyze_stock(symbol, prediction_days=30):
56
  "high_30d": 0,
57
  "low_30d": 0,
58
  "change_pct": 0,
59
- "summary": f"Error: {e}",
60
- "tp1": 0,
61
- "tp2": 0,
62
- "sl": 0,
63
  }
64
  return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions
65
 
@@ -75,146 +73,112 @@ def update_analysis(symbol, prediction_days):
75
  predictions,
76
  ) = analyze_stock(symbol, prediction_days)
77
 
78
- if not fundamental_info and "Error" in predictions.get("summary", ""):
79
- error_msg = f"**ERROR:** {predictions.get('summary')}"
80
  return (
81
- gr.Markdown.update(value=error_msg),
82
- gr.Markdown.update(value=error_msg),
83
- gr.Markdown.update(value=error_msg),
84
  gr.Plot.update(value=None),
85
  gr.Plot.update(value=None),
86
  gr.Plot.update(value=None),
87
  )
88
 
89
- fundamentals_text = f"""
90
- ### COMPANY FUNDAMENTALS
91
- - **Name:** {fundamental_info.get('name', 'N/A')} ({symbol.upper()})
92
- - **Current Price:** Rp{fundamental_info.get('current_price', 0):,.2f}
93
- - **Market Cap:** {fundamental_info.get('market_cap', 0):,}
94
- - **P/E Ratio:** {fundamental_info.get('pe_ratio', 0):.2f}
95
- - **Dividend Yield:** {fundamental_info.get('dividend_yield', 0):.2f}%
96
- - **Volume:** {fundamental_info.get('volume', 0):,}
97
  """
98
 
99
  details_list = "".join(
100
  [f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
101
  )
102
 
103
- trading_signal_text = f"""
104
- ### TECHNICAL SIGNAL SUMMARY
105
- - **Overall Trend:** **{signals.get('overall', 'N/A')}**
106
- - **Signal Strength:** {signals.get('strength', 0):.2f}%
107
- - **Support:** Rp{signals.get('support', 0):,.2f}
108
- - **Resistance:** Rp{signals.get('resistance', 0):,.2f}
109
- - **Stop Loss:** Rp{signals.get('stop_loss', 0):,.2f}
110
-
111
- #### Detailed Signals:
112
  <ul style="margin-top: 8px; padding-left: 20px; line-height: 1.6;">
113
  {details_list}
114
  </ul>
115
  """
116
 
117
- prediction_text = f"""
118
- ### 30-DAY AI FORECAST
119
- - **Predicted High:** Rp{predictions.get('high_30d', 0):,.2f}
120
- - **Predicted Low:** Rp{predictions.get('low_30d', 0):,.2f}
121
- - **Expected Change:** **{predictions.get('change_pct', 0):.2f}%**
122
-
123
- #### Trading Targets
124
- - **TP1 (Target Price 1):** Rp{predictions.get('tp1', 0):,.2f}
125
- - **TP2 (Target Price 2):** Rp{predictions.get('tp2', 0):,.2f}
126
- - **Stop Loss:** Rp{predictions.get('sl', 0):,.2f}
127
-
128
- #### Model Insight
129
- > {predictions.get('summary', 'No analysis available')}
130
  """
131
 
 
 
132
  return (
133
- gr.Markdown.update(value=fundamentals_text),
134
- gr.Markdown.update(value=trading_signal_text),
135
- gr.Markdown.update(value=prediction_text),
 
 
 
 
136
  fig_price,
137
  fig_technical,
138
  fig_prediction,
139
  )
140
 
141
 
 
142
  with gr.Blocks(
143
- title="REXPRO FINANCIAL AI DASHBOARD",
 
144
  ) as app:
145
  gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD")
146
  gr.Markdown(
147
- "Aplikasi Analisis Saham Komprehensif IDX, didukung oleh **Peramalan AI (CHRONOS-BOLT)** dan Analisis Teknikal."
148
  )
149
-
150
- with gr.Row(variant="panel"):
151
- with gr.Column(scale=1):
152
- symbol = gr.Textbox(
153
- label="MASUKKAN SIMBOL SAHAM (IDX)",
154
- value="BBCA",
155
- placeholder="Contoh: BBCA, TLKM, ADRO, BMRI",
156
- interactive=True,
157
- show_label=True
158
- )
159
- with gr.Column(scale=1):
160
- prediction_days = gr.Slider(
161
- label="PERIODE PERAMALAN (HARI)",
162
- minimum=5,
163
- maximum=60,
164
- step=5,
165
- value=30,
166
- interactive=True,
167
- show_label=True
168
- )
169
- with gr.Column(min_width=150, scale=0):
170
- analyze_button = gr.Button("RUN ANALYSIS", size="lg")
171
-
172
- with gr.Tabs():
173
- with gr.TabItem("RINGKASAN & TARGET"):
174
- with gr.Row():
175
- with gr.Group():
176
- fundamentals_output = gr.Markdown(
177
- "Hasil Fundamental akan muncul di sini.",
178
- elem_classes=["card"]
179
- )
180
- with gr.Group():
181
- trading_signal_output = gr.Markdown(
182
- "Ringkasan Sinyal Teknikal akan muncul di sini.",
183
- elem_classes=["card"]
184
- )
185
- with gr.Group():
186
- prediction_output = gr.Markdown(
187
- "Hasil Peramalan AI & Target Trading akan muncul di sini.",
188
- elem_classes=["card"]
189
- )
190
-
191
- with gr.TabItem("VISUALISASI GRAFIK"):
192
- gr.Markdown("## Grafik Analisis Saham")
193
-
194
- with gr.Row():
195
- with gr.Column(scale=1):
196
- price_chart = gr.Plot(label="1. HARGA & RATA-RATA BERGERAK (MA)")
197
-
198
- with gr.Column(scale=1):
199
- technical_chart = gr.Plot(label="2. INDIKATOR TEKNIKAL UTAMA (RSI/MACD)")
200
-
201
- gr.Markdown("---")
202
-
203
- with gr.Row():
204
- prediction_chart = gr.Plot(label="3. PROYEKSI PERAMALAN AI")
205
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
  analyze_button.click(
208
  fn=update_analysis,
209
  inputs=[symbol, prediction_days],
210
- outputs=[
211
- fundamentals_output,
212
- trading_signal_output,
213
- prediction_output,
214
- price_chart,
215
- technical_chart,
216
- prediction_chart,
217
- ],
218
  )
219
 
220
  if __name__ == "__main__":
 
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.")
 
38
  fig_technical = create_technical_chart(data, indicators)
39
  fig_prediction = create_prediction_chart(data, predictions)
40
 
41
+ # kalkulasi TP1, TP2, SL
42
  last_price = data['Close'].iloc[-1]
43
  tp1 = last_price * (1 + (predictions.get("change_pct", 0) / 200))
44
  tp2 = last_price * (1 + (predictions.get("change_pct", 0) / 100))
 
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
 
 
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__":