omniverse1 commited on
Commit
65d5f73
Β·
verified Β·
1 Parent(s): 7f84e9b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -278
app.py CHANGED
@@ -1,300 +1,162 @@
1
  import gradio as gr
2
- import yfinance as yf
3
  import pandas as pd
4
- import numpy as np
5
- import torch
6
- from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
7
- from datetime import datetime, timedelta
8
- import plotly.graph_objects as go
9
- import plotly.express as px
10
- from plotly.subplots import make_subplots
11
- import warnings
12
- warnings.filterwarnings('ignore')
13
- import spaces
14
-
15
- # Import utility functions
16
  from utils import (
17
- get_indonesian_stocks,
18
  calculate_technical_indicators,
19
  generate_trading_signals,
20
  get_fundamental_data,
21
- format_large_number,
22
  predict_prices,
23
  create_price_chart,
24
  create_technical_chart,
25
- create_prediction_chart
26
  )
27
- from config import IDX_STOCKS, TECHNICAL_INDICATORS, PREDICTION_CONFIG
28
-
29
- # Load Chronos-Bolt model
30
- @spaces.GPU(duration=120)
31
- def load_model():
32
- """Load the Amazon Chronos-Bolt model for time series forecasting"""
33
- model = AutoModelForSeq2SeqLM.from_pretrained(
34
- "amazon/chronos-bolt-base",
35
- torch_dtype=torch.bfloat16,
36
- device_map="auto",
37
- trust_remote_code=True
38
- )
39
- tokenizer = None
40
- return model, tokenizer
41
 
42
- # Initialize model
43
- model, tokenizer = load_model()
44
 
45
- def get_stock_data(symbol, period="1y"):
46
- """Fetch historical stock data using yfinance"""
47
  try:
48
  stock = yf.Ticker(symbol)
49
- data = stock.history(period=period)
50
  if data.empty:
51
- return None, None
52
- return data, stock
53
- except Exception as e:
54
- print(f"Error fetching data for {symbol}: {e}")
55
- return None, None
56
-
57
- def analyze_stock(symbol, prediction_days=30):
58
- """Main analysis function"""
59
- # FIX: Add .JK suffix if it's missing (case-insensitive check)
60
- if not symbol.upper().endswith(".JK"):
61
- symbol += ".JK"
62
 
63
- # Get stock data
64
- data, stock = get_stock_data(symbol)
65
-
66
- if data is None or stock is None:
67
- return None, None, None, None, None, None
68
-
69
- # Get fundamental data
70
- fundamental_info = get_fundamental_data(stock)
71
-
72
- # Calculate technical indicators
73
- indicators = calculate_technical_indicators(data)
74
-
75
- # Generate trading signals
76
- signals = generate_trading_signals(data, indicators)
77
-
78
- # Make predictions using Chronos-Bolt
79
- predictions = predict_prices(data, model, tokenizer, prediction_days)
80
-
81
- # Create charts
82
- fig_price = create_price_chart(data, indicators)
83
- fig_technical = create_technical_chart(data, indicators)
84
- fig_prediction = create_prediction_chart(data, predictions)
85
-
86
- return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction
87
 
