Miruzen commited on
Commit
72196d5
·
verified ·
1 Parent(s): a3bd9f8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -23
app.py CHANGED
@@ -23,15 +23,30 @@ class DateRange(BaseModel):
23
  end_date: str
24
 
25
  def ema_manual(prices, span):
 
 
 
 
 
26
  ema = [np.nan] * len(prices)
27
  alpha = 2 / (span + 1)
28
- for i in range(len(prices)):
29
- if i < span - 1:
30
- ema[i] = np.nan
31
- elif i == span - 1:
32
- ema[i] = np.mean(prices[:span])
33
- else:
34
- ema[i] = alpha * prices[i] + (1 - alpha) * ema[i - 1]
 
 
 
 
 
 
 
 
 
 
35
  return ema
36
 
37
  def get_dynamic_minmax():
@@ -45,18 +60,23 @@ def get_dynamic_minmax():
45
  close_min = df["Close"].min()
46
  close_max = df["Close"].max()
47
  logging.info(f"Min/Max Close: {close_min}/{close_max}")
48
- return close_min, close_max
49
 
50
  def normalize_close(value, close_min, close_max):
51
- if close_max == close_min: # Hindari pembagian dengan nol
52
- return 1.0 # Atau nilai default lain yang masuk akal
 
53
  return (value - close_min) / (close_max - close_min)
54
 
55
  def analyze_trend(latest_row):
 
 
 
56
  ema20 = latest_row["EMA20"]
57
  ema50 = latest_row["EMA50"]
58
  close = latest_row["close"]
59
 
 
60
  if ema20 > ema50:
61
  trend = "bullish"
62
  elif ema20 < ema50:
@@ -64,7 +84,13 @@ def analyze_trend(latest_row):
64
  else:
65
  trend = "neutral"
66
 
67
- diff = abs(ema20 - ema50) / ema50 * 100
 
 
 
 
 
 
68
  if diff > 0.3:
69
  strength = "strong"
70
  elif diff > 0.1:
@@ -79,6 +105,7 @@ def analyze_trend(latest_row):
79
  else:
80
  price_position = "between EMAs — indecision zone"
81
 
 
82
  return {
83
  "trend": trend,
84
  "strength": strength,
@@ -87,14 +114,14 @@ def analyze_trend(latest_row):
87
  }
88
 
89
  @app.post("/analyze")
90
- def analyze_ema(input_data: DateRange):
91
  try:
92
  logging.info(f"Menerima permintaan /analyze dengan start_date={input_data.start_date}, end_date={input_data.end_date}")
93
  start_date = pd.to_datetime(input_data.start_date)
94
  end_date = pd.to_datetime(input_data.end_date)
95
  extended_start = start_date - timedelta(days=60)
96
 
97
- logging.info(f"Mengunduh data dari yfinance: start={extended_start}, end={end_date + timedelta(days=1)}")
98
  df = yf.download(PAIR, start=extended_start, end=end_date + timedelta(days=1), auto_adjust=True)
99
 
100
  if df.empty:
@@ -103,14 +130,21 @@ def analyze_ema(input_data: DateRange):
103
 
104
  df = df.reset_index()[["Date", "Close"]]
105
  df.rename(columns={"Date": "date", "Close": "close"}, inplace=True)
 
106
 
107
  if len(df) < 50:
108
- logging.warning(f"Data terlalu sedikit ({len(df)} hari) untuk EMA50.")
 
109
  return {"status": "error", "message": f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50."}
110
 
111
- df["EMA20"] = ema_manual(df["close"], 20)
112
- df["EMA50"] = ema_manual(df["close"], 50)
 
 
 
 
113
  df = df.dropna().reset_index(drop=True)
 
114
 
115
  close_min, close_max = get_dynamic_minmax()
116
  df["norm_close"] = df["close"].apply(lambda x: normalize_close(x, close_min, close_max))
@@ -135,11 +169,12 @@ def analyze_ema(input_data: DateRange):
135
  }
136
 
137
  except Exception as e:
138
- logging.error(f"Error di /analyze: {e}", exc_info=True) # exc_info=True akan mencetak traceback
 
139
  return {"status": "error", "message": str(e)}
140
 
141
  @app.post("/summary")
142
- def ema_summary(input_data: DateRange):
143
  try:
144
  logging.info(f"Menerima permintaan /summary dengan start_date={input_data.start_date}, end_date={input_data.end_date}")
