omniverse1 commited on
Commit
380e150
·
verified ·
1 Parent(s): dbe373a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -192
app.py CHANGED
@@ -1,230 +1,125 @@
1
  import gradio as gr
2
- import pandas as pd
3
  import yfinance as yf
4
  from utils import (
5
  calculate_technical_indicators,
6
  generate_trading_signals,
7
  get_fundamental_data,
8
- predict_prices,
9
  create_price_chart,
10
  create_technical_chart,
11
  create_prediction_chart,
 
12
  )
13
- import warnings
14
-
15
- warnings.filterwarnings("ignore")
16
-
17
 
18
- def analyze_stock(symbol, prediction_days=30):
19
  try:
20
- if not symbol.strip():
21
- raise ValueError("Please enter a valid stock symbol.")
22
-
23
- if not symbol.endswith(".JK"):
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.")
31
 
32
  indicators = calculate_technical_indicators(data)
33
  signals = generate_trading_signals(data, indicators)
34
- fundamental_info = get_fundamental_data(stock)
35
- predictions = predict_prices(data, prediction_days=prediction_days)
36
 
37
  fig_price = create_price_chart(data, indicators)
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))
45
- sl = last_price * 0.95
46
-
47
- predictions["tp1"] = tp1
48
- predictions["tp2"] = tp2
49
- predictions["sl"] = sl
50
-
51
- return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction, predictions
52
 
 
 
 
 
 
 
53
  except Exception as e:
