omniverse1 commited on
Commit
2e5e038
·
verified ·
1 Parent(s): 05c066f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -42
app.py CHANGED
@@ -9,7 +9,7 @@ from utils import (
9
  create_prediction_chart,
10
  predict_prices,
11
  )
12
- import pandas as pd
13
 
14
 
15
  def analyze_stock(symbol, mode, pred_days):
@@ -17,16 +17,12 @@ def analyze_stock(symbol, mode, pred_days):
17
  stock = yf.Ticker(symbol)
18
  data = stock.history(period="1y")
19
 
20
- # ✅ Handle jika tidak ada data (misal salah kode atau delisted)
21
  if data.empty:
22
  msg = f"No data found for {symbol}. Check the symbol or try adding .JK (e.g., ADRO.JK)"
23
  return (
24
  {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0},
25
  {"overall": "N/A", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg},
26
- None,
27
- None,
28
- None,
29
- None,
30
  )
31
 
32
  indicators = calculate_technical_indicators(data)
@@ -48,22 +44,21 @@ def analyze_stock(symbol, mode, pred_days):
48
  return (
49
  {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0},
50
  {"overall": "Error", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg},
51
- None,
52
- None,
53
- None,
54
- None,
55
  )
56
 
57
 
58
  def format_fundamental_output(f):
59
  return f"""
 
60
  <h3>COMPANY FUNDAMENTALS</h3>
61
- <b>Name:</b> {f['name']}<br>
62
- <b>Current Price:</b> Rp{f['current_price']:,.2f}<br>
63
- <b>Market Cap:</b> {f['market_cap']:,}<br>
64
- <b>P/E Ratio:</b> {f['pe_ratio']:.2f}<br>
65
- <b>Dividend Yield:</b> {f['dividend_yield']:.2f}%<br>
66
- <b>Volume:</b> {f['volume']:,}<br>
 
67
  """
68
 
69
 
@@ -72,52 +67,85 @@ def format_signal_output(s):
72
  detail_list = details.split("\n") if details else []
73
  formatted_details = "<ul>" + "".join(f"<li>{d}</li>" for d in detail_list) + "</ul>"
74
  return f"""
 
75
  <h3>TECHNICAL SIGNAL SUMMARY</h3>
76
- <b>Overall Trend:</b> {s.get('overall','N/A')}<br>
77
- <b>Signal Strength:</b> {s.get('strength',0):.2f}%<br>
78
- <b>Support:</b> Rp{s.get('support',0):,.2f}<br>
79
- <b>Resistance:</b> Rp{s.get('resistance',0):,.2f}<br>
80
- <b>Stop Loss:</b> Rp{s.get('stop_loss',0):,.2f}<br><br>
81
- <b>Detailed Signals:</b>{formatted_details}
 
 
82
  """
83
 
84
 
85
  def format_ai_output(p):
86
- if not p or not p.get("values"):
87
- return "<h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3><p>No AI prediction data available.</p>"
 
 
 
 
 
88
  tp1 = p["mean_30d"] * 0.97
89
  tp2 = p["mean_30d"] * 1.02
90
  sl = p["low_30d"] * 0.95
91
  return f"""
 
92
  <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3>
93
- <b>Predicted High:</b> Rp{p['high_30d']:,.2f}<br>
94
- <b>Predicted Low:</b> Rp{p['low_30d']:,.2f}<br>
95
- <b>Expected Change:</b> {p['change_pct']:.2f}%<br><br>
96
- <b>TP1:</b> Rp{tp1:,.2f}<br>
97
- <b>TP2:</b> Rp{tp2:,.2f}<br>
98
- <b>Stop Loss:</b> Rp{sl:,.2f}<br><br>
99
- <b>Model Insight:</b><br>{p['summary']}
 
 
100
  """
101
 
102
 
103
  with gr.Blocks(css="""
104
  body { font-family: 'Inter', sans-serif; background-color: #f9fafc; color: #222; }
105
- .gradio-container { max-width: 1200px; margin: auto; }
106
- h3 { color: #003366; border-bottom: 2px solid #d3d3d3; padding-bottom: 5px; }
107
- .panel-box { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  """) as demo:
109
- gr.HTML("<h1 style='text-align:center;color:#003366;'>📊 STOCK ANALYSIS DASHBOARD</h1>")
 
110
 
111
  with gr.Row():
112
- stock_input = gr.Textbox(label="Enter Stock Symbol (e.g. BBCA.JK, ADRO.JK)", placeholder="Type your stock symbol here...")
113
  mode_input = gr.Radio(["Technical Analysis", "AI Prediction"], label="Select Analysis Mode", value="Technical Analysis")
114
- pred_days_input = gr.Slider(7, 60, value=30, step=1, label="Prediction Days (for AI mode only)")
115
- analyze_button = gr.Button("Analyze")
116
 
117
- with gr.Row():
118
- fundamentals_output = gr.HTML(elem_classes="panel-box")
119
- signal_output = gr.HTML(elem_classes="panel-box")
120
- ai_output = gr.HTML(elem_classes="panel-box")
 
 
 
 
121
 
122
  with gr.Row():
123
  chart_price = gr.Plot(label="Price Chart")
 
9
  create_prediction_chart,
10
  predict_prices,
11
  )
12
+ import numpy as np
13
 
14
 
15
  def analyze_stock(symbol, mode, pred_days):
 
17
  stock = yf.Ticker(symbol)
18
  data = stock.history(period="1y")
19
 
 
20
  if data.empty:
21
  msg = f"No data found for {symbol}. Check the symbol or try adding .JK (e.g., ADRO.JK)"
