/data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-96- }, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-97- report, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-98- ) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-99- if clean is None: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-100- continue /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py:101: bars.append(ProviderPriceBar( /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-102- date=_parse_date(clean["date"]), open=clean["open"], high=clean["high"], /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-103- low=clean["low"], close=clean["close"], adjusted_close=clean["adjusted_close"], /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-104- volume=clean["volume"], currency="USD", /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-105- )) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-106- self.last_price_validation = report /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-107- return bars /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-108- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-109- def get_income_statements(self, ticker: str, period: str = "annual", limit: int = 11) -> list[ProviderFinancialPeriod]: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-110- raise NotImplementedError( /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-111- "EODHD statement field mapping not yet implemented — see module docstring; use FMP as " /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-112- "primary or contribute the mapping once verified against a live EODHD response." /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-113- ) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-114- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-115- def get_balance_sheets(self, ticker: str, period: str = "annual", limit: int = 11) -> list[ProviderFinancialPeriod]: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/eodhd.py-116- raise NotImplementedError("EODHD balance sheet mapping not yet implemented — see module docstring.") -- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-216- d = start /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-217- price = base_price * 0.85 # start a bit below today's synthetic price, drift up to it /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-218- while d <= end: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-219- if d.weekday() < 5: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-220- price = max(price * (1 + rng.uniform(-0.01, 0.011)), 0.01) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py:221: bars.append(ProviderPriceBar(date=d, open=price, high=price * 1.01, low=price * 0.99, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-222- close=price, adjusted_close=price, volume=1_000_000, currency=p.currency)) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-223- d += timedelta(days=1) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-224- if bars: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py:225: bars[-1] = ProviderPriceBar(bars[-1].date, bars[-1].open, bars[-1].high, bars[-1].low, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-226- base_price, base_price, bars[-1].volume, p.currency) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-227- return bars /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-228- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-229- def get_estimates(self, ticker: str) -> list[ProviderEstimateRow]: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-230- rows = self._statements(ticker) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-231- last_eps = rows[-1]["eps_diluted"] /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-232- p = self._profile(ticker) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-233- if last_eps is None: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-234- return [] /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-235- forward = last_eps * (1 + p.revenue_cagr) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-236- return [ProviderEstimateRow( /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-237- period_end=date(date.today().year + 1, 12, 31), metric="eps", consensus_value=round(forward, 4), /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-238- num_analysts=12, as_of_date=date.today(), /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-239- )] /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/demo.py-240- -- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-156- }, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-157- report, /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-158- ) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-159- if clean is None: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-160- continue /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py:161: bars.append(ProviderPriceBar( /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-162- date=_parse_date(clean["date"]), open=clean["open"], high=clean["high"], /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-163- low=clean["low"], close=clean["close"], adjusted_close=clean["adjusted_close"], /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-164- volume=clean["volume"], currency="USD", /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-165- )) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-166- self.last_price_validation = report /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-167- return bars /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-168- /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-169- def get_estimates(self, ticker: str) -> list[ProviderEstimateRow]: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-170- rows = self._get(f"/analyst-estimates/{ticker}") /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-171- out = [] /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-172- for r in rows: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-173- period_end = _parse_date(r.get("date")) /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-174- for metric_key, fmp_key in (("eps", "estimatedEpsAvg"), ("revenue", "estimatedRevenueAvg")): /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-175- if r.get(fmp_key) is not None: /data/files/bmw/stocklab-audit-remediation-SL006-SL007-SL008-SL009-20260910-223000/app/app/adapters/fmp.py-176- out.append(ProviderEstimateRow(