88
- def create_ui():
89
- """Create the Gradio interface"""
90
- with gr.Blocks(
91
- title="IDX Stock Analysis & Prediction",
92
- theme=gr.themes.Soft(),
93
- css="""
94
- .header {
95
- text-align: center;
96
- padding: 20px;
97
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
98
- color: white;
99
- border-radius: 10px;
100
- margin-bottom: 20px;
101
- }
102
- .metric-card {
103
- background: white;
104
- padding: 15px;
105
- border-radius: 8px;
106
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
107
- margin: 10px 0;
108
  }
109
- .positive { color: #10b981; font-weight: bold; }
110
- .negative { color: #ef4444; font-weight: bold; }
111
- .neutral { color: #6b7280; font-weight: bold; }
112
- """
113
- ) as demo:
114
-
115
- with gr.Row():
116
- gr.HTML("""
117
- <div class="header">
118
- <h1>IDX Stock Analysis & Prediction</h1>
119
- <p>Advanced Technical Analysis & AI-Powered Predictions for Indonesian Stock Exchange</p>
120
- </div>
121
- """)
122
-
123
- with gr.Row():
124
- with gr.Column(scale=2):
125
- # FIX: Change Dropdown to Textbox for flexible user input
126
- stock_selector = gr.Textbox(
127
- value="BBCA",
128
- label="Input Simbol Saham IDX",
129
- info="Contoh: BBCA, ADRO, TLKM"
130
- )
131
-
132
- with gr.Row():
133
- prediction_days = gr.Slider(
134
- minimum=7,
135
- maximum=90,
136
- value=30,
137
- step=7,
138
- label="Prediction Days"
139
- )
140
- analyze_btn = gr.Button(
141
- "Analyze Stock",
142
- variant="primary",
143
- size="lg"
144
- )
145
-
146
- # Results sections
147
- with gr.Tabs() as tabs:
148
-
149
- # Tab 1: Stock Overview & Fundamentals
150
- with gr.TabItem("Stock Overview"):
151
- with gr.Row():
152
- company_name = gr.Textbox(label="Company Name", interactive=False)
153
- current_price = gr.Number(label="Current Price (IDR)", interactive=False)
154
- market_cap = gr.Textbox(label="Market Cap", interactive=False)
155
-
156
- with gr.Row():
157
- pe_ratio = gr.Number(label="P/E Ratio", interactive=False)
158
- dividend_yield = gr.Number(label="Dividend Yield (%)", interactive=False)
159
- volume = gr.Number(label="Volume", interactive=False)
160
-
161
- fundamentals_text = gr.Textbox(
162
- label="Company Information",
163
- lines=8,
164
- interactive=False
165
- )
166
-
167
- # Tab 2: Technical Analysis
168
- with gr.TabItem("Technical Analysis"):
169
- price_chart = gr.Plot(label="Price & Technical Indicators")
170
- technical_chart = gr.Plot(label="Technical Indicators Analysis")
171
-
172
- with gr.Row():
173
- rsi_value = gr.Number(label="RSI (14)", interactive=False)
174
- macd_signal = gr.Textbox(label="MACD Signal", interactive=False)
175
- bb_position = gr.Textbox(label="Bollinger Band Position", interactive=False)
176
-
177
- # Tab 3: Trading Signals
178
- with gr.TabItem("Trading Signals"):
179
- with gr.Row():
180
- overall_signal = gr.Textbox(label="Overall Signal", interactive=False, scale=2)
181
- signal_strength = gr.Slider(
182
- minimum=0,
183
- maximum=100,
184
- label="Signal Strength",
185
- interactive=False
186
- )
187
-
188
- signals_text = gr.Textbox(
189
- label="Detailed Signals",
190
- lines=10,
191
- interactive=False
192
- )
193
-
194
- with gr.Row():
195
- support_level = gr.Number(label="Support Level", interactive=False)
196
- resistance_level = gr.Number(label="Resistance Level", interactive=False)
197
- stop_loss = gr.Number(label="Recommended Stop Loss", interactive=False)
198
-
199
- # Tab 4: AI Predictions
200
- with gr.TabItem("AI Predictions"):
201
- prediction_chart = gr.Plot(label="Price Forecast (Chronos-Bolt)")
202
-
203
- with gr.Row():
204
- predicted_high = gr.Number(label="Predicted High (30d)", interactive=False)
205
- predicted_low = gr.Number(label="Predicted Low (30d)", interactive=False)
206
- predicted_change = gr.Number(label="Expected Change (%)", interactive=False)
207
-
208
- prediction_summary = gr.Textbox(
209
- label="Prediction Analysis",
210
- lines=5,
211
- interactive=False
212
- )
213
-
214
- # Event handlers
215
- def update_analysis(symbol, pred_days):
216
- fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction = analyze_stock(symbol, pred_days)
217
-
218
- if fundamental_info is None:
219
- # FIX: Return appropriate initial values or error message
220
- return {
221
- company_name: "Gagal memuat data",
222
- current_price: 0,
223
- market_cap: "N/A",
224
- pe_ratio: 0,
225
- dividend_yield: 0,
226
- volume: 0,
227
- fundamentals_text: f"Tidak dapat mengambil data saham untuk {symbol}. Pastikan simbol benar.",
228
- rsi_value: 0,
229
- macd_signal: "N/A",
230
- bb_position: "N/A",
231
- overall_signal: "N/A",
232
- signal_strength: 0,
233
- signals_text: "Tidak ada sinyal tersedia",
234
- support_level: 0,
235
- resistance_level: 0,
236
- stop_loss: 0,
237
- predicted_high: 0,
238
- predicted_low: 0,
239
- predicted_change: 0,
240
- prediction_summary: "Prediksi tidak tersedia",
241
- price_chart: go.Figure(),
242
- technical_chart: go.Figure(),
243
- prediction_chart: go.Figure()
244
- }
245
-
246
- # Format outputs
247
- return {
248
- company_name: fundamental_info.get('name', 'N/A'),
249
- current_price: fundamental_info.get('current_price', 0),
250
- market_cap: format_large_number(fundamental_info.get('market_cap', 0)),
251
- pe_ratio: fundamental_info.get('pe_ratio', 0),
252
- dividend_yield: fundamental_info.get('dividend_yield', 0),
253
- volume: fundamental_info.get('volume', 0),
254
- fundamentals_text: fundamental_info.get('info', ''),
255
- rsi_value: indicators.get('rsi', {}).get('current', 0),
256
- macd_signal: indicators.get('macd', {}).get('signal', 'N/A'),
257
- bb_position: indicators.get('bollinger', {}).get('position', 'N/A'),
258
- overall_signal: signals.get('overall', 'HOLD'),
259
- signal_strength: signals.get('strength', 50),
260
- signals_text: signals.get('details', ''),
261
- support_level: signals.get('support', 0),
262
- resistance_level: signals.get('resistance', 0),
263
- stop_loss: signals.get('stop_loss', 0),
264
- predicted_high: indicators.get('predictions', {}).get('high_30d', 0),
265
- predicted_low: indicators.get('predictions', {}).get('low_30d', 0),
266
- predicted_change: indicators.get('predictions', {}).get('change_pct', 0),
267
- prediction_summary: indicators.get('predictions', {}).get('summary', ''),
268
- price_chart: fig_price,
269
- technical_chart: fig_technical,
270
- prediction_chart: fig_prediction
271
- }
272
-
273
- analyze_btn.click(
274
- fn=update_analysis,
275
- inputs=[stock_selector, prediction_days],
276
- outputs=[
277
- company_name, current_price, market_cap, pe_ratio, dividend_yield, volume, fundamentals_text,
278
- rsi_value, macd_signal, bb_position, overall_signal, signal_strength, signals_text,
279
- support_level, resistance_level, stop_loss, predicted_high, predicted_low, predicted_change,
280
- prediction_summary, price_chart, technical_chart, prediction_chart
281
- ]
282
  )
