Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -33,6 +33,54 @@ class DateRange(BaseModel):
|
|
| 33 |
start_date: str # ISO date 'YYYY-MM-DD'
|
| 34 |
end_date: str # ISO date 'YYYY-MM-DD'
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
# -----------------------
|
| 37 |
# Utility functions
|
| 38 |
# -----------------------
|
|
|
|
| 33 |
start_date: str # ISO date 'YYYY-MM-DD'
|
| 34 |
end_date: str # ISO date 'YYYY-MM-DD'
|
| 35 |
|
| 36 |
+
def clean_yf_csv(df_raw):
|
| 37 |
+
"""
|
| 38 |
+
Membersihkan struktur CSV seperti hasil export yfinance:
|
| 39 |
+
- baris pertama: nama kolom
|
| 40 |
+
- baris kedua: ticker
|
| 41 |
+
- baris ketiga: header date kosong
|
| 42 |
+
- sisakan hanya kolom ['date', 'close']
|
| 43 |
+
"""
|
| 44 |
+
# Jika baris pertama bukan data (mengandung "Price,Close,High,..."), kita re-parse manual
|
| 45 |
+
if "Price" in df_raw.columns[0]:
|
| 46 |
+
logger.info("Detected raw yfinance export format, cleaning...")
|
| 47 |
+
# Baca ulang file tanpa header dulu
|
| 48 |
+
df_raw.columns = [c.strip().lower() for c in df_raw.columns]
|
| 49 |
+
# Hapus baris ke-2 dan ke-3
|
| 50 |
+
df_raw = df_raw.drop(index=[0, 1])
|
| 51 |
+
# Ganti kolom 'price' menjadi 'date'
|
| 52 |
+
df_raw = df_raw.rename(columns={"price": "date"})
|
| 53 |
+
# Pastikan hanya ambil kolom 'date' dan 'close'
|
| 54 |
+
keep_cols = [c for c in df_raw.columns if c in ["date", "close"]]
|
| 55 |
+
df_raw = df_raw[keep_cols]
|
| 56 |
+
# Ubah tipe data tanggal
|
| 57 |
+
df_raw["date"] = pd.to_datetime(df_raw["date"], errors="coerce")
|
| 58 |
+
df_raw = df_raw.dropna(subset=["date"])
|
| 59 |
+
df_raw["close"] = pd.to_numeric(df_raw["close"], errors="coerce")
|
| 60 |
+
df_raw = df_raw.dropna(subset=["close"])
|
| 61 |
+
df_raw = df_raw.reset_index(drop=True)
|
| 62 |
+
return df_raw
|
| 63 |
+
|
| 64 |
+
def load_yf_data(pair, start, end):
|
| 65 |
+
"""Download yfinance data and ensure 'date' and 'close' columns exist."""
|
| 66 |
+
df_raw = yf.download(pair, start=start, end=end, auto_adjust=True, progress=False)
|
| 67 |
+
if df_raw.empty:
|
| 68 |
+
raise ValueError("No data from yfinance for that range.")
|
| 69 |
+
|
| 70 |
+
# Jika data CSV seperti contoh kamu (ada baris Ticker dan Price)
|
| 71 |
+
if "Price" in df_raw.columns or "Ticker" in df_raw.columns:
|
| 72 |
+
df_raw = clean_yf_csv(df_raw)
|
| 73 |
+
return df_raw
|
| 74 |
+
|
| 75 |
+
# flatten MultiIndex columns
|
| 76 |
+
if isinstance(df_raw.columns, pd.MultiIndex):
|
| 77 |
+
df_raw.columns = df_raw.columns.get_level_values(0)
|
| 78 |
+
|
| 79 |
+
df = df_raw.reset_index()[["Date", "Close"]].rename(columns={"Date": "date", "Close": "close"})
|
| 80 |
+
df["date"] = pd.to_datetime(df["date"]).dt.normalize()
|
| 81 |
+
return df
|
| 82 |
+
|
| 83 |
+
|
| 84 |
# -----------------------
|
| 85 |
# Utility functions
|
| 86 |
# -----------------------
|