145
  start_date = pd.to_datetime(input_data.start_date)
@@ -153,14 +188,20 @@ def ema_summary(input_data: DateRange):
153
 
154
  df = df.reset_index()[["Date", "Close"]]
155
  df.rename(columns={"Date": "date", "Close": "close"}, inplace=True)
 
 
156
 
157
  if len(df) < 50:
158
- logging.warning(f"Data terlalu sedikit ({len(df)} hari) untuk EMA50.")
159
  return {"status": "error", "message": f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50."}
160
 
161
- df["EMA20"] = ema_manual(df["close"], 20)
162
- df["EMA50"] = ema_manual(df["close"], 50)
 
 
163
  df = df.dropna().reset_index(drop=True)
 
 
164
 
165
  latest = df.iloc[-1]
166
  analysis = analyze_trend(latest)
@@ -176,5 +217,9 @@ def ema_summary(input_data: DateRange):
176
  }
177
 
178
  except Exception as e:
179
- logging.error(f"Error di /summary: {e}", exc_info=True)
180
- return {"status": "error", "message": str(e)}
 
 
 
 
 
23
  end_date: str
24
 
25
  def ema_manual(prices, span):
26
+ logging.debug(f"Memulai ema_manual untuk span={span}. Jumlah harga: {len(prices)}")
27
+ if len(prices) < span:
28
+ logging.warning(f"Tidak cukup data untuk menghitung EMA span {span}. Hanya {len(prices)} tersedia.")
29
+ return [np.nan] * len(prices) # Kembalikan list NaN jika tidak cukup data
30
+
31
  ema = [np.nan] * len(prices)
32
  alpha = 2 / (span + 1)
33
+
34
+ # Debugging pada loop EMA
35
+ try:
36
+ for i in range(len(prices)):
37
+ if i < span - 1:
38
+ ema[i] = np.nan
39
+ elif i == span - 1:
40
+ # Tambahkan logging di sini
41
+ logging.debug(f"Menghitung EMA awal untuk span={span} pada indeks {i}. Data: {prices[:span]}")
42
+ ema[i] = np.mean(prices[:span])
43
+ else:
44
+ ema[i] = alpha * prices[i] + (1 - alpha) * ema[i - 1]
45
+ except Exception as e:
46
+ logging.error(f"Error dalam loop ema_manual (span={span}, index={i}): {e}", exc_info=True)
47
+ raise # Re-raise exception untuk ditangkap oleh try-except di endpoint
48
+
49
+ logging.debug(f"ema_manual selesai untuk span={span}.")
50
  return ema
51
 
52
  def get_dynamic_minmax():
 
60
  close_min = df["Close"].min()
61
  close_max = df["Close"].max()
62
  logging.info(f"Min/Max Close: {close_min}/{close_max}")
63
+ return float(close_min), float(close_max) # Pastikan kembali float
64
 
65
  def normalize_close(value, close_min, close_max):
66
+ if close_max == close_min:
67
+ logging.warning(f"Max_close ({close_max}) sama dengan min_close ({close_min}). Mengembalikan 0.5.")
68
+ return 0.5
69
  return (value - close_min) / (close_max - close_min)
70
 
71
  def analyze_trend(latest_row):
72
+ # Logging untuk memastikan data yang masuk valid
73
+ logging.debug(f"Menganalisis tren untuk data terbaru: {latest_row.to_dict()}")
74
+
75
  ema20 = latest_row["EMA20"]
76
  ema50 = latest_row["EMA50"]
77
  close = latest_row["close"]
78
 
79
+ # ... (sisa fungsi analyze_trend tidak berubah)
80
  if ema20 > ema50:
81
  trend = "bullish"
82
  elif ema20 < ema50:
 
84
  else:
85
  trend = "neutral"
86
 
87
+ # Pastikan ema50 tidak nol sebelum pembagian
88
+ if ema50 == 0:
89
+ logging.error("EMA50 adalah nol, tidak dapat menghitung gap persen.")
90
+ diff = 0
91
+ else:
92
+ diff = abs(ema20 - ema50) / ema50 * 100
93
+
94
  if diff > 0.3:
95
  strength = "strong"
96
  elif diff > 0.1:
 
105
  else:
106
  price_position = "between EMAs — indecision zone"
107
 
108
+ logging.debug(f"Analisis tren: trend={trend}, strength={strength}, pos={price_position}")
109
  return {
110
  "trend": trend,
111
  "strength": strength,
 
114
  }