283
-
284
- # Load initial analysis
285
- demo.load(
286
- fn=update_analysis,
287
- inputs=[stock_selector, prediction_days],
288
- outputs=[
289
- company_name, current_price, market_cap, pe_ratio, dividend_yield, volume, fundamentals_text,
290
- rsi_value, macd_signal, bb_position, overall_signal, signal_strength, signals_text,
291
- support_level, resistance_level, stop_loss, predicted_high, predicted_low, predicted_change,
292
- prediction_summary, price_chart, technical_chart, prediction_chart
293
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  )
295
-
296
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
  if __name__ == "__main__":
299
- demo = create_ui()
300
- demo.launch()
 
1
  import gradio as gr
 
2
  import pandas as pd
3
+ import yfinance as yf
4
+ from datetime import datetime
 
 
 
 
 
 
 
 
 
 
5
  from utils import (
6
+ get_indonesian_stocks,
7
  calculate_technical_indicators,
8
  generate_trading_signals,
9
  get_fundamental_data,
 
10
  predict_prices,
11
  create_price_chart,
12
  create_technical_chart,
13
+ create_prediction_chart,
14
  )
15
+ import warnings
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ warnings.filterwarnings("ignore")
 
18
 
19
+ def analyze_stock(symbol, prediction_days=30):
 
20
  try:
21
  stock = yf.Ticker(symbol)
22
+ data = stock.history(period="6mo", interval="1d")
23
  if data.empty:
24
+ raise ValueError("No price data available.")
 
 
 
 
 
 
 
 
 
 
25
 
26
+ indicators = calculate_technical_indicators(data)
27
+ signals = generate_trading_signals(data, indicators)
28
+ fundamental_info = get_fundamental_data(stock)
29
+ predictions = predict_prices(data, prediction_days=prediction_days)
30
+ fig_price = create_price_chart(data, indicators)
31
+ fig_technical = create_technical_chart(data, indicators)
32
+ fig_prediction = create_prediction_chart(data, predictions)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction, predictions
35
+ except Exception as e:
36
+ print(f"Error analyzing {symbol}: {e}")
37
+ empty_fig = gr.Plot.update(value=None)
38
+ empty_predictions = {
39
+ 'high_30d': 0, 'low_30d': 0, 'change_pct': 0, 'summary': 'Prediction unavailable.'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
+ return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions
42
+
43
+ def update_analysis(symbol, prediction_days):
44
+ (
45
+ fundamental_info,
46
+ indicators,
47
+ signals,
48
+ fig_price,
49
+ fig_technical,
50
+ fig_prediction,
51
+ predictions,
52
+ ) = analyze_stock(symbol, prediction_days)
53
+
54
+ if not fundamental_info:
55
+ return (
56
+ "Data unavailable.",
57
+ gr.Plot.update(value=None),
58
+ gr.Plot.update(value=None),
59
+ gr.Plot.update(value=None),
60
+ "",
61
+ "",
62
+ "",
63
+ "",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  )
65
+
66
+ summary_text = f"""
67
+ **{fundamental_info.get('name', 'N/A')} ({symbol})**
68
+ - Current Price: Rp{fundamental_info.get('current_price', 0):,.2f}
69
+ - Market Cap: {fundamental_info.get('market_cap', 0):,}
70
+ - P/E Ratio: {fundamental_info.get('pe_ratio', 0):.2f}
71
+ - Dividend Yield: {fundamental_info.get('dividend_yield', 0):.2f}%
72
+ - Volume: {fundamental_info.get('volume', 0):,}
73
+ """
74
+
75
+ signal_text = f"""
76
+ ### Overall Signal: **{signals.get('overall', 'N/A')}**
77
+ Strength: {signals.get('strength', 0):.2f}%
78
+ Support: {signals.get('support', 0):,.2f}
79
+ Resistance: {signals.get('resistance', 0):,.2f}
80
+ Stop Loss: {signals.get('stop_loss', 0):,.2f}
81
+
82
+ **Signal Details:**
83
+ {signals.get('details', '')}
84
+ """
85
+
86
+ prediction_text = f"""
87
+ ### AI Forecast (Chronos-Bolt)
88
+ Predicted High (30d): {predictions.get('high_30d', 0):,.2f}
89
+ Predicted Low (30d): {predictions.get('low_30d', 0):,.2f}
90
+ Expected Change (%): {predictions.get('change_pct', 0):.2f}%
91
+ Prediction Analysis:
92
+ {predictions.get('summary', 'No analysis available')}
93
+ """
94
+
95
+ return (
96
+ summary_text,
97
+ fig_price,
98
+ fig_technical,
99
+ fig_prediction,
100
+ signal_text,
101
+ f"{predictions.get('high_30d', 0):,.2f}",
102
+ f"{predictions.get('low_30d', 0):,.2f}",
103
+ f"{predictions.get('change_pct', 0):.2f}%",
104
+ prediction_text,
105
+ )
106
+
107
+ stock_options = get_indonesian_stocks()
108
+
109
+ with gr.Blocks(title="AI Stock Analysis (Chronos-Bolt Edition)", theme="soft") as app:
110
+ gr.Markdown("# πŸ“Š AI Stock Analysis Dashboard (Chronos-Bolt Base Model)")
111
+
112
+ with gr.Row():
113
+ symbol = gr.Dropdown(
114
+ label="Select Stock",
115
+ choices=list(stock_options.keys()),
116
+ value="BBCA.JK",
117
+ interactive=True,
118
+ )
119
+ prediction_days = gr.Slider(
120
+ label="Prediction Period (Days)",
121
+ minimum=5,
122
+ maximum=60,
123
+ step=5,
124
+ value=30,
125
+ interactive=True,
126
  )
127
+
128
+ analyze_button = gr.Button("πŸ” Analyze Stock")
129
+
130
+ with gr.Tab("Fundamentals & Signals"):
131
+ fundamentals_output = gr.Markdown()
132
+ signal_output = gr.Markdown()
133
+
134
+ with gr.Tab("Charts"):
135
+ price_chart = gr.Plot()
136
+ technical_chart = gr.Plot()
137
+ prediction_chart = gr.Plot()
138
+
139
+ with gr.Tab("Predictions"):
140
+ predicted_high = gr.Textbox(label="Predicted High (30d)")
141
+ predicted_low = gr.Textbox(label="Predicted Low (30d)")
142
+ predicted_change = gr.Textbox(label="Expected Change (%)")
143
+ prediction_summary = gr.Markdown(label="Prediction Analysis")
144
+
145
+ analyze_button.click(
146
+ fn=update_analysis,
147
+ inputs=[symbol, prediction_days],
148
+ outputs=[
149
+ fundamentals_output,
150
+ price_chart,
151
+ technical_chart,
152
+ prediction_chart,
153
+ signal_output,
154
+ predicted_high,
155
+ predicted_low,
156
+ predicted_change,
157
+ prediction_summary,
158
+ ],
159
+ )
160
 
161
  if __name__ == "__main__":
162
+ app.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=True)