omniverse1 commited on
Commit
823c183
Β·
verified Β·
1 Parent(s): 68974cf

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +129 -23
utils.py CHANGED
@@ -7,6 +7,33 @@ import plotly.graph_objects as go
7
  from plotly.subplots import make_subplots
8
  import spaces
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def get_indonesian_stocks():
11
  return {
12
  "BBCA.JK": "Bank Central Asia",
@@ -40,7 +67,10 @@ def calculate_technical_indicators(data):
40
  rs = gain / loss
41
  rsi = 100 - (100 / (1 + rs))
42
  return rsi
43
- indicators['rsi'] = {'current': calculate_rsi(data['Close']).iloc[-1], 'values': calculate_rsi(data['Close'])}
 
 
 
44
  def calculate_macd(prices, fast=12, slow=26, signal=9):
45
  exp1 = prices.ewm(span=fast).mean()
46
  exp2 = prices.ewm(span=slow).mean()
@@ -48,30 +78,71 @@ def calculate_technical_indicators(data):
48
  signal_line = macd.ewm(span=signal).mean()
49
  histogram = macd - signal_line
50
  return macd, signal_line, histogram
 
51
  macd, signal_line, histogram = calculate_macd(data['Close'])
52
- indicators['macd'] = {'macd': macd.iloc[-1], 'signal': signal_line.iloc[-1], 'histogram': histogram.iloc[-1], 'signal_text': 'BUY' if histogram.iloc[-1] > 0 else 'SELL', 'macd_values': macd, 'signal_values': signal_line}
 
 
 
 
 
 
 
 
 
53
  def calculate_bollinger_bands(prices, period=20, std_dev=2):
54
  sma = prices.rolling(window=period).mean()
55
  std = prices.rolling(window=period).std()
56
  upper_band = sma + (std * std_dev)
57
  lower_band = sma - (std * std_dev)
58
  return upper_band, sma, lower_band
 
59
  upper, middle, lower = calculate_bollinger_bands(data['Close'])
60
  current_price = data['Close'].iloc[-1]
61
- bb_position = (current_price - lower.iloc[-1]) / (upper.iloc[-1] - lower.iloc[-1])
 
 
 
 
 
 
 
 
 
62
  indicators['bollinger'] = {
63
- 'upper': upper.iloc[-1],
64
- 'middle': middle.iloc[-1],
65
- 'lower': lower.iloc[-1],
66
  'upper_values': upper,
67
  'middle_values': middle,
68
  'lower_values': lower,
69
- 'position': 'UPPER' if bb_position > 0.8 else 'LOWER' if bb_position < 0.2 else 'MIDDLE'
70
  }
 
71
  sma_20_series = data['Close'].rolling(20).mean()
72
  sma_50_series = data['Close'].rolling(50).mean()
73
- indicators['moving_averages'] = {'sma_20': sma_20_series.iloc[-1], 'sma_50': sma_50_series.iloc[-1], 'sma_200': data['Close'].rolling(200).mean().iloc[-1], 'ema_12': data['Close'].ewm(span=12).mean().iloc[-1], 'ema_26': data['Close'].ewm(span=26).mean().iloc[-1], 'sma_20_values': sma_20_series, 'sma_50_values': sma_50_series}
74
- indicators['volume'] = {'current': data['Volume'].iloc[-1], 'avg_20': data['Volume'].rolling(20).mean().iloc[-1], 'ratio': data['Volume'].iloc[-1] / data['Volume'].rolling(20).mean().iloc[-1]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  return indicators
76
 
77
  def generate_trading_signals(data, indicators):
@@ -80,7 +151,8 @@ def generate_trading_signals(data, indicators):
80
  buy_signals = 0
81
  sell_signals = 0
82
  signal_details = []
83
- rsi = indicators['rsi']['current']
 
84
  if rsi < 30:
85
  buy_signals += 1
86
  signal_details.append(f"βœ… RSI ({rsi:.1f}) - Oversold - BUY signal")
@@ -89,13 +161,15 @@ def generate_trading_signals(data, indicators):
89
  signal_details.append(f"❌ RSI ({rsi:.1f}) - Overbought - SELL signal")
90
  else:
91
  signal_details.append(f"βšͺ RSI ({rsi:.1f}) - Neutral")
92
- macd_hist = indicators['macd']['histogram']
 
93
  if macd_hist > 0:
94
  buy_signals += 1
95
  signal_details.append(f"βœ… MACD Histogram ({macd_hist:.4f}) - Positive - BUY signal")
96
  else:
97
  sell_signals += 1
98
  signal_details.append(f"❌ MACD Histogram ({macd_hist:.4f}) - Negative - SELL signal")
 
99
  bb_position = indicators['bollinger']['position']
100
  if bb_position == 'LOWER':
101
  buy_signals += 1
@@ -105,8 +179,9 @@ def generate_trading_signals(data, indicators):
105
  signal_details.append(f"❌ Bollinger Bands - Near upper band - SELL signal")
106
  else:
107
  signal_details.append("βšͺ Bollinger Bands - Middle position")
108
- sma_20 = indicators['moving_averages']['sma_20']
109
- sma_50 = indicators['moving_averages']['sma_50']
 
110
  if current_price > sma_20 > sma_50:
111
  buy_signals += 1
112
  signal_details.append(f"βœ… Price above MA(20,50) - Bullish - BUY signal")
@@ -115,7 +190,8 @@ def generate_trading_signals(data, indicators):
115
  signal_details.append(f"❌ Price below MA(20,50) - Bearish - SELL signal")
116
  else:
117
  signal_details.append("βšͺ Moving Averages - Mixed signals")
118
- volume_ratio = indicators['volume']['ratio']
 
119
  if volume_ratio > 1.5:
120
  buy_signals += 0.5
121
  signal_details.append(f"βœ… High volume ({volume_ratio:.1f}x avg) - Strengthens BUY signal")
@@ -124,12 +200,24 @@ def generate_trading_signals(data, indicators):
124
  signal_details.append(f"❌ Low volume ({volume_ratio:.1f}x avg) - Weakens SELL signal")
125
  else:
126
  signal_details.append(f"βšͺ Normal volume ({volume_ratio:.1f}x avg)")
 
127
  total_signals = buy_signals + sell_signals
128
  signal_strength = (buy_signals / max(total_signals, 1)) * 100
129
  overall_signal = "BUY" if buy_signals > sell_signals else "SELL" if sell_signals > buy_signals else "HOLD"
 
130
  recent_high = data['High'].tail(20).max()
131
  recent_low = data['Low'].tail(20).min()
132
- signals = {'overall': overall_signal, 'strength': signal_strength, 'details': '\n'.join(signal_details), 'support': recent_low, 'resistance': recent_high, 'stop_loss': recent_low * 0.95 if overall_signal == "BUY" else recent_high * 1.05}
 
 
 
 
 
 
 
 
 
 
133
  return signals
134
 
135
  def get_fundamental_data(stock):
@@ -142,15 +230,17 @@ def get_fundamental_data(stock):
142
  raw_pe = info.get('forwardPE', 0)
143
  raw_div_yield = info.get('dividendYield', 0) * 100 if info.get('dividendYield') else 0
144
  raw_volume = history['Volume'].iloc[-1] if not history.empty else 0
 
 
145
 
146
  fundamental_info = {
147
  'name': info.get('longName', 'N/A'),
148
- 'current_price': float(raw_price),
149
- 'market_cap': int(raw_market_cap),
150
- 'pe_ratio': float(raw_pe),
151
- 'dividend_yield': float(raw_div_yield),
152
- 'volume': int(raw_volume),
153
- 'info': f"Sector: {info.get('sector', 'N/A')}\nIndustry: {info.get('industry', 'N/A')}\nMarket Cap: {int(raw_market_cap):,}\n52 Week High: {info.get('fiftyTwoWeekHigh', 'N/A')}\n52 Week Low: {info.get('fiftyTwoWeekLow', 'N/A')}\nBeta: {info.get('beta', 'N/A')}\nEPS: {info.get('forwardEps', 'N/A')}\nBook Value: {info.get('bookValue', 'N/A')}\nPrice to Book: {info.get('priceToBook', 'N/A')}"
154
  }
155
  return fundamental_info
156
  except:
@@ -180,13 +270,29 @@ def predict_prices(data, model=None, tokenizer=None, prediction_days=30):
180
  if forecast_np.ndim > 1:
181
  mean_forecast = forecast_np.mean(axis=tuple(range(forecast_np.ndim - 1)))
182
  else:
183
- mean_forecast = forecast_np
 
184
  last_price = prices[-1]
185
  predicted_high = float(np.max(mean_forecast))
186
  predicted_low = float(np.min(mean_forecast))
187
  predicted_mean = float(np.mean(mean_forecast))
 
 
188
  change_pct = ((predicted_mean - last_price) / last_price) * 100 if last_price != 0 else 0
189
- return {'values': mean_forecast, 'dates': pd.date_range(start=data.index[-1] + timedelta(days=1), periods=len(mean_forecast), freq='D'), 'high_30d': predicted_high, 'low_30d': predicted_low, 'mean_30d': predicted_mean, 'change_pct': change_pct, 'summary': f"AI Model: Amazon Chronos-Bolt (Base)\nPredicted High: {predicted_high:.2f}\nPredicted Low: {predicted_low:.2f}\nExpected Change: {change_pct:.2f}%"}
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  except Exception as e:
191
  print(f"Error in prediction: {e}")
192
  return {'values': [], 'dates': [], 'high_30d': 0, 'low_30d': 0, 'mean_30d': 0, 'change_pct': 0, 'summary': f'Model error: {e}'}
 
7
  from plotly.subplots import make_subplots
8
  import spaces
9
 
10
+ def clean_value(v, default_val=0.0):
11
+ """
12
+ Mengonversi tipe NumPy dan float yang tidak valid (NaN/Inf)
13
+ ke nilai yang aman untuk JSON.
14
+ """
15
+ if v is None:
16
+ return default_val
17
+
18
+ # Periksa apakah itu float (Python atau NumPy) dan apakah itu NaN atau Inf
19
+ if isinstance(v, (float, np.float64, np.float32)) and (np.isnan(v) or np.isinf(v)):
20
+ return default_val
21
+
22
+ # Konversi int NumPy ke int Python
23
+ if isinstance(v, (np.int64, np.int32)):
24
+ return int(v)
25
+
26
+ # Konversi float NumPy ke float Python
27
+ if isinstance(v, (np.float64, np.float32)):
28
+ return float(v)
29
+
30
+ # Jika sudah merupakan tipe Python standar, kembalikan apa adanya
31
+ if isinstance(v, (int, float)):
32
+ return v
33
+
34
+ # Fallback untuk tipe lain (misalnya, jika sudah string)
35
+ return v
36
+
37
  def get_indonesian_stocks():
38
  return {
39
  "BBCA.JK": "Bank Central Asia",
 
67
  rs = gain / loss
68
  rsi = 100 - (100 / (1 + rs))
69
  return rsi
70
+
71
+ rsi_val = calculate_rsi(data['Close']).iloc[-1]
72
+ indicators['rsi'] = {'current': clean_value(rsi_val), 'values': calculate_rsi(data['Close'])}
73
+
74
  def calculate_macd(prices, fast=12, slow=26, signal=9):
75
  exp1 = prices.ewm(span=fast).mean()
76
  exp2 = prices.ewm(span=slow).mean()
 
78
  signal_line = macd.ewm(span=signal).mean()
79
  histogram = macd - signal_line
80
  return macd, signal_line, histogram
81
+
82
  macd, signal_line, histogram = calculate_macd(data['Close'])
83
+ macd_hist_val = histogram.iloc[-1]
84
+ indicators['macd'] = {
85
+ 'macd': clean_value(macd.iloc[-1]),
86
+ 'signal': clean_value(signal_line.iloc[-1]),
87
+ 'histogram': clean_value(macd_hist_val),
88
+ 'signal_text': 'BUY' if macd_hist_val > 0 else 'SELL',
89
+ 'macd_values': macd,
90
+ 'signal_values': signal_line
91
+ }
92
+
93
  def calculate_bollinger_bands(prices, period=20, std_dev=2):
94
  sma = prices.rolling(window=period).mean()
95
  std = prices.rolling(window=period).std()
96
  upper_band = sma + (std * std_dev)
97
  lower_band = sma - (std * std_dev)
98
  return upper_band, sma, lower_band
99
+
100
  upper, middle, lower = calculate_bollinger_bands(data['Close'])
101
  current_price = data['Close'].iloc[-1]
102
+
103
+ bb_upper_val = upper.iloc[-1]
104
+ bb_lower_val = lower.iloc[-1]
105
+
106
+ # Hindari pembagian dengan nol jika upper == lower
107
+ if (bb_upper_val - bb_lower_val) == 0:
108
+ bb_position_val = 0.5 # Default ke tengah
109
+ else:
110
+ bb_position_val = (current_price - bb_lower_val) / (bb_upper_val - bb_lower_val)
111
+
112
  indicators['bollinger'] = {
113
+ 'upper': clean_value(bb_upper_val),
114
+ 'middle': clean_value(middle.iloc[-1]),
115
+ 'lower': clean_value(bb_lower_val),
116
  'upper_values': upper,
117
  'middle_values': middle,
118
  'lower_values': lower,
119
+ 'position': 'UPPER' if bb_position_val > 0.8 else 'LOWER' if bb_position_val < 0.2 else 'MIDDLE'
120
  }
121
+
122
  sma_20_series = data['Close'].rolling(20).mean()
123
  sma_50_series = data['Close'].rolling(50).mean()
124
+
125
+ indicators['moving_averages'] = {
126
+ 'sma_20': clean_value(sma_20_series.iloc[-1]),
127
+ 'sma_50': clean_value(sma_50_series.iloc[-1]),
128
+ 'sma_200': clean_value(data['Close'].rolling(200).mean().iloc[-1]),
129
+ 'ema_12': clean_value(data['Close'].ewm(span=12).mean().iloc[-1]),
130
+ 'ema_26': clean_value(data['Close'].ewm(span=26).mean().iloc[-1]),
131
+ 'sma_20_values': sma_20_series,
132
+ 'sma_50_values': sma_50_series
133
+ }
134
+
135
+ vol_current = data['Volume'].iloc[-1]
136
+ vol_avg_20 = data['Volume'].rolling(20).mean().iloc[-1]
137
+
138
+ # Hindari pembagian dengan nol jika vol_avg_20 adalah 0
139
+ vol_ratio = vol_current / vol_avg_20 if vol_avg_20 > 0 else 0.0
140
+
141
+ indicators['volume'] = {
142
+ 'current': clean_value(vol_current, 0),
143
+ 'avg_20': clean_value(vol_avg_20, 0),
144
+ 'ratio': clean_value(vol_ratio)
145
+ }
146
  return indicators
147
 
148
  def generate_trading_signals(data, indicators):
 
151
  buy_signals = 0
152
  sell_signals = 0
153
  signal_details = []
154
+
155
+ rsi = indicators['rsi']['current'] # Sudah di-clean dari fungsi sebelumnya
156
  if rsi < 30:
157
  buy_signals += 1
158
  signal_details.append(f"βœ… RSI ({rsi:.1f}) - Oversold - BUY signal")
 
161
  signal_details.append(f"❌ RSI ({rsi:.1f}) - Overbought - SELL signal")
162
  else:
163
  signal_details.append(f"βšͺ RSI ({rsi:.1f}) - Neutral")
164
+
165
+ macd_hist = indicators['macd']['histogram'] # Sudah di-clean
166
  if macd_hist > 0:
167
  buy_signals += 1
168
  signal_details.append(f"βœ… MACD Histogram ({macd_hist:.4f}) - Positive - BUY signal")
169
  else:
170
  sell_signals += 1
171
  signal_details.append(f"❌ MACD Histogram ({macd_hist:.4f}) - Negative - SELL signal")
172
+
173
  bb_position = indicators['bollinger']['position']
174
  if bb_position == 'LOWER':
175
  buy_signals += 1
 
179
  signal_details.append(f"❌ Bollinger Bands - Near upper band - SELL signal")
180
  else:
181
  signal_details.append("βšͺ Bollinger Bands - Middle position")
182
+
183
+ sma_20 = indicators['moving_averages']['sma_20'] # Sudah di-clean
184
+ sma_50 = indicators['moving_averages']['sma_50'] # Sudah di-clean
185
  if current_price > sma_20 > sma_50:
186
  buy_signals += 1
187
  signal_details.append(f"βœ… Price above MA(20,50) - Bullish - BUY signal")
 
190
  signal_details.append(f"❌ Price below MA(20,50) - Bearish - SELL signal")
191
  else:
192
  signal_details.append("βšͺ Moving Averages - Mixed signals")
193
+
194
+ volume_ratio = indicators['volume']['ratio'] # Sudah di-clean
195
  if volume_ratio > 1.5:
196
  buy_signals += 0.5
197
  signal_details.append(f"βœ… High volume ({volume_ratio:.1f}x avg) - Strengthens BUY signal")
 
200
  signal_details.append(f"❌ Low volume ({volume_ratio:.1f}x avg) - Weakens SELL signal")
201
  else:
202
  signal_details.append(f"βšͺ Normal volume ({volume_ratio:.1f}x avg)")
203
+
204
  total_signals = buy_signals + sell_signals
205
  signal_strength = (buy_signals / max(total_signals, 1)) * 100
206
  overall_signal = "BUY" if buy_signals > sell_signals else "SELL" if sell_signals > buy_signals else "HOLD"
207
+
208
  recent_high = data['High'].tail(20).max()
209
  recent_low = data['Low'].tail(20).min()
210
+
211
+ stop_loss_val = recent_low * 0.95 if overall_signal == "BUY" else recent_high * 1.05
212
+
213
+ signals = {
214
+ 'overall': overall_signal,
215
+ 'strength': clean_value(signal_strength),
216
+ 'details': '\n'.join(signal_details),
217
+ 'support': clean_value(recent_low),
218
+ 'resistance': clean_value(recent_high),
219
+ 'stop_loss': clean_value(stop_loss_val)
220
+ }
221
  return signals
222
 
223
  def get_fundamental_data(stock):
 
230
  raw_pe = info.get('forwardPE', 0)
231
  raw_div_yield = info.get('dividendYield', 0) * 100 if info.get('dividendYield') else 0
232
  raw_volume = history['Volume'].iloc[-1] if not history.empty else 0
233
+
234
+ market_cap_clean = clean_value(raw_market_cap, 0)
235
 
236
  fundamental_info = {
237
  'name': info.get('longName', 'N/A'),
238
+ 'current_price': clean_value(raw_price),
239
+ 'market_cap': market_cap_clean,
240
+ 'pe_ratio': clean_value(raw_pe),
241
+ 'dividend_yield': clean_value(raw_div_yield),
242
+ 'volume': clean_value(raw_volume, 0),
243
+ 'info': f"Sector: {info.get('sector', 'N/A')}\nIndustry: {info.get('industry', 'N/A')}\nMarket Cap: {int(market_cap_clean):,}\n52 Week High: {info.get('fiftyTwoWeekHigh', 'N/A')}\n52 Week Low: {info.get('fiftyTwoWeekLow', 'N/A')}\nBeta: {info.get('beta', 'N/A')}\nEPS: {info.get('forwardEps', 'N/A')}\nBook Value: {info.get('bookValue', 'N/A')}\nPrice to Book: {info.get('priceToBook', 'N/A')}"
244
  }
245
  return fundamental_info
246
  except:
 
270
  if forecast_np.ndim > 1:
271
  mean_forecast = forecast_np.mean(axis=tuple(range(forecast_np.ndim - 1)))
272
  else:
273
+ mean_forecast = mean_forecast
274
+
275
  last_price = prices[-1]
276
  predicted_high = float(np.max(mean_forecast))
277
  predicted_low = float(np.min(mean_forecast))
278
  predicted_mean = float(np.mean(mean_forecast))
279
+
280
+ # Hindari pembagian dengan nol
281
  change_pct = ((predicted_mean - last_price) / last_price) * 100 if last_price != 0 else 0
282
+
283
+ high_clean = clean_value(predicted_high)
284
+ low_clean = clean_value(predicted_low)
285
+ change_clean = clean_value(change_pct)
286
+
287
+ return {
288
+ 'values': mean_forecast,
289
+ 'dates': pd.date_range(start=data.index[-1] + timedelta(days=1), periods=len(mean_forecast), freq='D'),
290
+ 'high_30d': high_clean,
291
+ 'low_30d': low_clean,
292
+ 'mean_30d': clean_value(predicted_mean),
293
+ 'change_pct': change_clean,
294
+ 'summary': f"AI Model: Amazon Chronos-Bolt (Base)\nPredicted High: {high_clean:.2f}\nPredicted Low: {low_clean:.2f}\nExpected Change: {change_clean:.2f}%"
295
+ }
296
  except Exception as e:
297
  print(f"Error in prediction: {e}")
298
  return {'values': [], 'dates': [], 'high_30d': 0, 'low_30d': 0, 'mean_30d': 0, 'change_pct': 0, 'summary': f'Model error: {e}'}