115
 
116
  @app.post("/analyze")
117
+ def analyze_ema_endpoint(input_data: DateRange): # Ganti nama fungsi agar tidak sama dengan analyze_ema
118
  try:
119
  logging.info(f"Menerima permintaan /analyze dengan start_date={input_data.start_date}, end_date={input_data.end_date}")
120
  start_date = pd.to_datetime(input_data.start_date)
121
  end_date = pd.to_datetime(input_data.end_date)
122
  extended_start = start_date - timedelta(days=60)
123
 
124
+ logging.info(f"Mengunduh data dari yfinance: start={extended_start.strftime('%Y-%m-%d')}, end={end_date.strftime('%Y-%m-%d')}")
125
  df = yf.download(PAIR, start=extended_start, end=end_date + timedelta(days=1), auto_adjust=True)
126
 
127
  if df.empty:
 
130
 
131
  df = df.reset_index()[["Date", "Close"]]
132
  df.rename(columns={"Date": "date", "Close": "close"}, inplace=True)
133
+ logging.debug(f"Jumlah baris setelah download dan rename: {len(df)}")
134
 
135
  if len(df) < 50:
136
+ # Perhatikan pesan error di sini, ini akan muncul di log, bukan di 'message'
137
+ logging.error(f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50.")
138
  return {"status": "error", "message": f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50."}
139
 
140
+ # Logging sebelum memanggil ema_manual
141
+ logging.debug(f"Memanggil ema_manual untuk EMA20 dengan {len(df)} data.")
142
+ df["EMA20"] = ema_manual(df["close"].tolist(), 20) # Kirim sebagai list agar lebih eksplisit
143
+ logging.debug(f"Memanggil ema_manual untuk EMA50 dengan {len(df)} data.")
144
+ df["EMA50"] = ema_manual(df["close"].tolist(), 50) # Kirim sebagai list
145
+
146
  df = df.dropna().reset_index(drop=True)
147
+ logging.debug(f"Jumlah baris setelah dropna: {len(df)}")
148
 
149
  close_min, close_max = get_dynamic_minmax()
150
  df["norm_close"] = df["close"].apply(lambda x: normalize_close(x, close_min, close_max))
 
169
  }
170
 
171
  except Exception as e:
172
+ # PENTING: Periksa output log server Anda untuk ini!
173
+ logging.error(f"Error TERTANGKAP di endpoint /analyze_ema_endpoint: {e}", exc_info=True)
174
  return {"status": "error", "message": str(e)}
175
 
176
  @app.post("/summary")
177
+ def ema_summary_endpoint(input_data: DateRange): # Ganti nama fungsi
178
  try:
179
  logging.info(f"Menerima permintaan /summary dengan start_date={input_data.start_date}, end_date={input_data.end_date}")
180
  start_date = pd.to_datetime(input_data.start_date)
 
188
 
189
  df = df.reset_index()[["Date", "Close"]]
190
  df.rename(columns={"Date": "date", "Close": "close"}, inplace=True)
191
+ logging.debug(f"Jumlah baris setelah download dan rename: {len(df)}")
192
+
193
 
194
  if len(df) < 50:
195
+ logging.error(f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50.")
196
  return {"status": "error", "message": f"Data terlalu sedikit ({len(df)} hari). Butuh minimal 50 hari untuk EMA50."}
197
 
198
+ logging.debug(f"Memanggil ema_manual untuk EMA20 dengan {len(df)} data.")
199
+ df["EMA20"] = ema_manual(df["close"].tolist(), 20)
200
+ logging.debug(f"Memanggil ema_manual untuk EMA50 dengan {len(df)} data.")
201
+ df["EMA50"] = ema_manual(df["close"].tolist(), 50)
202
  df = df.dropna().reset_index(drop=True)
203
+ logging.debug(f"Jumlah baris setelah dropna: {len(df)}")
204
+
205
 
206
  latest = df.iloc[-1]
207
  analysis = analyze_trend(latest)
 
217
  }
218
 
219
  except Exception as e:
220
+ logging.error(f"Error TERTANGKAP di endpoint /ema_summary_endpoint: {e}", exc_info=True)
221
+ return {"status": "error", "message": str(e)}
222
+
223
+ @app.get("/")
224
+ def root():
225
+ return {"message": "Model B API (EMA + Trend Summary) aktif 🚀"}