22
  return (
23
  {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0},
24
  {"overall": "N/A", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg},
25
+ None, None, None, None
 
 
 
26
  )
27
 
28
  indicators = calculate_technical_indicators(data)
 
44
  return (
45
  {"name": "N/A", "current_price": 0, "market_cap": 0, "pe_ratio": 0, "dividend_yield": 0, "volume": 0},
46
  {"overall": "Error", "strength": 0, "support": 0, "resistance": 0, "stop_loss": 0, "details": msg},
47
+ None, None, None, None
 
 
 
48
  )
49
 
50
 
51
  def format_fundamental_output(f):
52
  return f"""
53
+ <div class="card">
54
  <h3>COMPANY FUNDAMENTALS</h3>
55
+ <p><b>Name:</b> {f['name']}</p>
56
+ <p><b>Current Price:</b> Rp{f['current_price']:,.2f}</p>
57
+ <p><b>Market Cap:</b> {f['market_cap']:,}</p>
58
+ <p><b>P/E Ratio:</b> {f['pe_ratio']:.2f}</p>
59
+ <p><b>Dividend Yield:</b> {f['dividend_yield']:.2f}%</p>
60
+ <p><b>Volume:</b> {f['volume']:,}</p>
61
+ </div>
62
  """
63
 
64
 
 
67
  detail_list = details.split("\n") if details else []
68
  formatted_details = "<ul>" + "".join(f"<li>{d}</li>" for d in detail_list) + "</ul>"
69
  return f"""
70
+ <div class="card">
71
  <h3>TECHNICAL SIGNAL SUMMARY</h3>
72
+ <p><b>Overall Trend:</b> {s.get('overall','N/A')}</p>
73
+ <p><b>Signal Strength:</b> {s.get('strength',0):.2f}%</p>
74
+ <p><b>Support:</b> Rp{s.get('support',0):,.2f}</p>
75
+ <p><b>Resistance:</b> Rp{s.get('resistance',0):,.2f}</p>
76
+ <p><b>Stop Loss:</b> Rp{s.get('stop_loss',0):,.2f}</p>
77
+ <h4>Detailed Signals:</h4>
78
+ {formatted_details}
79
+ </div>
80
  """
81
 
82
 
83
  def format_ai_output(p):
84
+ if p is None or not isinstance(p, dict) or "values" not in p or len(p["values"]) == 0:
85
+ return """
86
+ <div class="card">
87
+ <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3>
88
+ <p>No AI prediction data available.</p>
89
+ </div>
90
+ """
91
  tp1 = p["mean_30d"] * 0.97
92
  tp2 = p["mean_30d"] * 1.02
93
  sl = p["low_30d"] * 0.95
94
  return f"""
95
+ <div class="card">
96
  <h3>30-DAY AI FORECAST (CHRONOS-BOLT)</h3>
97
+ <p><b>Predicted High:</b> Rp{p['high_30d']:,.2f}</p>
98
+ <p><b>Predicted Low:</b> Rp{p['low_30d']:,.2f}</p>
99
+ <p><b>Expected Change:</b> {p['change_pct']:.2f}%</p>
100
+ <p><b>TP1:</b> Rp{tp1:,.2f}</p>
101
+ <p><b>TP2:</b> Rp{tp2:,.2f}</p>
102
+ <p><b>Stop Loss:</b> Rp{sl:,.2f}</p>
103
+ <h4>Model Insight:</h4>
104
+ <p style="font-size:13px;line-height:1.4;">{p['summary']}</p>
105
+ </div>
106
  """
107
 
108
 
109
  with gr.Blocks(css="""
110
  body { font-family: 'Inter', sans-serif; background-color: #f9fafc; color: #222; }
111
+ .gradio-container { max-width: 1300px; margin: auto; }
112
+ h1 { text-align:center; color:#003366; margin-bottom:20px; }
113
+ h3 { color:#003366; margin-bottom:8px; }
114
+ .card {
115
+ background: #ffffff;
116
+ border-radius: 10px;
117
+ box-shadow: 0 2px 4px rgba(0,0,0,0.08);
118
+ padding: 18px;
119
+ margin: 5px;
120
+ flex: 1;
121
+ min-width: 0;
122
+ }
123
+ .row-flex {
124
+ display: flex;
125
+ flex-wrap: wrap;
126
+ justify-content: space-between;
127
+ gap: 10px;
128
+ }
129
+ ul { margin: 6px 0 0 20px; padding: 0; }
130
+ li { margin-bottom: 4px; font-size: 14px; }
131
  """) as demo:
132
+
133
+ gr.HTML("<h1>STOCK ANALYSIS DASHBOARD</h1>")
134
 
135
  with gr.Row():
136
+ stock_input = gr.Textbox(label="Enter Stock Symbol (e.g. BBCA.JK, ADRO.JK)", placeholder="Type stock symbol...")
137
  mode_input = gr.Radio(["Technical Analysis", "AI Prediction"], label="Select Analysis Mode", value="Technical Analysis")
138
+ pred_days_input = gr.Slider(7, 60, value=30, step=1, label="Prediction Days (AI only)")
139
+ analyze_button = gr.Button("Analyze", variant="primary")
140
 
141
+ gr.HTML("<hr style='margin:20px 0;'>")
142
+
143
+ with gr.Row(elem_classes="row-flex"):
144
+ fundamentals_output = gr.HTML()
145
+ signal_output = gr.HTML()
146
+ ai_output = gr.HTML()
147
+
148
+ gr.HTML("<hr style='margin:20px 0;'>")
149
 
150
  with gr.Row():
151
  chart_price = gr.Plot(label="Price Chart")