From d869ea98bda37173a91be9990113efa975fa14e9 Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Wed, 18 Mar 2026 10:41:52 -0700 Subject: [PATCH] =?UTF-8?q?fix(etf):=20as=5Fof=5Fdate=EC=97=90=20=EA=B0=80?= =?UTF-8?q?=EC=9E=A5=20=EA=B0=80=EA=B9=8C=EC=9A=B4=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=A7=81=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _load_snapshot_holdings(): DB 캐시 스냅샷이 as_of_date와 120일 초과 차이나면 stale로 판단하고 None 반환 → SEC 신규 fetch 트리거 - _find_best_filing_and_xml(): eligible 필터에 365일 하한 추가, target_date 기준 1년 이내 파일링만 우선 후보로 사용 (하한 내 후보 없으면 기존 전체 검색 fallback 유지) 수정 전: SPY?as_of_date=2021-06-30 → 2019-11-18 (19개월 stale) 수정 후: SPY?as_of_date=2021-06-30 → 2021-05-28 (정상) Co-Authored-By: Claude Sonnet 4.6 --- app/services/etf_holdings_fetcher.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/services/etf_holdings_fetcher.py b/app/services/etf_holdings_fetcher.py index 922cf76..2252771 100644 --- a/app/services/etf_holdings_fetcher.py +++ b/app/services/etf_holdings_fetcher.py @@ -149,6 +149,13 @@ class ETFHoldingsFetcher: snap = res.scalar_one_or_none() if not snap: return None + + # 최대 허용 시차 검증: 120일 초과 시 stale로 판단 → SEC에서 새로 fetch + if as_of_date is not None: + gap = dt_norm - snap.snapshot_date + if gap.days > 120: + return None + hres = await db.execute(select(ETFHolding).where(ETFHolding.snapshot_id == snap.id)) rows = hres.scalars().all() holdings = [] @@ -268,7 +275,11 @@ class ETFHoldingsFetcher: # Candidate list: newest first, filtered by date if provided. # Ensure we include multiple prior days (not just the top day) to avoid missing the target series. if target_date: - eligible = [(dt, acc) for dt, acc in filings if dt <= target_date] + lower_bound = target_date - timedelta(days=365) + eligible = [(dt, acc) for dt, acc in filings if lower_bound <= dt <= target_date] + if not eligible: + # fallback: 하한 없이 전체 검색 (아주 오래된 ETF 등) + eligible = [(dt, acc) for dt, acc in filings if dt <= target_date] if not eligible: early_dt, early_acc = filings[0] xml_url = await self._download_primary_xml(