54
- print(f"Error analyzing {symbol}: {e}")
55
- empty_fig = gr.Plot.update(value=None)
56
- empty_predictions = {
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
-
65
- def update_analysis(symbol, prediction_days):
66
- (
67
- fundamental_info,
68
- indicators,
69
- signals,
70
- fig_price,
71
- fig_technical,
72
- fig_prediction,
73
- predictions,
74
- ) = analyze_stock(symbol, prediction_days)
75
-
76
- if not fundamental_info:
77
- return (
78
- "Unable to fetch stock data.",
79
- "No technical signals available.",
80
- "No prediction data available.",
81
- gr.Plot.update(value=None),
82
- gr.Plot.update(value=None),
83
- gr.Plot.update(value=None),
84
- )
85
-
86
- fundamentals = f"""
87
- <h4>COMPANY FUNDAMENTALS</h4>
88
- <b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
89
- <b>Current Price:</b> Rp{fundamental_info.get('current_price', 0):,.2f}<br>
90
- <b>Market Cap:</b> {fundamental_info.get('market_cap', 0):,}<br>
91
- <b>P/E Ratio:</b> {fundamental_info.get('pe_ratio', 0):.2f}<br>
92
- <b>Dividend Yield:</b> {fundamental_info.get('dividend_yield', 0):.2f}%<br>
93
- <b>Volume:</b> {fundamental_info.get('volume', 0):,}<br>
94
  """
95
 
96
- details_list = "".join(
97
- [f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
98
- )
99
 
100
- trading_signal = f"""
101
- <h4>TECHNICAL SIGNAL SUMMARY</h4>
102
- <b>Overall Trend:</b> {signals.get('overall', 'N/A')}<br>
103
- <b>Signal Strength:</b> {signals.get('strength', 0):.2f}%<br>
104
- <b>Support:</b> Rp{signals.get('support', 0):,.2f}<br>
105
- <b>Resistance:</b> Rp{signals.get('resistance', 0):,.2f}<br>
106
- <b>Stop Loss:</b> Rp{signals.get('stop_loss', 0):,.2f}<br><br>
107
- <b>Detailed Signals:</b>
108
- <ul style="margin-top: 8px; padding-left: 20px; line-height: 1.6;">
109
- {details_list}
110
- </ul>
111
  """
112
 
113
- prediction = f"""
114
- <h4>30-DAY AI FORECAST (CHRONOS-BOLT)</h4>
115
- <b>Predicted High:</b> Rp{predictions.get('high_30d', 0):,.2f}<br>
116
- <b>Predicted Low:</b> Rp{predictions.get('low_30d', 0):,.2f}<br>
117
- <b>Expected Change:</b> {predictions.get('change_pct', 0):.2f}%<br><br>
118
- <b>TP1:</b> Rp{predictions.get('tp1', 0):,.2f}<br>
119
- <b>TP2:</b> Rp{predictions.get('tp2', 0):,.2f}<br>
120
- <b>Stop Loss:</b> Rp{predictions.get('sl', 0):,.2f}<br><br>
121
- <b>Model Insight:</b><br>{predictions.get('summary', 'No analysis available')}
122
- """
123
 
124
- return (
125
- f"""
126
- <div class='triple-panel'>
127
- <div class='panel-box'>{fundamentals}</div>
128
- <div class='panel-box'>{trading_signal}</div>
129
- <div class='panel-box'>{prediction}</div>
130
- </div>
131
- """,
132
- fig_price,
133
- fig_technical,
134
- fig_prediction,
135
- )
 
 
 
 
136
 
137
 
138
- with gr.Blocks(
139
- title="REXPRO FINANCIAL AI DASHBOARD",
140
- theme=gr.themes.Soft(primary_hue="blue", secondary_hue="gray"),
141
- css="""
142
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
143
- body {
144
- background-color: #f9fafb;
145
- color: #1e293b;
146
- font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
147
- }
148
- h1 {
149
- color: #1e40af;
150
- text-align: center;
151
- font-weight: 700;
152
- letter-spacing: 0.5px;
153
- }
154
- h2, h3, h4 {
155
- color: #1e3a8a;
156
- font-weight: 600;
157
- margin-bottom: 6px;
158
- }
159
- .gr-button {
160
- background-color: #2563eb !important;
161
- color: white !important;
162
- font-weight: 600;
163
- border-radius: 8px;
164
- padding: 10px 18px;
165
- }
166
- .panel-box {
167
- background-color: #ffffff;
168
- border-radius: 10px;
169
- border: 1px solid #e2e8f0;
170
- padding: 16px;
171
- flex: 1;
172
- min-width: 30%;
173
- }
174
- .triple-panel {
175
- display: flex;
176
- flex-direction: row;
177
- justify-content: space-between;
178
- gap: 16px;
179
- width: 100%;
180
- }
181
- ul { margin: 0; padding: 0 0 0 18px; }
182
- li { margin-bottom: 4px; }
183
- .gr-plot {
184
- background-color: #ffffff;
185
- border: 1px solid #e2e8f0;
186
- border-radius: 10px;
187
- }
188
- """,
189
- ) as app:
190
- gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD")
191
- gr.Markdown(
192
- "Comprehensive stock analytics powered by **AI forecasting and technical analysis.**"
193
- )
194
 
195
  with gr.Row():
196
- symbol = gr.Textbox(
197
- label="STOCK SYMBOL (IDX)",
198
- value="BBCA",
199
- placeholder="Example: BBCA, TLKM, ADRO, BMRI",
200
- interactive=True,
201
- )
202
- prediction_days = gr.Slider(
203
- label="FORECAST PERIOD (DAYS)",
204
- minimum=5,
205
- maximum=60,
206
- step=5,
207
- value=30,
208
- interactive=True,
209
- )
210
- analyze_button = gr.Button("RUN ANALYSIS")
211
 
212
- gr.Markdown("---")
213
- report_section = gr.HTML()
214
- gr.Markdown("---")
 
215
 
216
- with gr.Tab("MARKET CHARTS"):
217
- with gr.Row():
218
- price_chart = gr.Plot(label="PRICE & MOVING AVERAGES")
219
- technical_chart = gr.Plot(label="TECHNICAL INDICATORS OVERVIEW")
220
- gr.Markdown("---")
221
- prediction_chart = gr.Plot(label="AI FORECAST PROJECTION")
 
 
 
 
 
 
 
 
 
 
 
222
 
223
  analyze_button.click(
224
- fn=update_analysis,
225
- inputs=[symbol, prediction_days],
226
- outputs=[report_section, price_chart, technical_chart, prediction_chart],
227
  )
228
 
229
- if __name__ == "__main__":
230
- app.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=True)
 
1
  import gradio as gr
 
2
  import yfinance as yf
3
  from utils import (
4
  calculate_technical_indicators,
5
  generate_trading_signals,
6
  get_fundamental_data,
 
7
  create_price_chart,
8
  create_technical_chart,
9
  create_prediction_chart,
10
+ predict_prices,
11
  )
12
+ import pandas as pd
 
 
 
13
 
14
+ def analyze_stock(symbol, mode, pred_days):
15
  try:
 
 
 
 
 
 
16
  stock = yf.Ticker(symbol)
17
+ data = stock.history(period="1y")
 
18
  if data.empty:
19
+ return "No data found", None, None, None
20
 
21
  indicators = calculate_technical_indicators(data)
22
  signals = generate_trading_signals(data, indicators)
23
+ fundamentals = get_fundamental_data(stock)
 
24
 
25
  fig_price = create_price_chart(data, indicators)
26
  fig_technical = create_technical_chart(data, indicators)
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ if mode == "AI Prediction":
29
+ prediction = predict_prices(data, prediction_days=pred_days)
30
+ fig_prediction = create_prediction_chart(data, prediction)
31
+ return fundamentals, signals, fig_price, fig_technical, fig_prediction, prediction
32
+ else:
33
+ return fundamentals, signals, fig_price, fig_technical, None, None
34
  except Exception as e:
35
+ return f"Error analyzing {symbol}: {e}", None, None, None, None, None
36
+
37
+
38
+ def format_fundamental_output(f):
39
+ return f"""
40
+ <h3>COMPANY FUNDAMENTALS</h3>
41
+ <b>Name:</b> {f['name']}<br>
42
+ <b>Current Price:</b> Rp{f['current_price']:,.2f}<br>
43
+ <b>Market Cap:</b> {f['market_cap']:,}<br>
44
+ <b>P/E Ratio:</b> {f['pe_ratio']:.2f}<br>
45
+ <b>Dividend Yield:</b> {f['dividend_yield']:.2f}%<br>
46
+ <b>Volume:</b> {f['volume']:,}<br>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  """
48
 
 
 
 
49
 
50
+ def format_signal_output(s):
51
+ details = s["details"].split("\n")
52
+ formatted_details = "<ul>" + "".join(f"<li>{d}</li>" for d in details) + "</ul>"
53
+ return f"""
54
+ <h3>TECHNICAL SIGNAL SUMMARY</h3>
55
+ <b>Overall Trend:</b> {s['overall']}<br>
56
+ <b>Signal Strength:</b> {s['strength']:.2f}%<br>
57
+ <b>Support:</b> Rp{s['support']:,.2f}<br>
58
+ <b>Resistance:</b> Rp{s['resistance']:,.2f}<br>
59
+ <b>Stop Loss:</b> Rp{s['stop_loss']:,.2f}<br>
60
+ <br><b>Detailed Signals:</b>{formatted_details}
61
  """
62
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ def format_ai_output(p):
65
+ if not p:
66
+ return ""
67
+ tp1 = p["mean_30d"] * 0.97
68
+ tp2 = p["mean_30d"] * 1.02
69
+ sl = p["low_30d"] * 0.95
70
+ return f"""
71
+ <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3>
72
+ <b>Predicted High:</b> Rp{p['high_30d']:,.2f}<br>
73
+ <b>Predicted Low:</b> Rp{p['low_30d']:,.2f}<br>
74
+ <b>Expected Change:</b> {p['change_pct']:.2f}%<br><br>
75
+ <b>TP1:</b> Rp{tp1:,.2f}<br>
76
+ <b>TP2:</b> Rp{tp2:,.2f}<br>
77
+ <b>Stop Loss:</b> Rp{sl:,.2f}<br><br>
78
+ <b>Model Insight:</b><br>{p['summary']}
79
+ """
80
 
81
 
82
+ with gr.Blocks(css="""
83
+ body { font-family: 'Inter', sans-serif; background-color: #f9fafc; color: #222; }
84
+ .gradio-container { max-width: 1200px; margin: auto; }
85
+ h3 { color: #003366; border-bottom: 2px solid #d3d3d3; padding-bottom: 5px; }
86
+ .panel-box { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
87
+ """) as demo:
88
+ gr.HTML("<h1 style='text-align:center;color:#003366;'>📈 STOCK ANALYSIS DASHBOARD</h1>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  with gr.Row():
91
+ stock_input = gr.Textbox(label="Enter Stock Symbol (e.g. BBCA.JK, ADRO.JK)", placeholder="Type your stock symbol here...")
92
+ mode_input = gr.Radio(["Technical Analysis", "AI Prediction"], label="Select Analysis Mode", value="Technical Analysis")
93
+ pred_days_input = gr.Slider(7, 60, value=30, step=1, label="Prediction Days (for AI mode only)")
94
+ analyze_button = gr.Button("Analyze")
 
 
 
 
 
 
 
 
 
 
 
95
 
96
+ with gr.Row():
97
+ fundamentals_output = gr.HTML()
98
+ signal_output = gr.HTML()
99
+ ai_output = gr.HTML()
100
 
101
+ with gr.Row():
102
+ chart_price = gr.Plot(label="Price Chart")
103
+ chart_technical = gr.Plot(label="Technical Chart")
104
+ chart_prediction = gr.Plot(label="AI Prediction Chart")
105
+
106
+ def run_analysis(symbol, mode, pred_days):
107
+ fundamentals, signals, fig_price, fig_technical, fig_prediction, prediction = analyze_stock(symbol, mode, pred_days)
108
+ if isinstance(fundamentals, str):
109
+ return fundamentals, "", "", None, None, None
110
+ return (
111
+ format_fundamental_output(fundamentals),
112
+ format_signal_output(signals),
113
+ format_ai_output(prediction) if mode == "AI Prediction" else "",
114
+ fig_price,
115
+ fig_technical,
116
+ fig_prediction if mode == "AI Prediction" else None
117
+ )
118
 
119
  analyze_button.click(
120
+ fn=run_analysis,
121
+ inputs=[stock_input, mode_input, pred_days_input],
122
+ outputs=[fundamentals_output, signal_output, ai_output, chart_price, chart_technical, chart_prediction]
123
  )
124
 
125
+ demo.launch(server_name="0.0.0.0", server_port=7860)